首页 > 代码库 > IOS 开发入门—打砖块小游戏

IOS 开发入门—打砖块小游戏

忙着期末考试,读书笔记断更了~
 
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 //引入动画框架 QuartzCore11 #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 @end29 30 @implementation ViewController31 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 *)sender44 {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 *) event56 {57     //先判断本游戏是否已经开始了,如果游戏还没有开始:58     if (!_isPlaying) {59         //考虑一个点的触摸,获取触摸的对象60        // UITouch *touch = [touches anyObject];//暂时用不到61         62         // 触摸之后,给小球一个初始速度,0,-5,63         //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去564         _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)checkWithBlocks102 {103     BOOL gameWin = NO;104     105     //所有的在砖块集合里的砖块的碰撞检测106     for (UIImageView *block in _blocksImage) {107         //苹果提供了一个 bool 类型的矩形碰撞检测函数108         //如果两个矩形重叠了(也就是碰撞了),函数反悔 YES,否则返回 NO109         //同时只检测,那些没有被隐藏的砖块,已经隐藏的就不需要碰撞检测了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)checkWithPaddle138 {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 *)sender148 {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 *) event172 {173     //先判断本游戏是否已经开始了,如果游戏还没有开始:174     if (!_isPlaying) {175         //考虑一个点的触摸,获取触摸的对象176        // UITouch *touch = [touches anyObject];//暂时用不到177         178         // 触摸之后,给小球一个初始速度,0,-5,179         //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5180         _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)checkWithBlocks106 {107     BOOL gameWin = NO;108     109     //所有的在砖块集合里的砖块的碰撞检测110     for (UIImageView *block in _blocksImage) {111         //苹果提供了一个 bool 类型的矩形碰撞检测函数112         //如果两个矩形重叠了(也就是碰撞了),函数反悔 YES,否则返回 NO113         //同时只检测,那些没有被隐藏的砖块,已经隐藏的就不需要碰撞检测了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)checkWithPaddle142 {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 *)sender154 {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 *) event178 {179     //先判断本游戏是否已经开始了,如果游戏还没有开始:180     if (!_isPlaying) {181         //考虑一个点的触摸,获取触摸的对象182        // UITouch *touch = [touches anyObject];//暂时用不到183         184         // 触摸之后,给小球一个初始速度,0,-5,185         //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5186         _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 *)event203 {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)checkWithScreen100 {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)checkWithBlocks131 {132     //所有的在砖块集合里的砖块的碰撞检测133     for (UIImageView *block in _blocksImage) {134         //苹果提供了一个 bool 类型的矩形碰撞检测函数135         //如果两个矩形重叠了(也就是碰撞了),函数反悔 YES,否则返回 NO136         //同时只检测,那些没有被隐藏的砖块,已经隐藏的就不需要碰撞检测了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)checkWithPaddle178 {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 *)sender190 {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 *) event214 {215     //先判断本游戏是否已经开始了,如果游戏还没有开始:216     if (!_isPlaying) {217         //考虑一个点的触摸,获取触摸的对象218        // UITouch *touch = [touches anyObject];//暂时用不到219         220         // 触摸之后,给小球一个初始速度,0,-5,221         //-5就是 y 向下的过程,每一次时钟触发的时候,y 都减去5222         _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     else236     {237         //重置水平移动举例238         _deltaX = 0;239     }240 }241 242 //触摸移动的处理243 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event244 {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!)
 
程序的优化:
•游戏要设置难度和手动的调整 & 最好是有物理的仿真
•要有关卡的设置
•玩家得分与奖励制度的建立
•游戏暂停功能(必须要)
•游戏状态保存(必须的) 
 

IOS 开发入门—打砖块小游戏