疯狂ios
2014-01-18 11:12:32 cynixway 阅读数 2428

最近在看iOS开发方面的东西,想找一本书来看看。纸质的图书翻阅比较方便,为了支持国产,听说疯狂系列的书大家都感觉可以。

于是就买来一本看看。于是真的知道了“听说而已”

目前翻阅到第五章,感觉不来抒发一下郁闷不行了。

这本书比一般的国产书相对来好点。不像某些挂羊头的,出版社为了跟iOS7的风,显然是名不符题。其作者都不不好意思的道歉了。

我来给这本书挑刺吧

1、不够严谨

new操作符是为了方便Java程序员么?只能说你满脑子都是Java。我不了解疯狂Java……,我对Java无爱好,无歧视。可以goole一下

关于new,alloc init还是有一大堆人讨论过。

2、编辑错误

打错字的,代码段重复,缺少代码的。这类是我发现最多的。粗翻之下已经有好几个了。好吧编辑你胜利了

这本书,好吧,就这样结束郁闷吧,要好好努力啊。


2017-05-09 10:27:00 weixin_33774615 阅读数 4

分享资源给那些不知道买什么书的人,上干货。

链接: https://pan.baidu.com/s/1i5sV2TJ 密码: 2w96

注:链接只有7天有效期,请大家自行保存。到期没看到的朋友们请@YYSheng

《疯狂iOS讲义》 是2014年电子工业出版社出版的图书,作者是李刚。基于iOS 7平台,全部案例均通过iPhone 5s真机测试。商业级手游代码无保留全盘呈现。国家级行业大奖得主、电子工业出版社优秀作者、IT名家李刚老师出品,一如既往的质量保障。iOS开发零基础入门请阅读《疯狂iOS讲义(下)--Objective-C 2.0与iPhone/iPad应用开发基础》。

目录

****第1章 多点触摸与手势检测1****
 1.1 响应者链 2
 1.2 响应触碰方法 3
 1.3 使用手势处理器(UIGestureRecognizer)3
 1.3.1 使用UITapGestureRecognizer处理点击手势4
 1.3.2 使用UIPinchGestureRecognizer处理捏合手势 6
 实例:通过捏合手势缩放图片7
 1.3.3 使用UIRotationGestureRecognizer处理旋转手势 9
 实例:通过旋转手势旋转图片9
 1.3.4 使用UISwipeGestureRecognizer处理轻扫手势 10
 实例:贪食蛇 12
 1.3.5 使用UIPanGestureRecognizer处理拖动手势18
 1.3.6 使用UILongPressGestureRecognizer处理长按手势 19
 实例:长按添加按钮20
 1.4 创建和使用自定义手势处理器 21
 1.4.1 开发自定义手势处理器 21
 1.4.2 使用自定义手势处理器 23
 1.5本章小结 24
****第2章 国际化25****
 2.1iOS应用国际化的基础 26
 2.1.1 iOS应用的国际化思路26
 2.1.2 Objective-C国际化支持的语言和国家 28
 2.2 国际化界面设计文件 29
 2.3国际化应用程序的显示名称 32
 2.4国际化图片 34
 2.5国际化文本 35
 2.6本章小结 38
****第3章 iOS的数据存储与IO39****
 3.1应用程序沙盒 40
 3.1.1获取Documents目录 41
 3.1.2获取tmp目录41
 3.1.3文件保存策略思考41
 3.2应用程序参数与用户默认设置42
 3.2.1使用Settings Bundle 42
 3.2.2使用NSUserDefaults读取、保存应用程序参数50
 3.3属性列表 54
 实例:备忘录 55
 3.4对象归档和原生I/O API58
 3.5使用SQLite 3数据库 58
 3.5.1iOS的SQLite编程58
 3.5.2创建数据库和表 63
 3.5.3使用SQL语句执行查询63
 实例:英文生词本 64
 3.5.4使用sqlite3工具 67
 3.5.5使用SQLite Manager管理数据库69
 3.6使用Core Data框架 71
 3.6.1Core Data简介 71
 3.6.2初始化Core Data项目 73
 3.6.3设计实体模型76
 3.6.4使用Core Data实现数据的增、删、改、查 78
 3.6.5管理实体的关联关系 84
 实例:图书管理系统84
 3.7本章小结 95
****第4章 多媒体应用开发 96****
 4.1音频和视频的播放 97
 4.1.1使用System Sound Services播放音效97
 4.1.2使用AVAudioPlayer播放音乐 98
 4.1.3使用MPMediaPickerController选择系统音乐 102
 实例:简单音乐播放器 103
 4.1.4使用MPMoviePlayerController播放视频 106
 4.2使用AVAudioRecorder录制音频 108
 4.3拍照和录制视频112
 4.3.1使用UIImagePickerController拍照和录制视频112
 4.3.2使用AVFoundation拍照和录制视频 116
 实例:完全自定义的相机118
 4.4使用AVFoundation生成视频缩略图135
 4.5本章小结 137
****第5章 管理手机 138****
 5.1使用AddressBook管理联系人 139
 5.1.1删除联系人 142
 5.1.2添加联系人 144
 5.1.3修改联系人 147
 5.2使用AddressBookUI管理联系人 151
 5.2.1使用ABNewPersonViewController添加联系人 153
 5.2.2使用ABUnknownPersonViewController显示未知联系人 154
 5.2.3使用ABPeoplePickerNavigationController选择联系人 156
 5.2.4使用ABPersonViewController显示指定联系人 157
 5.3使用UIApplication打电话、发短信 159
 5.4使用MFMessageComposeViewController发短信160
 5.5使用MFMailComposeViewController发送邮件 162
 5.6本章小结 165
****第6章 加速计与陀螺仪 166****
 6.1iOS支持的加速计和陀螺仪 167
 6.1.1iOS加速计和陀螺仪的理论基础167
 6.1.2基于代码块方式获取加速度数据、陀螺仪数据、磁场数据 168
 6.1.3主动请求获取加速度数据、陀螺仪数据、磁场数据172
 实例:怪物足球173
 6.2感知设备移动 178
 实例:水平仪 181
 6.3iOS 7新增的计步器184
 6.4iOS 7新增的CMMotionActivityManager 186
 6.5本章小结 188
****第7章 多线程 189****
 7.1线程概述 190
 7.1.1线程和进程 190
 7.1.2多线程的优势191
 7.2使用NSThread实现多线程192
 7.2.1创建和启动线程 192
 7.2.2线程的状态 194
 7.2.3终止子线程 194
 7.2.4线程睡眠195
实例:使用线程下载网络图片196
 7.2.5改变线程优先级 197
 7.3线程同步与线程通信199
 7.3.1线程安全问题199
 7.3.2使用@synchronized实现同步201
 7.3.3释放对同步监视器的锁定 203
 7.3.4同步锁(NSLock)203
 7.3.5使用NSCondition控制线程通信 205
 实例:生产者-消费者 205
 7.4使用GCD实现多线程208
 7.4.1创建队列209
 7.4.2异步提交任务210
 实例:使用GCD下载图片212
 7.4.3同步提交任务213
 7.4.4多次执行的任务 214
 7.4.5只执行一次的任务215
 7.5后台运行 216
 7.5.1进入后台时释放内存 216
 实例:疯狂飞机大战216
 7.5.2进入后台时保存状态 223
 7.5.3请求更多的后台时间 223
 7.6使用NSOperation与NSOperationQueue实现多线程225
 7.6.1使用NSInvocationOperation和NSBlockOperation226
 实例:使用NSBlockOperation下载图片 226
 7.6.2定义NSOperation子类 227
 7.7本章小结 229
****第8章 iOS网络应用编程 230****
 8.1检测网络状态 231
 8.1.1检查网络状态 231
 8.1.2监听网络状态改变 234
 8.2使用CFNetwork实现TCP协议的通信 235
 8.2.1IP地址与端口号 236
 8.2.2TCP协议基础236
 8.2.3使用CFSocket实现TCP服务器端 237
 8.2.4使用CFSocket实现TCP客户端241
 实例:网络聊天程序244
 8.2.5使用CocoaAsyncSocket实现TCP客户端247
 8.3使用NSURLConnection 250
 8.3.1使用NSURLConnection从网络获取数据 250
 8.3.2使用NSMutableURLRequest向服务器发送数据 253
 8.4XML解析 255
 8.4.1DOM与SAX 255
 8.4.2使用NSXMLParser解析XML文档 257
 8.4.3使用libxml2解析XML文档 262
 8.4.4使用GDataXML解析XML文档 266
 8.4.5使用GDataXML生成、修改XML文档268
 8.5JSON解析 271
 8.5.1JSON的基本知识 271
 8.5.2使用NSJSONSerialization处理JSON数据 274
 8.5.3使用SBJson解析JSON数据 274
 8.5.4使用JSONKit解析JSON数据 275
 8.6使用AFNetworking实现网络通信280
 8.6.1提交GET请求与提交POST请求280
 实例:访问被保护资源 281
 8.6.2处理JSON或Plist响应 284
 8.6.3处理XML响应 288
 8.6.4上传文件 290
 8.7使用ASIHTTPRequest框架实现网络编程 293
 8.7.1发送同步或异步的GET请求 293
 8.7.2使用代码块 296
 8.7.3使用NSOperationQueue管理请求 297
 8.7.4发送请求参数和文件上传 299
 实例:天气预报300
 8.8本章小结 311
****第9章 使用CoreLocation定位 312****
 9.1iOS的定位支持313
 9.1.1GPS卫星定位313
 9.1.2基站定位 314
 9.1.3WiFi定位 314
 9.2获取定位信息 314
 9.2.1获取位置信息 315
 9.2.2使用iOS模拟器模拟位置 318
 9.2.3监控行车速度和行车距离 318
 9.3方向监测 320
 实例:指南针 322
 9.4区域监测 323
 9.5本章小结 325
****第10章 使用MapKit开发地图服务 326****
 10.1使用MapKit框架 327
 10.1.1使用MKMapView控件328
 10.1.2指定地图显示中心和显示区域329
 10.1.3使用iOS 7新增的MKMapCamera 332
 10.2根据地址定位333
 10.2.1地址解析与反向地址解析333
 10.2.2根据地址定位 337
 10.3在地图上添加锚点340
 10.3.1添加简单的锚点340
 10.3.2添加自定义锚点343
 10.4在地图上添加覆盖层 345
 10.4.1添加几何覆盖层346
 10.4.2使用iOS 7新增的MKTileOverlay覆盖层 348
 10.5使用iOS 7新增的MKDirections获取导航路线 350
 实例:行车导航仪 351
 10.6本章小结 354
****第11章 推送机制 355****
 11.1使用NSNotificationCenter通信 356
 11.1.1使用NSNotificationCenter监听系统组件的通知 358
 11.1.2使用NSNotificationCenter监听自定义通知 359
 11.2iOS本地通知 361
 11.3iOS远程推送通知 364
 11.3.1开发Push客户端应用366
 11.3.2开发Push服务端程序377
 11.4本章小结 381
****第12章 iCloud服务与应用 382****
 12.1iCloud入门 383
 12.1.1为应用开启iCloud服务 384
 12.1.2使用NSMetadataQuery查询文档389
 12.1.3添加文档 393
 12.1.4编辑文档 395
 12.1.5删除文档 397
 12.2使用iCloud保存云端首选项 398
 12.3本章小结 401
****第13章 使用cocos2d开发2D游戏402****
 13.1cocos2d简介 403
 13.1.1cocos2d的特点 403
 13.1.2cocos2d的主要功能 403
 13.2cocos2d的下载与安装 404
 13.2.1 下载cocos2d 404
 13.2.2安装cocos2d405
 13.2.3使用cocos2d-iPhone的帮助文档 405
 13.2.4cocos2d中内置的项 406
 13.3创建cocos2d项目 407
 13.3.1HelloWorld cocos2d项目 407
 13.3.2cocos2d项目如何支持ARC 408
 13.3.3cocos2d项目结构和代码分析 413
 13.4CCNode节点类 419
 13.4.1CCNode类的属性 419
 13.4.2CCNode类的方法420
 13.5CCScene场景类 423
 13.5.1CCTransitionScene 场景切换423
 13.5.2cocos2d支持的场景过渡效果 424
 13.6CCLayer类 424
 13.6.1CCLayer类的属性 425
 13.6.2CCLayer类的常用方法 425
 13.6.3CCLayer类的作用 425
 13.6.4CCLayerColor类的属性和方法425
 13.6.5CCLayerGradient渐变色层类 426
 13.6.6CCMenu菜单类 426
 13.7CCDirector导演类429
 13.7.1CCDirector导演类的属性430
 13.7.2CCDirector导演类的方法430
 13.8CCTexture纹理类 431
 13.8.1纹理的相关概念431
 13.8.2纹理相关的类 431
 13.9CCSprite精灵类 432
 13.9.1CCSprite精灵类的属性 432
 13.9.2CCSprite精灵类的方法 432
 13.9.3CCSpriteFrame精灵帧 435
 13.9.4CCSpriteFrameCache精灵帧缓存 436
 13.9.5CCSpriteBatchNode精灵表单 436
 13.9.6制作精灵表单 438
 13.9.7精灵表单示例 440
 13.10cocos2d中的动作442
 13.10.1cocos2d中的动作类443
 13.10.2基本动作 444
 13.10.3组合动作 453
 13.10.4Ease动作 454
 13.10.5延迟动作 456
 13.10.6方法回调动作 456
 13.10.7代码块调用动作 460
 13.11cocos2d中的动画462
 13.11.1cocos2d中动画相关的类462
 13.11.2简单动画效果 463
 13.11.3使用精灵表单实现动画效果 464
 13.12cocos2d中的文本466
 13.12.1CCLabelTTF类 466
 13.12.2CCLabelBMFont类 467
 13.13cocos2d中的声音470
 13.13.1SimpleAudioEngine470
 13.13.2游戏中的声音设置选项功能实现 474
 13.14疯狂打飞机游戏 477
 13.14.1开始前的准备工作 477
 13.14.2添加游戏菜单项功能 478
 13.14.3预加载游戏资源 480
 13.14.4玩家飞机飞行效果 485
 13.14.5玩家飞机Touch实现 487
 13.14.6背景滚动效果 488
 13.14.7添加敌机 491
 13.14.8玩家飞机添加子弹并射击 494
 13.14.9添加背景音乐 498
 13.14.10 添加游戏积分统计 498
 13.14.11 添加游戏大Boss 500
 13.15本章小结 504
****第14章 粒子效果、瓦片地图和物理引擎 505****
 14.1粒子系统相关的类506
 14.1.1CCParticleSystem类506
 14.1.2CCParticleSystemQuad类511
 14.1.3CCParticleBatchNode类 512
 14.2cocos2d中内置的粒子系统 512
 14.2.1使用cocos2d内置的粒子系统513
 14.2.2手动创建粒子系统类514
 14.3使用Particle Designer生成粒子效果 517
 14.3.1Particle Designer粒子工具的使用 518
 14.3.2使用plist文件创建粒子系统520
 14.4瓦片地图520
 14.4.1下载和安装Tiled地图编辑器521
 14.4.2使用Tiled绘制地图522
 14.5Tiled地图相关的类 527
 14.5.1CCTMXTiledMap类 527
 14.5.2CCTMXLayer类 529
 14.5.3CCTMXObjectGroup类530
 14.6在项目中使用Tiled地图 530
 14.7真实手游:萌仙 535
 14.7.1设计地图场景 535
 14.7.2载入地图 535
 14.7.3地图的移动537
 14.7.4物体遮挡效果 539
 14.7.5设置障碍物542
 14.7.6寻路算法 544
 14.7.7随机出现怪物 549
 14.7.8玩家和怪物进行战斗552
 14.8Box2D物理引擎 559
 14.8.1物理引擎概述 559
 14.8.2Box2D的核心概念 559
 14.8.3Box2D常用的属性和方法 562
 14.8.4Box2D模板项目HelloBox2D 563
 14.8.5HelloBox2D模板项目代码分析565
 14.8.6cocos2d和Box2D 573
 14.8.7Box2D开发步骤 575
 14.9开发Box2D项目 575
 14.10愤怒的小鸟 581
 14.10.1开始前的准备工作 581
 14.10.2制作游戏启动画面 581
 14.10.3进度条制作 582
 14.10.4游戏中的粒子效果 585
 14.10.5游戏选关操作 590
 14.10.6设计关卡数据 594
 14.10.7设计精灵类 596
 14.10.8游戏主界面 601
 14.10.9弹弓发射小鸟 604
 14.10.10 整合Box2D物理引擎 609
 14.10.11 游戏过关设计 613
 14.11本章小结 616

2014-04-22 11:27:46 weixin_34110749 阅读数 6

4玩家飞机飞行效果

下面添加游戏背景图片和玩家操控的飞机。打开HelloWorldLayer.m文件,首先定义4个变量,实现代码如下。

程序清单:codes/13/13.14/AirfightGame/AirfightGame/HelloWorldLayer.m

// 精灵表单tag
    static NSInteger kTagBatchNode = 1;
    // 玩家飞机变量
    CCSprite* planeSprite;
    // 屏幕宽度、高度的变量
    NSInteger screenWidth , screenHeight;

然后在init方法中添加背景图片,实现代码如下(程序清单同上)。

-(id) init
{
    if( (self=[super init]) ) {
        // ①本例使用精灵表单来优化游戏性能,
        // CCSpriteBatchNode中的所有CCSprite只会被渲染1次,因此可以提高游戏的FPS
        batchNode = [CCSpriteBatchNode batchNodeWithFile:@"airfightSheet.png"];
        batchNode.position = CGPointZero;
        [self addChild:batchNode z:0 tag:kTagBatchNode];
        // 获取屏幕宽度和高度
        CGSize winSize = [[CCDirector sharedDirector] winSize];
        screenWidth = winSize.width;
        screenHeight = winSize.height;
        // ②添加背景图片
        CCSprite* bgSprite = [CCSprite spriteWithSpriteFrameName:@"bg1.png"];
        bgSprite.position = ccp(screenWidth/2,screenHeight/2);
        [batchNode addChild:bgSprite];
    }
    return self;
}

以上代码①创建了一个CCSpriteBatchNode使用精灵表单加载精灵,优化游戏性能。接下来获取屏幕宽度和高度。代码②初始化了一个背景图片精灵,添加到CCSpriteBatchNode当中。

最后在onEnter方法中添加玩家飞机,实现代码如下(程序清单同上)。

// 节点调用init方法以后将会调用此方法
-(void) onEnter{
    [super onEnter];
    // ③添加玩家飞机精灵
    planeSprite = [CCSprite spriteWithSpriteFrameName:@"plane0.png"];
    planeSprite.position = ccp(screenWidth/2, planeSprite.contentSize.height/2+5);
    [batchNode addChild:planeSprite];
}

代码③初始化了一个玩家飞机精灵,通过屏幕的宽度和高度设置相对坐标,添加到CCSpriteBatchNode当中。

103750_zbwu_262659.jpg


再次编译并运行游戏,资源加载完毕后将显示背景图片和玩家飞机。模拟器显示效果如图13.61所示。

103852_bJrc_262659.jpg


现在,玩家飞机精灵已经显示在屏幕当中了,但是这只是一个静态效果,我们可以使用动画技术,让玩家飞机精灵实现飞行动画效果,这样可以使得游戏效果更加逼真。

打开HelloWorldLayer.m文件,在私有分类中添加一个新的辅助方法,因为之后很多地方都需要获取动画帧,所以将获取动画帧的代码封装起来,从而达到代码重用的效果。示例代码如下:

-(CCAnimation*) getAnimationByName:(NSString*)animName delay:(float) delay animNum:(int) num;

该方法的作用是根据动画帧的名字和动画帧的数量,以及动画帧与帧之间的间隔时间创建一个CCAnimation动画。使用该方法要注意如下两点。

q动画帧的命名必须带序号,比如xxx1.pngxxx2.png等。

q动画帧的命名必须连续,而且必须从0开始命名。

接下来是该方法的具体实现,实现代码如下(程序清单同上)。

-(CCAnimation*)getAnimationByName:(NSString *)animName delay:(float)delay animNum: (int)num{
    NSMutableArray *animeFrames = [NSMutableArray arrayWithCapacity:num];
    for (int i=0; i< num; i++) {
        // 获取动画图片名称
        NSString *frameName = [NSString stringWithFormat:@"%@%d.png",animName,i];
        // 根据图片名称获取动画帧
        CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
            spriteFrameByName:frameName];
        [animeFrames addObject:frame];
    }
    return [CCAnimation animationWithSpriteFrames:animeFrames delay:delay];
}

回到onEnter方法中,在③添加玩家飞机精灵部分代码之后添加动画效果,实现代码如下(程序清单同上)。

// ④玩家飞机动画(尾部喷火)
CCAnimation* planeFlyAnimation = [self getAnimationByName:@"plane" delay:0.08 animNum:2];
// 重复动作
id planeFlyAction = [CCRepeatForever actionWithAction:
    [CCAnimate actionWithAnimation:planeFlyAnimation]];
// 执行动作,达到飞机尾部喷火效果
[planeSprite runAction:planeFlyAction];

这段代码调用辅助方法getAnimationByName: delay: animNum:创建了玩家飞机飞行动画,然后使用CCRepeatForeverCCAnimation创建了一个重复飞行动作,最后调用planeSpriterunAction方法播放动画效果。再次编译并运行游戏,屏幕上玩家飞机的尾部会产生不断的喷火效果,给玩家的感觉就是飞机在不断地向前飞行。

5玩家飞机Touch实现

现在,我们要完成控制玩家飞机的移动了。找到onEnter方法,在④玩家飞机动画部分代码后添加touch事件,实现代码如下(程序清单同上)。

// ⑤这是一种新的方式来激活层的touch事件
[[[CCDirector sharedDirector] touchDispatcher]
    addTargetedDelegate:self priority:0 swallowsTouches:YES];

这是一种新的方式来激活层的touch事件,老的方式是设置层的isTouchEnabled属性为“YES”。cocos2dCCLayer默认是采用addTargetedDelegate: priority: swallowsTouches:这种方式进行touch事件处理的。每次touch事件发生时,先调用ccTouchBegan: withEvent:方法,该方法对每个UITouch进行响应并返回一个BOOL值,若为“YES”,则表明用户触摸事件已经被处理,后续的ccTouchMoved: withEvent:ccTouchEnabled: withEvent:ccTouchCancelled: withEvent:会接着响应,其他事件则不会再去进行监听。ccTouchBegan: withEvent:方法返回的值如果为假,则会继续交给其他注册过的类型进行处理。

接下来是ccTouchBegan: withEvent:方法和 ccTouchMoved: withEvent:方法的处理,实现代码如下(程序清单同上)。

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
    return YES;
}
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
    // 把touch坐标转换成局部node坐标
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    // 把旧坐标也转换成局部node坐标
    CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
    oldTouchLocation = [[CCDirector sharedDirector] convertToGL:oldTouchLocation];
    oldTouchLocation = [self convertToNodeSpace:oldTouchLocation];
    // ccpSub计算两点的差异,即计算touch偏移量,把当前的点坐标减去上一个点坐标
    CGPoint translation = ccpSub(touchLocation, oldTouchLocation);
    // ccpAdd让两个坐标相加
    CGPoint newPos = ccpAdd(planeSprite.position, translation);
    // 给玩家飞机精灵设置新的坐标位置
    planeSprite.position = newPos;
}

再次编译并运行游戏,在模拟器中使用鼠标选择玩家飞机,然后移动鼠标,玩家飞机会随着鼠标轨迹移动。模拟器显示效果如图13.62所示。

104217_6n8v_262659.jpg


6背景滚动效果

现在,玩家飞机已经开始飞行,但是背景图片一直都没有变化,我们将为游戏添加连续滚动的背景,制作出更加逼真的飞行效果。步骤如下。

打开HelloWorldLayer.m文件,添加一个变量:

CCParallaxNode* backgroundNode;

我们定义了一个CCParallaxNode(视差视图)变量,用来完成背景滚动效果。当移动时,会看到离我们越近的物体移动得越快,越远的物体,比如远处的山会移动得很慢,而最远处的物体,比如太阳几乎不动,这种现象叫视差,而在游戏中模仿视差,可以让玩家感觉到游戏中的角色的确是在移动。CCParallaxNode可以很容易地建立一个视差层,你可以控制每一层的视差率、位置和层级的高低;而CCFollow可以让你的层镜头跟随目标,所以,这里我们会使用CCParallaxNodeCCFollow给游戏添加连续滚动的背景效果。

找到init方法,注释掉之前②添加背景图片的代码;再找到onEnter方法,添加两个背景图片用于拼接,实现代码如下(程序清单同上)。

// ②添加连续滚动的背景
//初始化CCParallaxNode添加到当前层中
backgroundNode = [CCParallaxNode node];
[self addChild:backgroundNode z:-1];
// ratio指在CCParallaxNode移动时,添加进去的背景图片精灵的移动速度和CCParallaxNode的比率
CGPoint ratio = ccp(1.0,1.0);
// 屏幕高度480是iPhone Retina(3.5-inch),568是iPhone Retina(4-inch)
NSString *bgName;
if (screenHeight == 480) {
    bgName = @"bg1.png"; // 640*960
}else{
    bgName = @"bg2.png"; // 640*1136
}
// 第1张背景图
CCSprite *bgSprite1 = [CCSprite spriteWithFile:bgName];
// setAliasTexParameters用于解决拼接的地图在连接滚动时容易形成黑色缝隙的问题
[[bgSprite1 texture] setAliasTexParameters];
bgSprite1.anchorPoint = ccp(0,0);
[backgroundNode addChild:bgSprite1 z:1 parallaxRatio:ratio positionOffset:ccp(0,0)];
// 第2张背景图
CCSprite *bgSprite2 = [CCSprite spriteWithFile:bgName];
[[bgSprite2 texture] setAliasTexParameters];
bgSprite2.anchorPoint = ccp(0,0);
// positionOffset时在第2张背景图与第1个背景图拼接处减去1个像素,可以消除地图拼接的缝隙
[backgroundNode addChild:bgSprite2 z:1 parallaxRatio:ratio positionOffset:ccp(0, winSize.height - 1)];
// 添加开始连续滚动背景的代码
const int MAX_WIDTH = 320;
const int MAX_HEIGHT = 480 * 100;
CCSprite *hiddenPlaneSprite = [CCSprite spriteWithSpriteFrameName:@"plane0.png"];
hiddenPlaneSprite.visible = NO;
hiddenPlaneSprite.position = ccp(winSize.width / 2, winSize.height / 2);
[batchNode addChild:hiddenPlaneSprite z:-4 tag:1024];
id move = [CCMoveBy actionWithDuration:300.0f position:ccp(0,MAX_HEIGHT)];
[hiddenPlaneSprite runAction:move];
// 让背景开始滚动,背景跟随隐形飞机移动
[backgroundNode runAction:[CCFollow actionWithTarget:hiddenPlaneSprite
    worldBoundary:CGRectMake(0, 0, MAX_WIDTH, MAX_HEIGHT)]];

上面代码首先初始化了一个CCParallaxNode,并把它添加到当前层中。初始化两个背景图片精灵,设置锚点为(0,0),并把两个背景图片精灵都添加到CCParallaxNode当中。CCParallaxNoderatio属性表示在CCParallaxNode移动时,添加进去的背景图片精灵的移动速度和CCParallaxNode的比率。假设CCParallaxNode是以每秒10像素移动的,如果设置的ratio(1,1),那么bgSprite1bgSprite2X轴方向的速度也是每秒10像素,Y轴方向的速度也是每秒10像素。如果需要飞行速度加快,则可以将ratio设置为(1,2),读者可以自行设置来测试背景图片移动的速度。在两个背景图片精灵上面都调用了setAliasTexParameters方法,用于解决拼接的地图在连接滚动时容易形成黑色缝隙的问题。同时,在设置positionOffset时,在第2张背景图与第1张背景图拼接处减去1个像素,可以消除地图拼接的缝隙。

接下来是添加连续滚动背景的代码。这里创建了一个隐形的飞机精灵,因为想要实现背景的连续滚动,需要背景能够跟随一个不断向上前进的CCNode才会产生连续向下滚动的效果。让隐形的飞机精灵执行一个moveBy动作,在一定的时间范围内运行一定的距离,而backgroundNode则执行一个CCFollow跟随动作,跟随隐形飞机移动,从而达到背景滚动的效果。

这里还需要一个算法来计算backgroundNode的坐标位置。读者可以在配套光盘的Resource目录下找到两个预先制作好的CCParallaxNode的扩展类:CCParallaxNode-Extras.hCCParallaxNode-Extras.m,将这两个文件添加到项目的“AirfightGame”组中。

104552_ULNe_262659.jpg


打开HelloWorldLayer.m文件,在私有分类中添加一个更新背景图片滚动的方法,示例代码如下:

-(void) updateBackground:(ccTime)delay;

下面是该方法的具体实现,实现代码如下(程序清单同上)。

-(void) updateBackground:(ccTime)delay{
    CCSprite *sprite;
    int index = 0;
    CCARRAY_FOREACH([backgroundNode children],sprite){
    CGPoint pt = [backgroundNode convertToWorldSpace:sprite.position];
        if (pt.y <= -sprite.contentSize.height) {
            // sprite.contentSize.height表示精灵的高度,即背景图片的高度
            [backgroundNode incrementOffset:ccp(0, (sprite.contentSize.height - 1) *
2.0f) forChild:sprite];
        }
        index++;
    }
}

updateBackground的作用是循环遍历backgroundNode中的背景图片精灵,即时修改背景图片精灵的坐标位置。

找到onEnter方法,在最后添加游戏的主循环代码,实现代码如下。

// ⑥游戏主循环,每帧都调用的更新方法
// 这样以默认cocos2d的刷新频率1/60.0s调用(void)update:(ccTime)delta一次
 [self scheduleUpdate];

这个方法是游戏的主循环。任何游戏都包括一个游戏主循环,用来更新游戏的状态、玩家和敌人的数量、碰撞处理的逻辑等。

定义一个update方法,调用更新背景图片滚动的方法,实现代码如下(程序清单同上)。

-(void) update:(ccTime)delta{
    [self updateBackground:delta];
}

再次编译并运行游戏,可以看到一个连续滚动的游戏背景效果。

 ————本文节选自《疯狂ios讲义(下)》   100627_lvjp_262659.jpg


2014-04-25 09:01:04 weixin_34194702 阅读数 8

13.14.10添加游戏积分统计

现在,我们来给玩家加入游戏积分统计功能。步骤如下。

打开HelloWorldLayer.m文件,添加变量,实现代码如下(程序清单同上)。

// 分数值标签

CCLabelTTF* scoreLabel;

// 分数

int scoreValue;

找到onEnter方法,在初始化子弹和敌机数组之后初始化分数值标签和分数,实现代码如下。

// 初始化分数标签

scoreLabel = [CCLabelTTF labelWithString:@"00" fontName:@"Arial" fontSize:20];

scoreLabel.position = ccp(60, screenHeight-20);

[self addChild:scoreLabel];

// 初始化分数值

scoreValue = 0;

修改检查碰撞方法collisionDetection:,当敌机生命值小于0时,增加计分算法,小飞机每个计分100,小飞碟每个计分500,实现代码如下(程序清单同上)。

if (enemyPlaneSprite.lifeValue <= 0) {

// 删除敌机精灵

[enemyPlaneArray removeObject:enemyPlaneSprite];

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

// 播放爆炸动画

[self bombAnimate:@"blast" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

if ([enemyPlaneSprite.name isEqualToString:@"e1"])

scoreValue += 500;

else

scoreValue += 100;

}

在私有分类中添加一个根据分数值实时更新相应的Label的方法,实现代码如下(程序清单同上)。

-(void) updateHUD:(ccTime)delta;

updateHUD:方法实时更新生命值和分数值,地图、分数、血条、时间进度条和技能条等都是HUDHead-UpDisplay)。实现代码如下(程序清单同上)。

-(void) updateHUD:(ccTime)delta{

[scoreLabel setString:[NSString stringWithFormat:@"%i",scoreValue]];

}

修改update方法,实现代码如下(程序清单同上)。

-(void) update:(ccTime)delta{

count++;

[self updateBackground:delta];

[self updateEnemySprite:delta];

[self removeEnemySprite:delta];

[self updateShooting:delta];

[self removeBulletSprite:delta];

self collisionDetection:delta];

[self updateHUD:delta];

}

再次编译并运行游戏,控制玩家飞机发射子弹,子弹击中敌机,左上角的分数标签不断统计玩家得分。模拟器显示效果如图13.65所示。

085422_zpfY_262659.jpg

13.65统计积分效果

13.14.11添加游戏大Boss

到现在为止,一个基本的打飞机游戏已经快完成了,让我们再给它添加一个大Boss,增加一点游戏的趣味性和难度吧!增加大Boss的具体步骤如下。

打开HelloWorldLayer.m文件,添加变量,实现代码如下(程序清单同上)。

FKSprite* bossSprite;

// Boss子弹精灵数组

CCArray* bossBulletArray;

// 是否启动BossBoss是否发射子弹

BOOL isStartBoss,isMoveBoss,isShootingBoss,isTemp;

在私有分类中添加3个方法,实现代码如下(程序清单同上)。

// Boss出动

-(void) startBossSprite:(ccTime)delta;

// Boss在屏幕上不规则移动

-(void) moveBossSprite:(ccTime)delta;

// Boss更新子弹

-(void) updateBossShooting:(ccTime)delta;

startBossSprite:方法用于启动Boss。实现代码如下(程序清单同上)。

-(void) startBossSprite:(ccTime)delta{

if(isStartBoss && !isMoveBoss && !isTemp ){

isTemp = YES;

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag: kTagBatchNode];

FKSprite* enemyPlaneSprite;

// 删除所有敌机

CCARRAY_FOREACH(enemyPlaneArray, enemyPlaneSprite){

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

}

[enemyPlaneArray removeAllObjects];

// Boss出动

bossSprite= [FKSprite spriteWithSpriteFrameName:@"e-10.png"];

bossSprite.position=ccp(screenWidth/2, screenHeight+bossSprite.contentSize.height);

bossSprite.name = @"boss";

bossSprite.lifeValue = 600;

// 创建一个进度条精灵

CCSprite* barSprite = [CCSprite spriteWithFile:@"planeHP.png"];

// 初始化一个Boss血条对象

bossSprite.enemyPlaneHP = [CCProgressTimer progressWithSprite:barSprite];

// setPercentage:0.0f,表示并未加载任何资源,表现在画面上就是什么也看不见

[bossSprite.enemyPlaneHP setPercentage:0.0f];

// 由于图片大小关系,把scale设置成0.5,即缩小一半

bossSprite.enemyPlaneHP.scale = 0.25;

bossSprite.enemyPlaneHP.midpoint = ccp(0,0.5);

bossSprite.enemyPlaneHP.barChangeRate = ccp(1, 0);

bossSprite.enemyPlaneHP.type = kCCProgressTimerTypeBar;

bossSprite.enemyPlaneHP.percentage = 100;

[bossSprite.enemyPlaneHP setPosition:ccp(screenWidth/2, screenHeight/2)];

bossSprite.enemyPlaneHP.visible = NO;

[self addChild:bossSprite.enemyPlaneHP];

// 血条更新量,100/10=10

bossSprite.HPInterval = 100.0 / (float)bossSprite.lifeValue;

// Boss精灵添加到敌机数组

[enemyPlaneArray addObject:bossSprite];

[batchNode addChild:bossSprite z:4];

// Boss移动到屏幕上方

id moveTo = [CCMoveTo actionWithDuration:2

position:ccp(screenWidth/2, screenHeight-bossSprite.contentSize.height-20)];

id action = [CCSequence actions:moveTo,[CCCallBlock actionWithBlock:^(){

isMoveBoss = YES;

}], nil] ;

[bossSprite runAction:action];

// 初始化Boss子弹数组

bossBulletArray = [[CCArray alloc] init];

}

}

startBossSprite:方法首先判断isStartBoss是否为“YES”(默认设置为“NO”,当玩家达到10000分时会将该值改为“YES”,则Boss启动),如果是,则先获取精灵表单,循环遍历敌机数组,从精灵表单中删除敌机,再从敌机数组中删除敌机(如果玩家是高手,希望玩到高难度的打飞机游戏,则可以不执行这段代码,游戏就会变成Boss和大量的小敌机轮番轰炸玩家)。接下来,创建一个Boss精灵,设置名称为“Boss”,生命值为600,为Boss创建一个血条,并计算血条比率。然后将Boss添加到敌机数组和精灵表单中。最后,执行一个moveBy动作,实际效果是Boss缓缓移动到屏幕上方,再将isMoveBoss设置为“YES”(Boss开始不规则动作)。记得初始化Boss子弹数组。

moveBossSprite:方法用于Boss启动后在屏幕上方做不规则运动。实现代码如下(程序清单同上)。

-(void) moveBossSprite:(ccTime)delta{

if(isMoveBoss && !isShootingBoss){

isShootingBoss = YES;

// 不停地在屏幕上方左右移动

id moveToLift = [CCMoveTo actionWithDuration:3

position:ccp(screenWidth-bossSprite.contentSize.width/2,

screenHeight-bossSprite.contentSize.height-20)];

id moveRight = [CCMoveTo actionWithDuration:3

position:ccp(0+bossSprite.contentSize.width/2,

screenHeight-bossSprite.contentSize.height-20)];

id delay = [CCDelayTime actionWithDuration:2];

id sequence = [CCSequence actions:delay,moveToLift,moveRight, nil];

// 注意:CCSequence中不能包含这个反复的动作。

id repeat = [CCRepeatForever actionWithAction:sequence];

[bossSprite runAction:repeat];

}

}

moveBossSprite:方法首先判断isMoveBoss是否为“YES”,如果是,则说明Boss精灵已经启动,开始做不规则运动,并且设置isShootingBoss = YES,表示Boss可以发射子弹***玩家精灵。

updateBossShooting:方法用于Boss开始发射子弹。实现代码如下(程序清单同上)。

-(void) updateBossShooting:(ccTime)delta{

if (isShootingBoss) {

// Boss精灵坐标

CGPoint pos = bossSprite.position;

// Boss血条显示坐标位置

bossSprite.enemyPlaneHP.position = ccp(pos.x, pos.y+55);

if (!bossSprite.enemyPlaneHP.visible) {

bossSprite.enemyPlaneHP.visible = YES;

}

// 获得精灵表单

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

if(count % 80 == 0)

{

// 创建代表子弹的精灵

CCSprite* bossBulletSprite = [CCSprite spriteWithSpriteFrameName:@"bullet1.png"];

// 设置子弹坐标

CGPoint bulletPos = ccp(pos.x, pos.y - bossSprite.contentSize.height/2);

bossBulletSprite.position = bulletPos;

// 子弹精灵可见

bossBulletSprite.visible = YES;

// 子弹移动时间为0.5秒,移动距离为屏幕高度-子弹的y

id moveBy=[CCMoveBy actionWithDuration:2.0f position:ccp(0,-screenHeight-bulletPos.y)];

[bossBulletSprite runAction:moveBy];

// 添加到Boss子弹数组中

[bossBulletArray addObject:bossBulletSprite];

// 将子弹精灵添加到精灵表单中

[batchNode addChild:bossBulletSprite z:4];

}

}

}

updateBossShooting:首先判断isShootingBoss是否为“YES”,如果是,则设置Boss血条的坐标位置,并显示Boss血条。当count % 80 == 0时,发射Boss子弹,同时将Boss子弹添加到Boss子弹数组和精灵表单中。

修改collisionDetection:方法,重新判断玩家得分,并在爆炸效果之后添加代码,当玩家积分达到10000时,启动Boss。实现代码如下(程序清单同上)。

if ([enemyPlaneSprite.name isEqualToString:@"boss"]) {

// 播放爆炸动画

[self bombAnimate:@"bomb" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b1.mp3"];

scoreValue += 5000;

// 游戏胜利

[self gameOver:@"游戏胜利!"];

}else{

// 播放爆炸动画

[self bombAnimate:@"blast" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

if ([enemyPlaneSprite.name isEqualToString:@"e1"])

scoreValue += 500;

else

scoreValue += 100;

}

// 10000分大Boss出动

if (scoreValue >= 10000) {

isStartBoss = YES;

break;

}

}

循环遍历完子弹数组之后,再添加遍历Boss子弹数组的代码,判断Boss子弹是否击中玩家飞机。实现代码如下(程序清单同上)。

// 判断Boss的子弹和玩家飞机的碰撞

if (isShootingBoss) {

CCSprite* bossBulletSprite;

CCARRAY_FOREACH(bossBulletArray, bossBulletSprite){

if(CGRectIntersectsRect(planeSprite.boundingBox,bossBulletSprite.boundingBox)){

[planeSprite stopAllActions];

// 删除玩家精灵

[batchNode removeChild:planeSprite cleanup:YES];

// 爆炸声音

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

// 播放爆炸动画

[self bombAnimate:@"blast" :planeSprite.position ];

[self gameOver:@"游戏结束!"];

}

}

}

修改updateEnemySprite:方法,判断是否更新敌机时增加!isStartBoss进行判断,意味着Boss出动后不再更新敌机。实现代码如下(程序清单同上)。

if (count % 30 == 0 && !isStartBoss)

if (count % 200 == 0 && !isStartBoss)

修改update方法,实现代码如下(程序清单同上)。

-(void) update:(ccTime)delta{

count++;

[self updateBackground:delta];

[self updateEnemySprite:delta];

[self removeEnemySprite:delta];

[self updateShooting:delta];

[self removeBulletSprite:delta];

self collisionDetection:delta];

[self updateHUD:delta];

[self startBossSprite:delta];

[self moveBossSprite:delta];

[self updateBossShooting:delta];

}

再次编译并运行游戏,当玩家得分达到10000分时,Boss出动。模拟器显示效果如图13.66所示。

当玩家控制飞机***大Boss时,Boss的血条会随着生命值的减少而缩短。当Boss生命值为0时,播放爆炸效果,提示游戏胜利,模拟器显示效果如图13.67所示。

085329_Am7W_262659.jpg085346_Mx1D_262659.jpg

到此为止,这个打飞机游戏基本已经开发完成,包括背景滚动、飞机飞行动画、背景音乐、音效、大量敌机***、玩家射击、Boss大招、玩家积分统计和游戏设置等功能。记得有位软件大师曾经说过,游戏没有真正意义上的完结,因为开发者总是可以不断地完善它,赋予游戏更多的新元素和新玩法。比如,我们可以让敌机俯冲时发射炮弹、敌机做不规则运动、Boss出动时伴随大量小飞机、玩家飞机增加大炸弹功能、每过一关玩家飞机增加一架等。这个游戏我们暂时就介绍到这里,本节我们的目的是学习使用cocos2d制作一个简单的游戏。游戏虽然简单,但是包括的知识点很多,希望大家好好掌握,将来制作出更加有趣和完美的游戏。


2014-04-25 09:01:04 weixin_34212189 阅读数 10

13.14.10添加游戏积分统计

现在,我们来给玩家加入游戏积分统计功能。步骤如下。

打开HelloWorldLayer.m文件,添加变量,实现代码如下(程序清单同上)。

// 分数值标签

CCLabelTTF* scoreLabel;

// 分数

int scoreValue;

找到onEnter方法,在初始化子弹和敌机数组之后初始化分数值标签和分数,实现代码如下。

// 初始化分数标签

scoreLabel = [CCLabelTTF labelWithString:@"00" fontName:@"Arial" fontSize:20];

scoreLabel.position = ccp(60, screenHeight-20);

[self addChild:scoreLabel];

// 初始化分数值

scoreValue = 0;

修改检查碰撞方法collisionDetection:,当敌机生命值小于0时,增加计分算法,小飞机每个计分100,小飞碟每个计分500,实现代码如下(程序清单同上)。

if (enemyPlaneSprite.lifeValue <= 0) {

// 删除敌机精灵

[enemyPlaneArray removeObject:enemyPlaneSprite];

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

// 播放爆炸动画

[self bombAnimate:@"blast" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

if ([enemyPlaneSprite.name isEqualToString:@"e1"])

scoreValue += 500;

else

scoreValue += 100;

}

在私有分类中添加一个根据分数值实时更新相应的Label的方法,实现代码如下(程序清单同上)。

-(void) updateHUD:(ccTime)delta;

updateHUD:方法实时更新生命值和分数值,地图、分数、血条、时间进度条和技能条等都是HUDHead-UpDisplay)。实现代码如下(程序清单同上)。

-(void) updateHUD:(ccTime)delta{

[scoreLabel setString:[NSString stringWithFormat:@"%i",scoreValue]];

}

修改update方法,实现代码如下(程序清单同上)。

-(void) update:(ccTime)delta{

count++;

[self updateBackground:delta];

[self updateEnemySprite:delta];

[self removeEnemySprite:delta];

[self updateShooting:delta];

[self removeBulletSprite:delta];

self collisionDetection:delta];

[self updateHUD:delta];

}

再次编译并运行游戏,控制玩家飞机发射子弹,子弹击中敌机,左上角的分数标签不断统计玩家得分。模拟器显示效果如图13.65所示。

085422_zpfY_262659.jpg

13.65统计积分效果

13.14.11添加游戏大Boss

到现在为止,一个基本的打飞机游戏已经快完成了,让我们再给它添加一个大Boss,增加一点游戏的趣味性和难度吧!增加大Boss的具体步骤如下。

打开HelloWorldLayer.m文件,添加变量,实现代码如下(程序清单同上)。

FKSprite* bossSprite;

// Boss子弹精灵数组

CCArray* bossBulletArray;

// 是否启动BossBoss是否发射子弹

BOOL isStartBoss,isMoveBoss,isShootingBoss,isTemp;

在私有分类中添加3个方法,实现代码如下(程序清单同上)。

// Boss出动

-(void) startBossSprite:(ccTime)delta;

// Boss在屏幕上不规则移动

-(void) moveBossSprite:(ccTime)delta;

// Boss更新子弹

-(void) updateBossShooting:(ccTime)delta;

startBossSprite:方法用于启动Boss。实现代码如下(程序清单同上)。

-(void) startBossSprite:(ccTime)delta{

if(isStartBoss && !isMoveBoss && !isTemp ){

isTemp = YES;

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag: kTagBatchNode];

FKSprite* enemyPlaneSprite;

// 删除所有敌机

CCARRAY_FOREACH(enemyPlaneArray, enemyPlaneSprite){

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

}

[enemyPlaneArray removeAllObjects];

// Boss出动

bossSprite= [FKSprite spriteWithSpriteFrameName:@"e-10.png"];

bossSprite.position=ccp(screenWidth/2, screenHeight+bossSprite.contentSize.height);

bossSprite.name = @"boss";

bossSprite.lifeValue = 600;

// 创建一个进度条精灵

CCSprite* barSprite = [CCSprite spriteWithFile:@"planeHP.png"];

// 初始化一个Boss血条对象

bossSprite.enemyPlaneHP = [CCProgressTimer progressWithSprite:barSprite];

// setPercentage:0.0f,表示并未加载任何资源,表现在画面上就是什么也看不见

[bossSprite.enemyPlaneHP setPercentage:0.0f];

// 由于图片大小关系,把scale设置成0.5,即缩小一半

bossSprite.enemyPlaneHP.scale = 0.25;

bossSprite.enemyPlaneHP.midpoint = ccp(0,0.5);

bossSprite.enemyPlaneHP.barChangeRate = ccp(1, 0);

bossSprite.enemyPlaneHP.type = kCCProgressTimerTypeBar;

bossSprite.enemyPlaneHP.percentage = 100;

[bossSprite.enemyPlaneHP setPosition:ccp(screenWidth/2, screenHeight/2)];

bossSprite.enemyPlaneHP.visible = NO;

[self addChild:bossSprite.enemyPlaneHP];

// 血条更新量,100/10=10

bossSprite.HPInterval = 100.0 / (float)bossSprite.lifeValue;

// Boss精灵添加到敌机数组

[enemyPlaneArray addObject:bossSprite];

[batchNode addChild:bossSprite z:4];

// Boss移动到屏幕上方

id moveTo = [CCMoveTo actionWithDuration:2

position:ccp(screenWidth/2, screenHeight-bossSprite.contentSize.height-20)];

id action = [CCSequence actions:moveTo,[CCCallBlock actionWithBlock:^(){

isMoveBoss = YES;

}], nil] ;

[bossSprite runAction:action];

// 初始化Boss子弹数组

bossBulletArray = [[CCArray alloc] init];

}

}

startBossSprite:方法首先判断isStartBoss是否为“YES”(默认设置为“NO”,当玩家达到10000分时会将该值改为“YES”,则Boss启动),如果是,则先获取精灵表单,循环遍历敌机数组,从精灵表单中删除敌机,再从敌机数组中删除敌机(如果玩家是高手,希望玩到高难度的打飞机游戏,则可以不执行这段代码,游戏就会变成Boss和大量的小敌机轮番轰炸玩家)。接下来,创建一个Boss精灵,设置名称为“Boss”,生命值为600,为Boss创建一个血条,并计算血条比率。然后将Boss添加到敌机数组和精灵表单中。最后,执行一个moveBy动作,实际效果是Boss缓缓移动到屏幕上方,再将isMoveBoss设置为“YES”(Boss开始不规则动作)。记得初始化Boss子弹数组。

moveBossSprite:方法用于Boss启动后在屏幕上方做不规则运动。实现代码如下(程序清单同上)。

-(void) moveBossSprite:(ccTime)delta{

if(isMoveBoss && !isShootingBoss){

isShootingBoss = YES;

// 不停地在屏幕上方左右移动

id moveToLift = [CCMoveTo actionWithDuration:3

position:ccp(screenWidth-bossSprite.contentSize.width/2,

screenHeight-bossSprite.contentSize.height-20)];

id moveRight = [CCMoveTo actionWithDuration:3

position:ccp(0+bossSprite.contentSize.width/2,

screenHeight-bossSprite.contentSize.height-20)];

id delay = [CCDelayTime actionWithDuration:2];

id sequence = [CCSequence actions:delay,moveToLift,moveRight, nil];

// 注意:CCSequence中不能包含这个反复的动作。

id repeat = [CCRepeatForever actionWithAction:sequence];

[bossSprite runAction:repeat];

}

}

moveBossSprite:方法首先判断isMoveBoss是否为“YES”,如果是,则说明Boss精灵已经启动,开始做不规则运动,并且设置isShootingBoss = YES,表示Boss可以发射子弹***玩家精灵。

updateBossShooting:方法用于Boss开始发射子弹。实现代码如下(程序清单同上)。

-(void) updateBossShooting:(ccTime)delta{

if (isShootingBoss) {

// Boss精灵坐标

CGPoint pos = bossSprite.position;

// Boss血条显示坐标位置

bossSprite.enemyPlaneHP.position = ccp(pos.x, pos.y+55);

if (!bossSprite.enemyPlaneHP.visible) {

bossSprite.enemyPlaneHP.visible = YES;

}

// 获得精灵表单

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

if(count % 80 == 0)

{

// 创建代表子弹的精灵

CCSprite* bossBulletSprite = [CCSprite spriteWithSpriteFrameName:@"bullet1.png"];

// 设置子弹坐标

CGPoint bulletPos = ccp(pos.x, pos.y - bossSprite.contentSize.height/2);

bossBulletSprite.position = bulletPos;

// 子弹精灵可见

bossBulletSprite.visible = YES;

// 子弹移动时间为0.5秒,移动距离为屏幕高度-子弹的y

id moveBy=[CCMoveBy actionWithDuration:2.0f position:ccp(0,-screenHeight-bulletPos.y)];

[bossBulletSprite runAction:moveBy];

// 添加到Boss子弹数组中

[bossBulletArray addObject:bossBulletSprite];

// 将子弹精灵添加到精灵表单中

[batchNode addChild:bossBulletSprite z:4];

}

}

}

updateBossShooting:首先判断isShootingBoss是否为“YES”,如果是,则设置Boss血条的坐标位置,并显示Boss血条。当count % 80 == 0时,发射Boss子弹,同时将Boss子弹添加到Boss子弹数组和精灵表单中。

修改collisionDetection:方法,重新判断玩家得分,并在爆炸效果之后添加代码,当玩家积分达到10000时,启动Boss。实现代码如下(程序清单同上)。

if ([enemyPlaneSprite.name isEqualToString:@"boss"]) {

// 播放爆炸动画

[self bombAnimate:@"bomb" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b1.mp3"];

scoreValue += 5000;

// 游戏胜利

[self gameOver:@"游戏胜利!"];

}else{

// 播放爆炸动画

[self bombAnimate:@"blast" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

if ([enemyPlaneSprite.name isEqualToString:@"e1"])

scoreValue += 500;

else

scoreValue += 100;

}

// 10000分大Boss出动

if (scoreValue >= 10000) {

isStartBoss = YES;

break;

}

}

循环遍历完子弹数组之后,再添加遍历Boss子弹数组的代码,判断Boss子弹是否击中玩家飞机。实现代码如下(程序清单同上)。

// 判断Boss的子弹和玩家飞机的碰撞

if (isShootingBoss) {

CCSprite* bossBulletSprite;

CCARRAY_FOREACH(bossBulletArray, bossBulletSprite){

if(CGRectIntersectsRect(planeSprite.boundingBox,bossBulletSprite.boundingBox)){

[planeSprite stopAllActions];

// 删除玩家精灵

[batchNode removeChild:planeSprite cleanup:YES];

// 爆炸声音

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

// 播放爆炸动画

[self bombAnimate:@"blast" :planeSprite.position ];

[self gameOver:@"游戏结束!"];

}

}

}

修改updateEnemySprite:方法,判断是否更新敌机时增加!isStartBoss进行判断,意味着Boss出动后不再更新敌机。实现代码如下(程序清单同上)。

if (count % 30 == 0 && !isStartBoss)

if (count % 200 == 0 && !isStartBoss)

修改update方法,实现代码如下(程序清单同上)。

-(void) update:(ccTime)delta{

count++;

[self updateBackground:delta];

[self updateEnemySprite:delta];

[self removeEnemySprite:delta];

[self updateShooting:delta];

[self removeBulletSprite:delta];

self collisionDetection:delta];

[self updateHUD:delta];

[self startBossSprite:delta];

[self moveBossSprite:delta];

[self updateBossShooting:delta];

}

再次编译并运行游戏,当玩家得分达到10000分时,Boss出动。模拟器显示效果如图13.66所示。

当玩家控制飞机***大Boss时,Boss的血条会随着生命值的减少而缩短。当Boss生命值为0时,播放爆炸效果,提示游戏胜利,模拟器显示效果如图13.67所示。

085329_Am7W_262659.jpg085346_Mx1D_262659.jpg

到此为止,这个打飞机游戏基本已经开发完成,包括背景滚动、飞机飞行动画、背景音乐、音效、大量敌机***、玩家射击、Boss大招、玩家积分统计和游戏设置等功能。记得有位软件大师曾经说过,游戏没有真正意义上的完结,因为开发者总是可以不断地完善它,赋予游戏更多的新元素和新玩法。比如,我们可以让敌机俯冲时发射炮弹、敌机做不规则运动、Boss出动时伴随大量小飞机、玩家飞机增加大炸弹功能、每过一关玩家飞机增加一架等。这个游戏我们暂时就介绍到这里,本节我们的目的是学习使用cocos2d制作一个简单的游戏。游戏虽然简单,但是包括的知识点很多,希望大家好好掌握,将来制作出更加有趣和完美的游戏。


没有更多推荐了,返回首页