iOS开发之MonsterBall

MonsterBall主要用到的框架是重力加速度CoreMotion,二话不说,直接上代码了!
1.创建FKBallView类继承自UIView
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>

@interface FKBallView : UIView
// 定义属性来记录足球的当前位置
@property (nonatomic , assign) CGPoint currentPoint;
@property (nonatomic , assign) CMAcceleration acceleration;
// 定义属性来记录足球滚动的X、Y轴方向的速度
@property (nonatomic , assign) CGFloat xVelocity;
@property (nonatomic , assign) CGFloat yVelocity;
- (void)update;
@end
#import "FKBallView.h"
#define BALL_SIZE 24
// 定义怪物的数量
#define MONSTER_NUM 3
// 定义球门的起始位置
#define GATE_ORIGIN_X 85
// 定义球门的宽度
#define GATE_WIDTH 150
@interface FKBallView () <UIAlertViewDelegate>
{
	NSArray* ballImages;
	NSArray* monsterImages;
	UIImage* gateImage;
	// 定义变量记录足球动画帧的索引
	NSInteger ballIndex , count;
	// 定义变量记录每个怪物当前显示的动画帧的索引
	NSInteger monsterImageIndexs[MONSTER_NUM];
	// 定义数组来记录每个怪物的位置
	CGPoint monsterPoints[MONSTER_NUM];
	NSTimer* timer;
	BOOL isPlaying;  // 定义变量记录游戏的状态
}
@end
@implementation FKBallView
- (id)initWithCoder:(NSCoder *)aDecoder
{
	self = [super initWithCoder:aDecoder];
	if (self) {
		// 加载球门图片
		gateImage = [UIImage imageNamed:@"gate"];
		// 加载足球滚动的每一帧的图片
		ballImages = [NSArray arrayWithObjects:
			[UIImage imageNamed:@"ball1"],
			[UIImage imageNamed:@"ball2"],
			[UIImage imageNamed:@"ball3"],
			[UIImage imageNamed:@"ball4"],
			[UIImage imageNamed:@"ball5"],
			[UIImage imageNamed:@"ball6"],
			[UIImage imageNamed:@"ball7"],
			[UIImage imageNamed:@"ball8"], nil];
		// 加载怪物走动的每一帧的图片
		monsterImages = [NSArray arrayWithObjects:
			[UIImage imageNamed:@"monster_move_1"],
			[UIImage imageNamed:@"monster_move_2"],
			[UIImage imageNamed:@"monster_move_3"],
			[UIImage imageNamed:@"monster_move_4"], nil];
		monsterImageIndexs[1] = 1;
		monsterImageIndexs[2] = 2;
		[self startGame];   // 开始游戏
	}
	return self;
}
- (void) moveMonster
{
	for (int i = 0 ; i < MONSTER_NUM ; i++)
	{
		// 控制怪物动画显示下一帧的图片
		monsterImageIndexs[i] = monsterImageIndexs[i] + 1;
		// 改变第i个怪物的X坐标
		monsterPoints[i].x = monsterPoints[i].x + arc4random() % 9 - 4;
	}
	[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
	// 绘制足球
	[ballImages[ballIndex++ % 8] drawAtPoint:self.currentPoint];
	// 绘制球门
	[gateImage drawAtPoint:CGPointMake(GATE_ORIGIN_X , 0)];
	// 采用循环绘制3个怪物
	for(int i = 0 ; i < MONSTER_NUM ; i++)
	{
		[monsterImages[monsterImageIndexs[i] % 4] drawAtPoint:monsterPoints[i]];
	}
}
// 重写实现currentPoint属性的setter方法
- (void)setCurrentPoint:(CGPoint)newPoint
{
	// 如果正在游戏中,且足球新的位置点与原来的位置点不位于同一个点。
	if(isPlaying && (fabs(_currentPoint.x - newPoint.x) > 1
	   || fabs(_currentPoint.y - newPoint.y) > 1))
	{
		_currentPoint = newPoint;
		// 如果足球当前的X坐标小于0,就足球已经位于最左边
		if (_currentPoint.x < 0)
		{
			// 将足球设置在最左边,并将水平速度设为0
			_currentPoint.x = 0;
			self.xVelocity = 0;
		}
		// 球已经到了底线, 且没进球门
		if (_currentPoint.y < 75 && (_currentPoint.x < GATE_ORIGIN_X + 2
				|| _currentPoint.x > GATE_ORIGIN_X  + GATE_WIDTH - 4))
		{
			// 将足球设置在底线上,并将垂直速度设为0
			_currentPoint.y = 75;
			self.yVelocity = 0;
		}
		// 球进了球门
		if (_currentPoint.y < 75 && (_currentPoint.x >= GATE_ORIGIN_X + 2
			|| _currentPoint.x <= GATE_ORIGIN_X  + GATE_WIDTH - 4))
		{
			// 使用UIAlertView提示用户游戏结束,并询问用户是否要开始下一盘游戏
			[[[UIAlertView alloc] initWithTitle:@"游戏结束"
				message:@"您进球了,再来一盘?" delegate:self
				cancelButtonTitle:@"" otherButtonTitles:nil] show];
			// 取消计时器
			[timer invalidate];
			isPlaying = NO;
		}
		// 如果足球的X坐标大于该控件的高度,表明足球已经到了屏幕最下方
		if (_currentPoint.x > self.bounds.size.width - BALL_SIZE)
		{
			// 将足球设置到屏幕最下方,并将垂直速度设为0
			_currentPoint.x = self.bounds.size.width - BALL_SIZE;
			self.xVelocity = 0;
		}
		// 如果足球的Y坐标大于该控件的宽度,表明足球已经到了屏幕最右边
		if (_currentPoint.y > self.bounds.size.height - BALL_SIZE)
		{
			// 将足球设置到屏幕最右边,并将水平速度设为0
			_currentPoint.y = self.bounds.size.height - BALL_SIZE;
			self.yVelocity = 0;
		}
		// 遍历每个怪物,检测怪物与足球是否碰撞
		for (int i = 0 ; i < MONSTER_NUM ; i ++)
		{
			// 如果怪物所在矩形和足球所在矩形有交集,表明二者相撞
			if(CGRectIntersectsRect([self getBallRect], [self getMonsterRect:i]))
			{
				// 怪物将足球快速向下踢出,也就是足球的Y方向上速度增加0.6
				self.yVelocity = self.yVelocity + 0.6;
			}
		}
		[self setNeedsDisplay];
	}
}
- (void)update
{
	static NSDate *lastUpdateTime;
	// 如果初始化过lastUpdateTime变量
	if (lastUpdateTime != nil)
	{
		// 计算上次到现在的时间差
		NSTimeInterval secondsSinceLastDraw =
			-([lastUpdateTime timeIntervalSinceNow]);
		// 根据加速度数据计算足球在X方向、Y方向的速度
		self.yVelocity = self.yVelocity + -(self.acceleration.y *
			secondsSinceLastDraw);
		self.xVelocity = self.xVelocity + self.acceleration.x *
			secondsSinceLastDraw;
		// 根据足球的速度计算足球在单位时间内滚动的距离。
		// 由于实际算出来的滚动距离太小,因此都需要乘以500(实际上可用400、600等)
		CGFloat xDelta = secondsSinceLastDraw * self.xVelocity * 500;
		CGFloat yDelta = secondsSinceLastDraw * self.yVelocity * 500;
		// 设置足球的位置为新计算出来的位置
		self.currentPoint = CGPointMake(self.currentPoint.x + xDelta,
			self.currentPoint.y + yDelta);
	}
	lastUpdateTime = [[NSDate alloc] init];
}
// 获取怪物所在的矩形框
- (CGRect) getMonsterRect:(NSInteger) monsterIndex
{
	CGRect rect;
	// 获取索引为monsterIndex的怪物的左上角坐标
	rect.origin = monsterPoints[monsterIndex];
	// 获取图片的大小
	rect.size = ((UIImage*)monsterImages[0]).size;
	return rect;
}
// 获取足球所在的矩形框
- (CGRect) getBallRect
{
	CGRect rect;
	rect.origin = self.currentPoint;
	rect.size = ((UIImage*)ballImages[0]).size;
	return rect;
}
- (void) resetGame
{
	// 依次设置每个怪物的位置
	monsterPoints[0] = CGPointMake(20 , 50);
	monsterPoints[1] = CGPointMake(190 , 50);
	monsterPoints[2] = CGPointMake(80 , 180);
	// 设置足球开始的位置,位于该UIView的中心
	self.currentPoint = CGPointMake((self.bounds.size.width - BALL_SIZE ) / 2.0f,
		(self.bounds.size.height - BALL_SIZE) / 2.0f);
	// 设置足球的开始速度
	self.xVelocity = 0.0f;
	self.yVelocity = 0.0f;
}
// 当用户单击UIAlertView警告框上按钮时激发该方法
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:
	(NSInteger)buttonIndex
{
	// 如果用户单击第一个按钮
	if(buttonIndex == 0)
	{
		[self startGame];  // 重新开始游戏
	}
}
- (void) startGame
{
	// 设置游戏状态:正在游戏
	isPlaying = YES;
	// 重设足球和怪物的位置
	[self resetGame];
	// 使用定时器控制怪物的动作
	timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self
		selector:@selector(moveMonster) userInfo:nil repeats:YES];
}
@end
2.创建FKViewController继承自UIViewController
#import <CoreMotion/CoreMotion.h>
#import "FKViewController.h"
#import "FKBallView.h"

@interface FKViewController ()
@property (strong, nonatomic) CMMotionManager* motionManager;
@property (weak, nonatomic) FKBallView* ballView;
@end
@implementation FKViewController
- (void)viewDidLoad
{
	[super viewDidLoad];
	// 创建以grass.png图片平铺的颜色
	UIColor* bgColor = [UIColor colorWithPatternImage:
		[UIImage imageNamed:@"grass"]];
	// 将该视图控制器管理的View控件转换为FKBallView
	self.ballView = (FKBallView*)self.view;
	// 将背景设为以grass.png图片平铺的颜色
	self.ballView.backgroundColor = bgColor;
	// 创建CMMotionManager对象
	self.motionManager = [[CMMotionManager alloc] init];
	NSOperationQueue* queue = [[NSOperationQueue alloc] init];
	// 设置CMMotionManager获取加速度数据的频率
	self.motionManager.accelerometerUpdateInterval = 0.05;
	// 使用代码块获取加速度数据
	[self.motionManager startAccelerometerUpdatesToQueue:queue withHandler:
	^(CMAccelerometerData *accelerometerData, NSError *error)
	{
		// 将获取得到的加速度数据传给FKBallView对象
		self.ballView.acceleration = accelerometerData.acceleration;
		// 在主线程中调用FKBallView对象的update方法
		[self.ballView performSelectorOnMainThread:@selector(update)
			withObject:nil waitUntilDone:NO];
	}];
}
@end

你可能感兴趣的:(iOS开发之MonsterBall)