忙着期末考试,读书笔记断更了~
ios 游戏处女作—demo
游戏规则
屏幕上方有四排砖块
点击屏幕开始游戏
游戏开始时,小球向上方运行
小球与砖块撞击可以撞碎砖块并反弹
小球与屏幕顶部、右侧、左侧碰撞会反弹
小球与挡板碰撞会反弹
左右移动手指可以挪动挡板
小球从屏幕下方掉出游戏结束
撞碎所有砖块游戏胜利
手机游戏的使用习惯
除非是非常出色的游戏或者游戏模式所迫,否则最好使用竖版的模式,适合用户单手操作手机,比较方便。而 iPad 则最好使用横版。
游戏类的屏幕一般要把手机上面的状态栏隐藏。不同于一般的应用程序,比如淘宝,美团,网上银行等,这些程序就不需要把状态栏隐藏,用户需要看到时间等信息。
Xcode6:
并且 Iphone6模拟器默认自带状态栏,还是需要设置一下,把它屏蔽掉;
需要添加动画框架QuartzCore.framework
这里要知道一些苹果手机的配置:
iPhone三代(iPhone3GS)
- 2009年发布
- 外观上基本跟iPhone3G没区别,速度更快,3GS后面的S就是“Speed”的意思
- 3.5英寸,480x320像素分辨率
- 后置摄像头300万像素
iPhone4
- 2010年发布,艳惊四座
- 全新外观+玻璃材质,9.3毫米厚度,A4单核处理器,支持多任务
- 3.5英寸Retina显示屏(视网膜屏幕),960x640像素分辨率
- 后置摄像头500万像素
- 前置摄像头30万像素
iPhone4S
- 2011年发布
- 外观上与iPhone4区别不大
- A5双核处理器,性能上有较大的提升
- 3.5英寸,960x640像素分辨率
- 后置摄像头800万像素
- 前置摄像头30万像素
iPhone5
- 2012年发布
- 全新外观,机身更轻薄,7.6毫米厚度,屏幕更大
- A6双核处理器,速度更快
- 4.0英寸,1136x640像素分辨率
- 后置摄像头800万像素
- 前置摄像头120万像素
2013年9月发布iphone5s
- 800万像素
- IPS屏幕;1136*640;4.0英寸
- 64位双核苹果A7处理器,外观优雅简洁,机身轻薄,用户体验极佳,操作简单,让用户感受到从未有过的爽,软件种类丰富、高质量 。
- 性能极佳,支持众多大型3D游戏
iPhone6和6s
太平洋时间2014年9月9日10点(北京时间9月10日凌晨1点)正式发布
6主屏尺寸4.7英寸 主屏分辨率1704x960像素 后置摄像头800万像素 前置摄像头210万像素
6s 主屏5.5英寸 ,分辨率 1920x1080像素
iPad做游戏是必用的!否则不一定用到
iPad1
- 2010年发布的平板电脑
- A4单核处理器,9.7英寸,1024x768像素分辨率
iPad2
- 2011年发布
- A5双核处理器,9.7英寸,1024x768像素分辨率
- 前置摄像头:30万像素,后置摄像头:70万像素
The new iPad
- 2012年发布
- A5X双核处理器,9.7英寸Retina显示屏,2048x1536像素分辨率
- 前置摄像头:30万像素,后置摄像头:500万像素
iPad4
- 2012年发布
- A6X双核处理器,9.7英寸Retina显示屏,2048x1536像素分辨率
- 前置摄像头:120万像素,后置摄像头:500万像素
iPad Mini 1
2012年10月23日于美国加州圣荷西发布
7.9英寸、1024 × 768 分辨率显示屏
500 万像素后置 ,120 万像素前置,处理器等硬件规格大致与iPad 2相同;
采用与 iPhone 5相同的Lightning连接线作充电或数据传送。
立体声扬声器。
iPad Mini 2
2013年10月22日发布
超过310万像素的Retina显示屏,分辨率2048 x 1536像素。
A7芯片,薄至仅7.5毫米,轻达331克。
iPad Air
2013年10月23日发布
9.7英寸,视网膜显示屏,厚7.5毫米
重量是1磅(约合454克),A7处理器,并搭配了M7协处理器
后置摄像头500万,支持1080p高清视频FaceTime;
电池续航能力达到10小时。
iPad mini 3
美国东部时间2014年10月16日下午1点(北京时间10月17日凌晨1点)正式发布。
7.9英寸,分辨率2048x1536
内置苹果64位 A7 双核处理器
系统内存1GB。
iPad Air 2
2014年10月
A8X处理器,IOS 8
9.7寸,分辨率2048×1536
iPod Touch
- iPod Touch是一台没有电话服务功能的iPhone
- 可以使用wifi接入无线网络,拥有和iPhone一样的上网体验
- 可以通过苹果皮实现打电话和短信功能
Apple TV(不在大陆销售)
- 苹果公司推出的一款高清电视机顶盒产品
- 可以通过Apple TV在线收看电视节目
- 可以通过Airplay功能,将iPad、iPhone、iPod和PC中的照片、视频和音乐通过传输到电视上进行播放
敏捷开发 scrum
以需求为驱动,反复迭代。而不是上来就先写代码。故我们先设计界面的布局,看看好玩不好玩。
大致样子:按照4和4s
每行设计为5个砖块,则单个砖块的宽是64,因为总宽为320。然后把图片素材拖进去即可,初步设置为6排。
挡板同样是宽度64,高度20。
小球是宽度20,高度20。
有些粗糙,美工的问题,可以折中缓解下,发现这些素材的背景都是灰色,那么我们设置屏幕的背景为灰色即可解决。切记;苹果的产品素材最好是1:1的比例,来保证最佳的性能和效果,尽量让美工去调整素材。
最终成品:
尺寸问题
先调整3.5英寸的(4和4s),再调整4英寸的(5和5s),现在又有了4.7英寸和5.5英寸。一般的原则是从小到大调整。
界面设计的总结
在 IOS 游戏开发中,界面设计是重中之重!!非常重要,不能小视。要先设计界面原型,再讨论游戏的过程,期间要对游戏的好玩度抱有信心,必须相信自己的游戏是好玩的,一定要坚定不移,即使这是一种病态的坚持。这样的爱好和热心才会给开发人员带来热情和激情。
最忌讳还没对游戏的好玩度抱有决心和信心的时候,就动手写代码。这样很容易失败。相反,有了成型的界面和对游戏好玩度的信心和激情,这之后的思路才会清晰和长久。
继续游戏的开发
比较经典的应用程序的循环,设置完毕,处理用户事件(包括触摸,点击,说话,摇晃等),处理的同时更新游戏状态(比如,手指滑动挡板,则挡板移动,小球碰撞了砖块,则砖块隐藏),判断游戏是否结束,没有结束就继续循环,否则结束。几乎所有的语言在开发游戏的时候,都会有类似的循环过程。
建立IBOutlet & IBOutlet Collection
这需要注意下砖块的 outlet 集合的设置,把每个砖块都拖拽到这个集合里。
// // ViewController.h // 打砖块小游戏 // // Created by 大帅 on 14-12-21. // Copyright (c) 2014年 dashuai. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController //按住 ctrl 健进行拖拽,连接outlet //小球 @property (weak, nonatomic) IBOutlet UIImageView *ballImage; //挡板 @property (weak, nonatomic) IBOutlet UIImageView *paddleImage; //砖块的集合 @property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *blocksImage; @end
让小球动起来
要求;在屏幕的任意位置点击一下,小球就会跳起来。如图是4和4s 的坐标图
要注意,iphone 的坐标里 y 向下增长,故小球向上打出去,y 方向是负数。且苹果开发中,考虑的是点的概念,而不是像素的概念!记住,4和4s 是320x480的大小。
m 文件的代码如下:
1 // 2 // ViewController.m 3 // 打砖块小游戏 4 // 5 // Created by 大帅 on 14-12-21. 6 // Copyright (c) 2014年 dashuai. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 //引入动画框架 QuartzCore 11 #import <QuartzCore/QuartzCore.h> 12 13 //私有的变量,在 m 文件里定义一下 14 @interface ViewController () 15 { 16 //游戏开始的标志 17 BOOL _isPlaying; 18 19 //定义游戏的时钟 20 CADisplayLink *_gameTimer; 21 22 //定义小球的速度,_ballV来表示 23 CGPoint _ballV; 24 } 25 //游戏时钟的处理方法,对外不可见,应该定义在点m 文件里 26 - (void)step:(CADisplayLink *)sender; 27 28 @end 29 30 @implementation ViewController 31 32 - (void)viewDidLoad { 33 [super viewDidLoad]; 34 // Do any additional setup after loading the view, typically from a nib. 35 } 36 37 - (void)didReceiveMemoryWarning { 38 [super didReceiveMemoryWarning]; 39 // Dispose of any resources that can be recreated. 40 } 41 42 //游戏时钟的处理方法, 因为对外不可见,故定义在 点m 文件里,而不是头文件里 43 - (void)step:(CADisplayLink *)sender 44 { 45 //让求(小球的图)动起来,本质 是 设置小球的 位置(也就是更新小球的位置的状态) 46 //小球中心点的 x 位置加上小球中心点的 x 方向的速度 47 //小球中心点的 y 位置加上小球中心点的 y 方向的速度 48 [_ballImage setCenter:CGPointMake(_ballImage.center.x + _ballV.x, _ballImage.center.y + _ballV.y)]; 49 //可以打印测试下,游戏时钟的方法是否是每秒钟运行60次 50 NSLog(@"游戏运行了~");//后期去掉 51 } 52 53 //触摸事件的实现 54 //触摸结束(手指抬起之后),游戏开始,小球动起来,这里的方法是支持多点触摸的 55 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *) event 56 { 57 //先判断本游戏是否已经开始了,如果游戏还没有开始: 58 if (!_isPlaying) { 59 //考虑一个点的触摸,获取触摸的对象 60 // UITouch *touch = [touches anyObject];//暂时用不到 61 62 // 触摸之后,给小球一个初始速度,0,-5, 63 //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5 64 _ballV = CGPointMake(0, -5); 65 66 //定义游戏时钟 67 //通过函数名来调用头文件里定义的另外的方法 step: 方法,时钟的目标是自己 68 _gameTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(step:)]; 69 70 //把当前时钟添加到游戏里经典的应用循环中,ios默认提供的循环方法 71 [_gameTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 72 73 //勿忘修改游戏状态的标识 74 //表面本游戏已经开始了 75 _isPlaying = YES; 76 } 77 } 78 79 @end
屏幕刷新频率的概念
每秒钟,屏幕上的所有的点被重新绘制的次数。而苹果设备的屏幕刷新频率,大概每秒是将近60次,或多或少。
而在本游戏里,给小球设置的初试速度,也就是初试移动位置是(0, -5),那么每秒钟小球就跑出了300左右的点的距离。表现的就是小球飞了!
程序运行发现:
1 2014-12-30 18:39:04.064 打砖块小游戏[4498:129623] 游戏运行了~ 2 2014-12-30 18:39:04.082 打砖块小游戏[4498:129623] 游戏运行了~ 3 2014-12-30 18:39:04.099 打砖块小游戏[4498:129623] 游戏运行了~ 4 2014-12-30 18:39:04.114 打砖块小游戏[4498:129623] 游戏运行了~ 5 2014-12-30 18:39:04.132 打砖块小游戏[4498:129623] 游戏运行了~ 6 2014-12-30 18:39:04.148 打砖块小游戏[4498:129623] 游戏运行了~ 7 2014-12-30 18:39:04.165 打砖块小游戏[4498:129623] 游戏运行了~ 8 2014-12-30 18:39:04.181 打砖块小游戏[4498:129623] 游戏运行了~ 9 2014-12-30 18:39:04.199 打砖块小游戏[4498:129623] 游戏运行了~ 10 2014-12-30 18:39:04.215 打砖块小游戏[4498:129623] 游戏运行了~ 11 2014-12-30 18:39:04.232 打砖块小游戏[4498:129623] 游戏运行了~ 12 2014-12-30 18:39:04.249 打砖块小游戏[4498:129623] 游戏运行了~ 13 2014-12-30 18:39:04.264 打砖块小游戏[4498:129623] 游戏运行了~ 14 2014-12-30 18:39:04.281 打砖块小游戏[4498:129623] 游戏运行了~ 15 2014-12-30 18:39:04.299 打砖块小游戏[4498:129623] 游戏运行了~ 16 2014-12-30 18:39:04.315 打砖块小游戏[4498:129623] 游戏运行了~ 17 2014-12-30 18:39:04.331 打砖块小游戏[4498:129623] 游戏运行了~ 18 2014-12-30 18:39:04.349 打砖块小游戏[4498:129623] 游戏运行了~ 19 2014-12-30 18:39:04.365 打砖块小游戏[4498:129623] 游戏运行了~ 20 2014-12-30 18:39:04.381 打砖块小游戏[4498:129623] 游戏运行了~ 21 2014-12-30 18:39:04.398 打砖块小游戏[4498:129623] 游戏运行了~ 22 2014-12-30 18:39:04.415 打砖块小游戏[4498:129623] 游戏运行了~ 23 2014-12-30 18:39:04.431 打砖块小游戏[4498:129623] 游戏运行了~ 24 2014-12-30 18:39:04.448 打砖块小游戏[4498:129623] 游戏运行了~ 25 2014-12-30 18:39:04.465 打砖块小游戏[4498:129623] 游戏运行了~ 26 2014-12-30 18:39:04.481 打砖块小游戏[4498:129623] 游戏运行了~ 27 2014-12-30 18:39:04.498 打砖块小游戏[4498:129623] 游戏运行了~ 28 2014-12-30 18:39:04.514 打砖块小游戏[4498:129623] 游戏运行了~ 29 2014-12-30 18:39:04.532 打砖块小游戏[4498:129623] 游戏运行了~ 30 2014-12-30 18:39:04.548 打砖块小游戏[4498:129623] 游戏运行了~ 31 2014-12-30 18:39:04.564 打砖块小游戏[4498:129623] 游戏运行了~ 32 2014-12-30 18:39:04.581 打砖块小游戏[4498:129623] 游戏运行了~ 33 2014-12-30 18:39:04.598 打砖块小游戏[4498:129623] 游戏运行了~ 34 2014-12-30 18:39:04.614 打砖块小游戏[4498:129623] 游戏运行了~ 35 2014-12-30 18:39:04.631 打砖块小游戏[4498:129623] 游戏运行了~ 36 2014-12-30 18:39:04.648 打砖块小游戏[4498:129623] 游戏运行了~ 37 2014-12-30 18:39:04.664 打砖块小游戏[4498:129623] 游戏运行了~ 38 2014-12-30 18:39:04.682 打砖块小游戏[4498:129623] 游戏运行了~ 39 2014-12-30 18:39:04.698 打砖块小游戏[4498:129623] 游戏运行了~ 40 2014-12-30 18:39:04.715 打砖块小游戏[4498:129623] 游戏运行了~ 41 2014-12-30 18:39:04.731 打砖块小游戏[4498:129623] 游戏运行了~ 42 2014-12-30 18:39:04.748 打砖块小游戏[4498:129623] 游戏运行了~ 43 2014-12-30 18:39:04.764 打砖块小游戏[4498:129623] 游戏运行了~ 44 2014-12-30 18:39:04.781 打砖块小游戏[4498:129623] 游戏运行了~ 45 2014-12-30 18:39:04.798 打砖块小游戏[4498:129623] 游戏运行了~ 46 2014-12-30 18:39:04.815 打砖块小游戏[4498:129623] 游戏运行了~ 47 2014-12-30 18:39:04.831 打砖块小游戏[4498:129623] 游戏运行了~ 48 2014-12-30 18:39:04.848 打砖块小游戏[4498:129623] 游戏运行了~ 49 2014-12-30 18:39:04.865 打砖块小游戏[4498:129623] 游戏运行了~ 50 2014-12-30 18:39:04.881 打砖块小游戏[4498:129623] 游戏运行了~ 51 2014-12-30 18:39:04.898 打砖块小游戏[4498:129623] 游戏运行了~ 52 2014-12-30 18:39:04.914 打砖块小游戏[4498:129623] 游戏运行了~ 53 2014-12-30 18:39:04.932 打砖块小游戏[4498:129623] 游戏运行了~ 54 2014-12-30 18:39:04.948 打砖块小游戏[4498:129623] 游戏运行了~ 55 2014-12-30 18:39:04.964 打砖块小游戏[4498:129623] 游戏运行了~ 56 2014-12-30 18:39:04.981 打砖块小游戏[4498:129623] 游戏运行了~ 57 2014-12-30 18:39:04.999 打砖块小游戏[4498:129623] 游戏运行了~
大概是57次/每秒钟,差不多就是前面分析的那样,在本游戏里,是可以被接受的!不是太快,也不是太慢,刚刚好。屏幕点击之后,小球就飞出去了。
碰撞检测
1、要知道这个物理公式:位移 = 时间 * 速度
2、时钟处理的流程图
3、在做小球的碰撞检测的时候,要知道这个图的含义
代码如下
1 // 2 // ViewController.m 3 // 打砖块小游戏 4 // 5 // Created by 大帅 on 14-12-21. 6 // Copyright (c) 2014年 dashuai. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 //引入动画框架 QuartzCore 11 #import <QuartzCore/QuartzCore.h> 12 13 //私有的变量,在 m 文件里定义一下 14 @interface ViewController () 15 { 16 //游戏开始的标志 17 BOOL _isPlaying; 18 19 //定义游戏的时钟 20 CADisplayLink *_gameTimer; 21 22 //定义小球的速度,_ballV来表示 23 CGPoint _ballV; 24 } 25 //游戏时钟的处理方法,对外不可见,应该定义在点m 文件里 26 - (void)step:(CADisplayLink *)sender; 27 28 //检测和屏幕边缘的碰撞 29 - (BOOL)checkWithScreen; 30 31 //检测和砖块的碰撞 32 - (BOOL)checkWithBlocks; 33 34 //检测和挡板的碰撞 35 - (void)checkWithPaddle; 36 37 //重置游戏的状态 38 //游戏胜利,失败的状态 39 - (void)resetGamesStateWithMessage:(NSString *)message; 40 41 @end 42 43 @implementation ViewController 44 45 - (void)viewDidLoad { 46 [super viewDidLoad]; 47 // Do any additional setup after loading the view, typically from a nib. 48 } 49 50 - (void)didReceiveMemoryWarning { 51 [super didReceiveMemoryWarning]; 52 // Dispose of any resources that can be recreated. 53 } 54 55 //游戏的重置方法的实现 56 - (void)resetGamesStateWithMessage:(NSString *)message 57 { 58 NSLog(@"%@", message); 59 _isPlaying = NO; 60 //屏幕的中间位置 x是160 61 //把小球设置到中间 62 [_ballImage setCenter:CGPointMake(160, 430)]; 63 //把挡板设置到中间位置也 64 [_paddleImage setCenter:CGPointMake(160, 450)]; 65 //把时钟清除也就是关掉,千万不要忘记,否则后果很严重!不亚于内存泄露的错误! 66 [_gameTimer invalidate]; 67 } 68 69 //小球和屏幕的碰撞检测方法实现 70 - (BOOL)checkWithScreen 71 { 72 //除了下方的屏幕边缘,其他的都是反弹回来,而下方是掉出去,游戏失败 73 BOOL gameOver = NO; 74 75 //左边碰撞检测的处理,比较简单,因为屏幕的原点就是在左边的线上 76 if ([_ballImage frame].origin.x <= 0) { 77 //反弹回去,就是把它取正数,x 方向的速度变为正数,使用绝对值函数 78 _ballV.x = abs(_ballV.x); 79 } 80 81 //右边碰撞检测处理,小球边框的距离原点的 x 加上小球本身的宽度,如果大于了视图本身边框的宽度的尺寸,那就是碰撞 82 if ([_ballImage frame].origin.x + [_ballImage frame].size.width >= self.view.frame.size.width) { 83 //反弹,就是保证小球 x 方向的速度必须为负的 84 _ballV.x = -1 * abs(_ballV.x); 85 } 86 87 //顶部屏幕的碰撞检测处理 88 if ([_ballImage frame].origin.y <= 0) { 89 _ballV.y = abs(_ballV.y); 90 } 91 92 //底部碰撞检测处理 93 if ([_ballImage frame].origin.y + [_ballImage frame].size.height >= self.view.frame.size.height) { 94 gameOver = YES; 95 } 96 97 return gameOver; 98 } 99 100 //小球和方块的碰撞检测方法的实现 101 - (BOOL)checkWithBlocks 102 { 103 BOOL gameWin = NO; 104 105 //所有的在砖块集合里的砖块的碰撞检测 106 for (UIImageView *block in _blocksImage) { 107 //苹果提供了一个 bool 类型的矩形碰撞检测函数 108 //如果两个矩形重叠了(也就是碰撞了),函数反悔 YES,否则返回 NO 109 //同时只检测,那些没有被隐藏的砖块,已经隐藏的就不需要碰撞检测了 110 if (CGRectIntersectsRect([block frame], [_ballImage frame]) && ![block isHidden]) { 111 //碰撞就消除砖块,其实是隐藏砖块的图像 112 [block setHidden:YES]; 113 //碰撞完成之后,要让小球向下运动 114 _ballV.y = abs(_ballV.y); 115 //保证循环的效率,提前退出循环 116 break; 117 } 118 } 119 120 //判断游戏是否胜利的逻辑 121 int count = 0; 122 123 for (UIImageView *block in _blocksImage) { 124 if ([block isHidden]) { 125 count++; 126 } 127 } 128 129 if (count == [_blocksImage count]) { 130 gameWin = YES; 131 } 132 133 return gameWin; 134 } 135 136 //小球和挡板的碰撞检测方法 137 - (void)checkWithPaddle 138 { 139 //如果小球和挡板碰撞 140 if (CGRectIntersectsRect([_ballImage frame], [_paddleImage frame])) { 141 //强制把小球 y 方向的速度设为负数,让它反弹回去 142 _ballV.y = -1 * abs(_ballV.y); 143 } 144 } 145 146 //游戏时钟的处理方法, 因为对外不可见,故定义在 点m 文件里,而不是头文件里 147 - (void)step:(CADisplayLink *)sender 148 { 149 //让求(小球的图)动起来,本质 是 设置小球的 位置(也就是更新小球的位置的状态) 150 //小球中心点的 x 位置加上小球中心点的 x 方向的速度 151 //小球中心点的 y 位置加上小球中心点的 y 方向的速度 152 [_ballImage setCenter:CGPointMake(_ballImage.center.x + _ballV.x, _ballImage.center.y + _ballV.y)]; 153 //可以打印测试下,游戏时钟的方法是否是每秒钟运行60次 154 //NSLog(@"游戏运行了~"); 155 156 //在游戏时钟处理方法里,调用碰撞检测方法 157 if ([self checkWithScreen]) { 158 [self resetGamesStateWithMessage:@"游戏结束!"]; 159 } 160 161 if ([self checkWithBlocks]) { 162 [self resetGamesStateWithMessage:@"游戏胜利!"]; 163 } 164 165 [self checkWithPaddle]; 166 167 } 168 169 //触摸事件的实现 170 //触摸结束(手指抬起之后),游戏开始,小球动起来,这里的方法是支持多点触摸的 171 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *) event 172 { 173 //先判断本游戏是否已经开始了,如果游戏还没有开始: 174 if (!_isPlaying) { 175 //考虑一个点的触摸,获取触摸的对象 176 // UITouch *touch = [touches anyObject];//暂时用不到 177 178 // 触摸之后,给小球一个初始速度,0,-5, 179 //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5 180 _ballV = CGPointMake(0, -5); 181 182 //定义游戏时钟 183 //通过函数名来调用头文件里定义的另外的方法 step: 方法,时钟的目标是自己 184 _gameTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(step:)]; 185 186 //把当前时钟添加到游戏里经典的应用循环中,ios默认提供的循环方法 187 [_gameTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 188 189 //勿忘修改游戏状态的标识 190 //表面本游戏已经开始了 191 _isPlaying = YES; 192 } 193 } 194 195 @end
挡板移动的处理
如下代码:
1 // 2 // ViewController.m 3 // 打砖块小游戏 4 // 5 // Created by 大帅 on 14-12-21. 6 // Copyright (c) 2014年 dashuai. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 //引入动画框架 QuartzCore 11 #import <QuartzCore/QuartzCore.h> 12 13 //私有的变量,在 m 文件里定义一下 14 @interface ViewController () 15 { 16 //游戏开始的标志 17 BOOL _isPlaying; 18 19 //定义游戏的时钟 20 CADisplayLink *_gameTimer; 21 22 //定义小球的速度,_ballV来表示 23 CGPoint _ballV; 24 25 //水平位移 26 CGFloat _deltaX; 27 } 28 29 //游戏时钟的处理方法,对外不可见,应该定义在点m 文件里 30 - (void)step:(CADisplayLink *)sender; 31 32 //检测和屏幕边缘的碰撞 33 - (BOOL)checkWithScreen; 34 35 //检测和砖块的碰撞 36 - (BOOL)checkWithBlocks; 37 38 //检测和挡板的碰撞 39 - (void)checkWithPaddle; 40 41 //重置游戏的状态 42 //游戏胜利,失败的状态 43 - (void)resetGamesStateWithMessage:(NSString *)message; 44 45 @end 46 47 @implementation ViewController 48 49 - (void)viewDidLoad { 50 [super viewDidLoad]; 51 // Do any additional setup after loading the view, typically from a nib. 52 } 53 54 - (void)didReceiveMemoryWarning { 55 [super didReceiveMemoryWarning]; 56 // Dispose of any resources that can be recreated. 57 } 58 59 //游戏的重置方法的实现 60 - (void)resetGamesStateWithMessage:(NSString *)message 61 { 62 NSLog(@"%@", message); 63 _isPlaying = NO; 64 //屏幕的中间位置 x是160 65 //把小球设置到中间 66 [_ballImage setCenter:CGPointMake(160, 430)]; 67 //把挡板设置到中间位置也 68 [_paddleImage setCenter:CGPointMake(160, 450)]; 69 //把时钟清除也就是关掉,千万不要忘记,否则后果很严重!不亚于内存泄露的错误! 70 [_gameTimer invalidate]; 71 } 72 73 //小球和屏幕的碰撞检测方法实现 74 - (BOOL)checkWithScreen 75 { 76 //除了下方的屏幕边缘,其他的都是反弹回来,而下方是掉出去,游戏失败 77 BOOL gameOver = NO; 78 79 //左边碰撞检测的处理,比较简单,因为屏幕的原点就是在左边的线上 80 if ([_ballImage frame].origin.x <= 0) { 81 //反弹回去,就是把它取正数,x 方向的速度变为正数,使用绝对值函数 82 _ballV.x = abs(_ballV.x); 83 } 84 85 //右边碰撞检测处理,小球边框的距离原点的 x 加上小球本身的宽度,如果大于了视图本身边框的宽度的尺寸,那就是碰撞 86 if ([_ballImage frame].origin.x + [_ballImage frame].size.width >= self.view.frame.size.width) { 87 //反弹,就是保证小球 x 方向的速度必须为负的 88 _ballV.x = -1 * abs(_ballV.x); 89 } 90 91 //顶部屏幕的碰撞检测处理 92 if ([_ballImage frame].origin.y <= 0) { 93 _ballV.y = abs(_ballV.y); 94 } 95 96 //底部碰撞检测处理 97 if ([_ballImage frame].origin.y + [_ballImage frame].size.height >= self.view.frame.size.height) { 98 gameOver = YES; 99 } 100 101 return gameOver; 102 } 103 104 //小球和方块的碰撞检测方法的实现 105 - (BOOL)checkWithBlocks 106 { 107 BOOL gameWin = NO; 108 109 //所有的在砖块集合里的砖块的碰撞检测 110 for (UIImageView *block in _blocksImage) { 111 //苹果提供了一个 bool 类型的矩形碰撞检测函数 112 //如果两个矩形重叠了(也就是碰撞了),函数反悔 YES,否则返回 NO 113 //同时只检测,那些没有被隐藏的砖块,已经隐藏的就不需要碰撞检测了 114 if (CGRectIntersectsRect([block frame], [_ballImage frame]) && ![block isHidden]) { 115 //碰撞就消除砖块,其实是隐藏砖块的图像 116 [block setHidden:YES]; 117 //碰撞完成之后,要让小球向下运动 118 _ballV.y = abs(_ballV.y); 119 //保证循环的效率,提前退出循环 120 break; 121 } 122 } 123 124 //判断游戏是否胜利的逻辑 125 int count = 0; 126 127 for (UIImageView *block in _blocksImage) { 128 if ([block isHidden]) { 129 count++; 130 } 131 } 132 133 if (count == [_blocksImage count]) { 134 gameWin = YES; 135 } 136 137 return gameWin; 138 } 139 140 //小球和挡板的碰撞检测方法 141 - (void)checkWithPaddle 142 { 143 //如果小球和挡板碰撞 144 if (CGRectIntersectsRect([_ballImage frame], [_paddleImage frame])) { 145 //强制把小球 y 方向的速度设为负数,让它反弹回去 146 _ballV.y = -1 * abs(_ballV.y); 147 //给小球的 x 方向,加上水平的位移,让它能随着挡板的移动而水平的移动起来 148 _ballV.x += _deltaX; 149 } 150 } 151 152 //游戏时钟的处理方法, 因为对外不可见,故定义在 点m 文件里,而不是头文件里 153 - (void)step:(CADisplayLink *)sender 154 { 155 //让求(小球的图)动起来,本质 是 设置小球的 位置(也就是更新小球的位置的状态) 156 //小球中心点的 x 位置加上小球中心点的 x 方向的速度 157 //小球中心点的 y 位置加上小球中心点的 y 方向的速度 158 [_ballImage setCenter:CGPointMake(_ballImage.center.x + _ballV.x, _ballImage.center.y + _ballV.y)]; 159 //可以打印测试下,游戏时钟的方法是否是每秒钟运行60次 160 //NSLog(@"游戏运行了~"); 161 162 //在游戏时钟处理方法里,调用碰撞检测方法 163 if ([self checkWithScreen]) { 164 [self resetGamesStateWithMessage:@"游戏结束!"]; 165 } 166 167 if ([self checkWithBlocks]) { 168 [self resetGamesStateWithMessage:@"游戏胜利!"]; 169 } 170 171 [self checkWithPaddle]; 172 173 } 174 175 //触摸事件的实现 176 //触摸结束(手指抬起之后),游戏开始,小球动起来,这里的方法是支持多点触摸的 177 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *) event 178 { 179 //先判断本游戏是否已经开始了,如果游戏还没有开始: 180 if (!_isPlaying) { 181 //考虑一个点的触摸,获取触摸的对象 182 // UITouch *touch = [touches anyObject];//暂时用不到 183 184 // 触摸之后,给小球一个初始速度,0,-5, 185 //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5 186 _ballV = CGPointMake(0, -5); 187 188 //定义游戏时钟 189 //通过函数名来调用头文件里定义的另外的方法 step: 方法,时钟的目标是自己 190 _gameTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(step:)]; 191 192 //把当前时钟添加到游戏里经典的应用循环中,ios默认提供的循环方法 193 [_gameTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 194 195 //勿忘修改游戏状态的标识 196 //表面本游戏已经开始了 197 _isPlaying = YES; 198 } 199 } 200 201 //触摸移动的处理 202 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 203 { 204 if (_isPlaying) { 205 //获取手指移动的距离 206 UITouch *touch = [touches anyObject]; 207 208 //计算手指在 x 方向的移动举例 209 //方向分解 210 //本次触摸的位置 - 上次触摸的位置(x 方向的),就是水平方向的移动距离 211 //在声明里,定义一个成员变量,方便使用 212 //CGFloat deltaX = [touch locationInView:self.view].x - [touch previousLocationInView:self.view].x; 213 _deltaX = [touch locationInView:self.view].x - [touch previousLocationInView:self.view].x; 214 //挡板 x 方向的移动,y 方向不用管,不需要移动。 215 [_paddleImage setCenter:CGPointMake([_paddleImage center].x + _deltaX, [_paddleImage center].y)]; 216 } 217 } 218 219 @end
运行:
会出现,随着游戏的继续,小球速度越来越快!不合理!问题出在如下代码:在检测小球和挡板碰撞的方法里
//给小球的 x 方向,加上水平的位移,让它能随着挡板的移动而水平的移动起来 _ballV.x += _deltaX;
不符合物理常识,按照原则,应该修改为符合物理常识的碰撞和移动。
最后修正
每次手指离开屏幕之后,都把水平的距离变化设置为0,且代码其他一些善后操作要做一些修正。
比较粗糙的完整运行的代码,离着发布还有一定距离。
1 // 2 // ViewController.m 3 // 打砖块小游戏 4 // 5 // Created by 大帅 on 14-12-21. 6 // Copyright (c) 2014年 dashuai. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 //引入动画框架 QuartzCore 11 #import <QuartzCore/QuartzCore.h> 12 13 //私有的变量,在 m 文件里定义一下 14 @interface ViewController () 15 { 16 //游戏开始的标志 17 BOOL _isPlaying; 18 19 //定义游戏的时钟 20 CADisplayLink *_gameTimer; 21 22 //定义小球的速度,_ballV来表示 23 CGPoint _ballV; 24 25 //水平位移 26 CGFloat _deltaX; 27 } 28 29 //游戏时钟的处理方法,对外不可见,应该定义在点m 文件里 30 - (void)step:(CADisplayLink *)sender; 31 32 //检测和屏幕边缘的碰撞 33 - (BOOL)checkWithScreen; 34 35 //检测和砖块的碰撞 36 - (BOOL)checkWithBlocks; 37 38 //检测和挡板的碰撞 39 - (void)checkWithPaddle; 40 41 //重置游戏的状态 42 //游戏胜利,失败的状态 43 - (void)resetGamesStateWithMessage:(NSString *)message; 44 45 @end 46 47 @implementation ViewController 48 49 - (void)viewDidLoad { 50 [super viewDidLoad]; 51 // Do any additional setup after loading the view, typically from a nib. 52 } 53 54 - (void)didReceiveMemoryWarning { 55 [super didReceiveMemoryWarning]; 56 // Dispose of any resources that can be recreated. 57 } 58 59 //游戏的重置方法的实现 60 - (void)resetGamesStateWithMessage:(NSString *)message 61 { 62 NSLog(@"%@", message); 63 64 //先把时钟清除也就是关掉,千万不要忘记,否则后果很严重!不亚于内存泄露的错误! 65 //之后,step 方法不会被调用,同时游戏是开始状态的 66 [_gameTimer invalidate]; 67 68 //然后所有的砖块的图片全部恢复,设置为可见 69 for (UIImageView *block in _blocksImage) { 70 [block setHidden:NO]; 71 //把透明度设置为0,此时,肉眼又看不见了 72 [block setAlpha:0]; 73 //把砖块缩小到一个看不见的点 74 [block setFrame:CGRectMake(block.center.x, block.center.y, 0, 0)]; 75 } 76 77 //用两秒钟做一个动画 78 [UIView animateWithDuration:2.0 animations:^{ 79 for (UIImageView *block in _blocksImage) { 80 //然后这里的动画效果,再把砖块的透明度设置为1,可见了。 81 [block setAlpha:1]; 82 //接下来把砖块放大的效果实现 83 [block setFrame:CGRectMake(block.center.x - 32, block.center.y - 10, 64, 20)]; 84 } 85 }completion:^(BOOL finished){ 86 _isPlaying = NO; 87 //屏幕的中间位置 x是160 88 //把小球设置到中间 89 [_ballImage setCenter:CGPointMake(160, 430)]; 90 91 //把挡板设置到中间位置也 92 [_paddleImage setCenter:CGPointMake(160, 450)]; 93 }]; 94 95 96 } 97 98 //小球和屏幕的碰撞检测方法实现 99 - (BOOL)checkWithScreen 100 { 101 //除了下方的屏幕边缘,其他的都是反弹回来,而下方是掉出去,游戏失败 102 BOOL gameOver = NO; 103 104 //左边碰撞检测的处理,比较简单,因为屏幕的原点就是在左边的线上 105 if ([_ballImage frame].origin.x <= 0) { 106 //反弹回去,就是把它取正数,x 方向的速度变为正数,使用绝对值函数 107 _ballV.x = abs(_ballV.x); 108 } 109 110 //右边碰撞检测处理,小球边框的距离原点的 x 加上小球本身的宽度,如果大于了视图本身边框的宽度的尺寸,那就是碰撞 111 if ([_ballImage frame].origin.x + [_ballImage frame].size.width >= self.view.frame.size.width) { 112 //反弹,就是保证小球 x 方向的速度必须为负的 113 _ballV.x = -1 * abs(_ballV.x); 114 } 115 116 //顶部屏幕的碰撞检测处理 117 if ([_ballImage frame].origin.y <= 0) { 118 _ballV.y = abs(_ballV.y); 119 } 120 121 //底部碰撞检测处理 122 if ([_ballImage frame].origin.y + [_ballImage frame].size.height >= self.view.frame.size.height) { 123 gameOver = YES; 124 } 125 126 return gameOver; 127 } 128 129 //小球和方块的碰撞检测方法的实现 130 - (BOOL)checkWithBlocks 131 { 132 //所有的在砖块集合里的砖块的碰撞检测 133 for (UIImageView *block in _blocksImage) { 134 //苹果提供了一个 bool 类型的矩形碰撞检测函数 135 //如果两个矩形重叠了(也就是碰撞了),函数反悔 YES,否则返回 NO 136 //同时只检测,那些没有被隐藏的砖块,已经隐藏的就不需要碰撞检测了 137 if (CGRectIntersectsRect([block frame], [_ballImage frame]) && ![block isHidden]) { 138 //碰撞就消除砖块,其实是隐藏砖块的图像 139 [block setHidden:YES]; 140 //碰撞完成之后,要让小球向下运动 141 _ballV.y = abs(_ballV.y); 142 //保证循环的效率,提前退出循环 143 break; 144 } 145 } 146 147 //判断游戏是否胜利的逻辑 148 BOOL gameWin = YES; 149 150 for (UIImageView *block in _blocksImage) { 151 //如果砖块有没被隐藏的,就认为游戏失败了,否则胜利 152 if (![block isHidden]) { 153 gameWin = NO; 154 //节省性能,发现一个就行了 155 break; 156 } 157 } 158 159 return gameWin; 160 161 //如下比较耗费性能 162 163 // int count = 0; 164 // 165 // for (UIImageView *block in _blocksImage) { 166 // if ([block isHidden]) { 167 // count++; 168 // } 169 // } 170 // 171 // if (count == [_blocksImage count]) { 172 // gameWin = YES; 173 // } 174 } 175 176 //小球和挡板的碰撞检测方法 177 - (void)checkWithPaddle 178 { 179 //如果小球和挡板碰撞 180 if (CGRectIntersectsRect([_ballImage frame], [_paddleImage frame])) { 181 //强制把小球 y 方向的速度设为负数,让它反弹回去 182 _ballV.y = -1 * abs(_ballV.y); 183 //给小球的 x 方向,加上水平的位移,让它能随着挡板的移动而水平的移动起来 184 _ballV.x += _deltaX; 185 } 186 } 187 188 //游戏时钟的处理方法, 因为对外不可见,故定义在 点m 文件里,而不是头文件里 189 - (void)step:(CADisplayLink *)sender 190 { 191 //让求(小球的图)动起来,本质 是 设置小球的 位置(也就是更新小球的位置的状态) 192 //小球中心点的 x 位置加上小球中心点的 x 方向的速度 193 //小球中心点的 y 位置加上小球中心点的 y 方向的速度 194 [_ballImage setCenter:CGPointMake(_ballImage.center.x + _ballV.x, _ballImage.center.y + _ballV.y)]; 195 //可以打印测试下,游戏时钟的方法是否是每秒钟运行60次 196 //NSLog(@"游戏运行了~"); 197 198 //在游戏时钟处理方法里,调用碰撞检测方法 199 if ([self checkWithScreen]) { 200 [self resetGamesStateWithMessage:@"游戏结束!"]; 201 } 202 203 if ([self checkWithBlocks]) { 204 [self resetGamesStateWithMessage:@"游戏胜利!"]; 205 } 206 207 [self checkWithPaddle]; 208 209 } 210 211 //触摸事件的实现 212 //触摸结束(手指抬起之后),游戏开始,小球动起来,这里的方法是支持多点触摸的 213 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *) event 214 { 215 //先判断本游戏是否已经开始了,如果游戏还没有开始: 216 if (!_isPlaying) { 217 //考虑一个点的触摸,获取触摸的对象 218 // UITouch *touch = [touches anyObject];//暂时用不到 219 220 // 触摸之后,给小球一个初始速度,0,-5, 221 //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5 222 _ballV = CGPointMake(0, -5); 223 224 //定义游戏时钟 225 //通过函数名来调用头文件里定义的另外的方法 step: 方法,时钟的目标是自己 226 _gameTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(step:)]; 227 228 //把当前时钟添加到游戏里经典的应用循环中,ios默认提供的循环方法 229 [_gameTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 230 231 //勿忘修改游戏状态的标识 232 //表面本游戏已经开始了 233 _isPlaying = YES; 234 } 235 else 236 { 237 //重置水平移动举例 238 _deltaX = 0; 239 } 240 } 241 242 //触摸移动的处理 243 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 244 { 245 if (_isPlaying) { 246 //获取手指移动的距离 247 UITouch *touch = [touches anyObject]; 248 249 //计算手指在 x 方向的移动举例 250 //方向分解 251 //本次触摸的位置 - 上次触摸的位置(x 方向的),就是水平方向的移动距离 252 //在声明里,定义一个成员变量,方便使用 253 //CGFloat deltaX = [touch locationInView:self.view].x - [touch previousLocationInView:self.view].x; 254 _deltaX = [touch locationInView:self.view].x - [touch previousLocationInView:self.view].x; 255 //挡板 x 方向的移动,y 方向不用管,不需要移动。 256 [_paddleImage setCenter:CGPointMake([_paddleImage center].x + _deltaX, [_paddleImage center].y)]; 257 } 258 } 259 260 @end
离发布还要至少经过:
素材的完善和优化:
•图像素材的完备:图标、启动图像
•必须要有音频:没有声音的游戏是不可想象的
•多语言(perfect!)
程序的优化:
•游戏要设置难度和手动的调整 & 最好是有物理的仿真
•要有关卡的设置
•玩家得分与奖励制度的建立
•游戏暂停功能(必须要)
•游戏状态保存(必须的)