跟我学ios开发(二)-分析一个简单的游戏

来源:互联网 发布:小聪软件 编辑:程序博客网 时间:2024/05/17 15:20

我常去的网站:http://www.cocoachina.com/,算是国内比较好的一个学习ios开发论坛了;当然少不了百度。学习过程中遇到任何问题都不要拖着放在一边,一定要查资料搞清楚才行。最直接的方法:对不懂的地方按住option并点击就可以查看xcode的文档。

另外一个好地方:www.code4app.com,可以下载并学习大量源码。今天分析的一个源码就是在这里下载的,一个简单的打砖头游戏。这个源码比较简单,没有涉及到cocoa2d等框架,比较适合初学者学习。下载链接

首先我们打开解压后的工程文件:Breakout.xcodeproj,先直接运行看看效果:点击上面的播放键,用鼠标按住平板可以移动。


看起来还不错~(这里我增加了生命,主要是不太好控制)

下面我们来分析下源码。

首先要说明的是框架(frameworks)文件夹里的这几个文件:

QuartzCore.framework:使用"绘画者模型”,实现图层编程。将图层(layer)放置于画布上(canvas)进行绘图。类似于油画作画。

UIKit.framework:实现ios的用户界面、绘图模型、事件控制等。

Foundation.framework:包括各种object c的基础类型、集合等。

CoreGraphics.framework:简单的说,就是我们可以用来自己绘制ui的框架。


接下来我们看看作者定义的几个类:

BRKBall:定义球的类型,以及几种操作。这里比较简单,重点说一下 update这个函数。

- (void) update{ 
    //Keep adjusting the ball's position untill a valid one if found.
    while(![self isPositionValid]);
    self.center = [self nextPosition];
}

这里用来返回球的下一个位置并由此设置球的中心。这里可以去掉isPositionValid这个函数,直接替换成isWithinStageBounds也可以,就是判断球的下一个位置是否在屏幕内,如果不是则根据球到达的边界就在x 或者y轴反向。也就是说这个循环只需执行1-2次就可以返回了。

这里会有个疑问,球如果已经在平板下面,到达最底部还会反弹吗?待会再解释。


BRKBlock:定义砖块的类。

BRKPaddle:定义平板的类。

这两个类及其实现都比较简单,要说明的是作者将碰撞后的碎纹图片跟当前的砖块图片进行了整合作为新的图片给了砖块。不过这里的update函数似乎也有个问题,砖块的生命值减到0后应该会消失,这里为何没有处理?


终于到重头戏了,BRKStageViewController了。

如果理解MVC的话这里就不难理解了,view controller就是将我们定义的model:BKGBall、BKGBlock、BKGPaddle,跟视图view:BKGStage.xib联系在一起,处理模型的逻辑并在视图上进行显示。具体怎么做的,我们继续往下看:

首先说明一下程序的加载步骤,对于我们理解BKGStageViewController.m有帮助。


这是一个应用启动的步骤,对应这个游戏为:

main.m:main(),UIApplicationMain(argc, argv, nil, NSStringFromClass([BRKAppDelegate class]));

BRKAPPDelegate.m:didFinishLaunchingWithOptions(),stageViewController = [[BRKStageViewController alloc] initWithNibName:@"BRKStage" bundle:nil];

关于委托就不再多说了,大家可以搜一下这个基本概念。

这里我们可以看到,调用了BRKStageViewController 的initWithNibName函数。这个函数定义在UIViewController类里,进行初始化相关的工作。这里牵扯到uiviewcontroller生命周期的概念,这里不再赘述了,搜一下吧。

作者在初始化的过程中进行了如下几个操作:

displayLink = [NSClassFromString(@"CADisplayLink")displayLinkWithTarget:selfselector:@selector(gameLoop:)];

[displayLink addToRunLoop:[NSRunLoopcurrentRunLoop] forMode:NSDefaultRunLoopMode];

简单的说,CADisplayLink类实现画面重绘功能,默认为60次/秒,即60fps,@selector类似于函数指针,调用定义的gameLoop函数;第二行指定了循环的模式。

[selfplayPause];

注意这里,在初始化之前先暂停画面。大家也可以试试剪切这句放到viewDidUnload里是什么情况。

再看看playPause:

- (IBAction)playPause {

    //On resume form game over hide the labels.

    if(gameOver){

        gameOverLabel.hidden =YES;

        playToRestartLabel.hidden =YES;

    }

   displayLink.paused = !displayLink.paused;

    [playPauseButtonsetImage:[UIImageimageNamed:displayLink.isPaused ?@"play.png" : @"pause.png"]forState:UIControlStateNormal];

}

其实这里是有问题的,self在初始化后就直接判断gameOver是否为真,但这时其实gameOver的值并不确定,只是碰巧初始化后设为0而已。所以我们修改成[self pause]比较好。


另外要说明的一点是 displayLink.paused = YES;这句是将displayLink的paused属性(BOOL类型)设为YES,我们会有个疑问:仅仅设置为YES就可以暂停了?

我们看看这个属性的定义:@property(getter=isPaused, nonatomic) BOOL paused;这里的getter方法由isPaused代替,但这是系统自己的操作,我们并不用关心。因为我没有找到CADisplayLink的具体实现(也不会让你找到吧..),必然会在每次执行前都会调用isPaused()函数以判断游戏是否继续。

接下来就很简单了,初始化球、砖块、平板等的位置和颜色。具体的gameLoop实现等也比较简单,大家可以看看。

关于之前说的两个问题:

1.球落到最底面下面会反弹吗?

这里肯定不会,因为每次循环都会判断当前球的位置是否在平板上面,只要刚刚低于平台的时候就会暂停,并重置球和平板的位置。

2.砖块的生命会不会为负值?

看看这里就明白了:

for(BRKBlock *block in blocks){

            

            //Check is the ball will hit a block

            if([block isImpactWithBallAtPosition:nextPosition]){

                

                //If the block has zero health remove it.

                if([block update] == 0 ){

                    

                    [blocks removeObject:block];

                    [block removeFromSuperview];

                    [self updateScore];

                }

                [ball bounce];

                break;//Jump out of the for loop on impact.

            }

        }

每次循环中,球最多只会碰到一个砖块,因此跳出循环节省CPU。

好了,第二篇就到此结束。

ps:

最近工作太忙,挤时间写博客真的是体力活啊。

下一篇分析一下code4app上面的一个类似于捕鱼达人的游戏吧,感谢开源的朋友~这个游戏涉及cocoa2d、opengl es、avfoundation等比较复杂的框架和库,先提前学习一下相关知识吧。













原创粉丝点击