上一篇文章分析了游戏的结构,并做了基本的文档工作。这一篇文章,将完成游戏菜单的创建和显示功能。 本篇文章对应的源代码下载:My_Flight_Control_2010-06-16.zip 添加游戏菜单启动XCode,新建一个基于“cocos2d Application”模版的新应用。应用名称为“My Flight Control”,后续文章里面就称我们的山寨版Flight Control为MYFC,而原版则称为FC。新建的应用除了显示cocos2d的logo和一个hello,world外,什么功能也没有,我们就在此基础上逐步实现MYFC。 游戏菜单具备几个条目,例如“开始新游戏”、“查看积分榜”、“查看帮助信息”等。除非是极其简单的游戏,否则添加一个游戏菜单是很有必要的。MYFC的菜单很简单,只有“Start Game”和“Scores”两项。 虽然菜单很简单,但我们还是将菜单分为MenuScene和MenuLayer两个对象。MenuScene包含一个菜单背景图和MenuLayer对象。MenuLayer对象则显示菜单项目,并响应玩家对菜单项目的点击。 创建MenuScene和MenuLayer对象在XCode中新建文件,并选择cocos2d模版“CCNode class”,Subclass则设定为“CCLayer”。文件名输入MenuScene。 新增的文件MenuScene.h和MenuScene.m会出现在Classes群组中: 接下来重复上述步骤,再建立一个MenuLayer对象。 显示菜单背景iPhone的分辨率是480×320,所以我们要做一个同等尺寸的png图片作为菜单背景图。做好的图片名为MenuBackground.png,拖入XCode中的Resources群组即可。 注意:拖入Resources群组时,如果MenuBackground.png原本没有存放在MYFC的目录中,则导入时需要选中“Copy items into destination group’s folder(is needed)”选项。 有了资源,我们就可以进行编码了。 打开MenuScene.h文件,将: @interface MenuScene : CCLayer 修改为: @interface MenuScene : CCScene 然后再打开MenuScene.m文件,加入下面的代码: 01. - (id) init 02. { 03. self = [super init]; 04. if (self) { 05. // 取得屏幕大小 06. CGSize winSize = [[CCDirector sharedDirector] winSize]; 07. // 将 MenuBackground.png 载入一个 CCSprite 对象实例 08. CCSprite *bg = [CCSprite spriteWithFile:@ "MenuBackground.png" ]; 09. // 设定菜单背景的显示位置 10. bg.position = ccp(winSize.width / 2, winSize.height / 2); 11. // 将菜单背景添加到场景中 12. [self addChild:bg]; 13. } 14. return self; 15. } CCDirector是cocos2d里面很重要的一个对象。这个对象充当游戏流程控制者的角色,让开发者可以根据需要切换不同的场景。由于CCDirector是一个单子模式实现,所以调用 [CCDirector sharedDirector] 可以获得CCDirector对象的唯一实例。 CCDirector除了控制流程,还有其他一些功能。此处我们用 [winSize] 消息来获得当前屏幕的大小。 接下来,使用CCSprite载入MenuBackground.png图片,并将这个Sprite添加到MenuScene的显示列表(显示列表的概念请参考本文后面部分)中。当MenuScene刷新画面时,MenuBackground.png的内容就会出现在屏幕上。 由于cocos2d载入一个图片后,会将图片的中心点做为原点。所以为了将图片显示在屏幕中央,需要设定图片的position属性。 如上图,CCSprite的中心点默认在图片的中间。所以要将某个图片显示在屏幕中央,代码就是: sprite.position = ccp(winSize.width / 2, winSize.height / 2); PS:ccp()是cocos2d定义的一个宏,是CGPointMake()的简写形式。 载入图片并调整好位置后,[self addChild:bg] 将包含背景图的CCSprite对象添加到MenuScene的显示列表中。 测试菜单背景在编写MenuLayer的代码之前,我们先用MenuScene替换掉默认的hello,world。 打开My_Flight_ControlAppDelegate.m文件,将 #import "HelloWorldScene.h"; 替换为: #import "MenuScene.h"; 再找到 applicationDidFinishLaunching 方法最后的 [[CCDirector sharedDirector] runWithScene: [HelloWorld scene]]; 替换为: [[CCDirector sharedDirector] runWithScene: [MenuScene node]]; 确认无误后,运行模拟器即可看到菜单背景图了: 显示菜单项菜单背景显示出来后,就该实现菜单项的显示了。这部分工作在MenuLayer对象中完成。这里我们使用cocos2d提供的CCMenuItem和CCMenu辅助类。这两个类可以创建一些简单的菜单,完全可以满足我们目前的需求。 打开MenuLayer.h文件,增加如下代码: 1. - ( void ) startGame: (id)sender; 2. - ( void ) scores: (id)sender; 打开MenuLayer.m文件,增加如下代码: 01. - (id) init 02. { 03. self = [super init]; 04. if (self) { 05. // 设定菜单项字体 06. [CCMenuItemFont setFontName:@ "Helvetica" ]; 07. [CCMenuItemFont setFontSize:30]; 08. 09. // 创建菜单项 10. CCMenuItem *start = [CCMenuItemFont itemFromString:@ "Start Game" 11. target:self 12. selector:@selector(startGame:)]; 13. CCMenuItem *scores = [CCMenuItemFont itemFromString:@ "Scores" 14. target:self 15. selector:@selector(scores:)]; 16. // 创建菜单 17. CCMenu *menu = [CCMenu menuWithItems:start, scores, nil]; 18. // 设定菜单项为垂直对齐 19. [menu alignItemsVertically]; 20. 21. // 添加菜单到显示列表中 22. [self addChild:menu]; 23. } 24. return self; 25. } 26. 27. - ( void ) startGame: (id)sender { 28. // 开始游戏 29. } 30. 31. - ( void ) scores: (id)sender { 32. // 显示得分记录 33. } 与添加背景一样的道理,最后需要把创建好的CCMenu对象添加到MenuLayer的显示列表中。 完成了对MenuLayer的修改,我们还要修改MenuScene对象,将MenuLayer包含的菜单项显示在背景之上。 打开MenuScene.m,在头部增加: #import "MenuLayer.h" 修改init方法,在最后增加: // 添加菜单层 [self addChild:[MenuLayer node]]; 最终MenuScene.m中init方法的代码为: 01. - (id) init 02. { 03. self = [super init]; 04. if (self) { 05. // 取得屏幕大小 06. CGSize winSize = [[CCDirector sharedDirector] winSize]; 07. // 将 MenuBackground.png 载入一个 CCSprite 对象实例 08. CCSprite *bg = [CCSprite spriteWithFile:@ "MenuBackground.png" ]; 09. // 设定菜单背景的显示位置 10. bg.position = ccp(winSize.width / 2, winSize.height / 2); 11. // 将菜单背景添加到场景中 12. [self addChild:bg]; 13. 14. // 添加菜单层 15. [self addChild:[MenuLayer node]]; 16. } 17. return self; 18. } 这时再编译运行,就可以看到菜单项了: 点击菜单项,还可以看到菜单项的放大缩小效果。 什么是显示列表?虽然cocos2d没有明确提到“显示列表”这个概念,但实际上cocos2d是使用类似的技术来决定哪些对象应该显示在屏幕上。 在cocos2d中,所有出现在屏幕上的对象以一个树型结构来组织,例如MenuScene包含背景图和MenuLayer,而MenuLayer又包含几个菜单项目。这个树型结构中每一个节点都会维护一个列表。 例如MenuScene的显示列表中包含了背景图和MenuLayer对象。那么当MenuScene显示在屏幕上时,cocos2d就会把MenuScene显示列表中包含的对象也显示出来。如果MenuScene的显示列表中没有包含MenuLayer,则显示MenuScene时就不会显示MenuLayer对象。 当cocos2d刷新屏幕时,只有在显示列表中的对象会被绘制到屏幕上。因此如果我们有些对象不需要显示,则应该从显示列表中移除。 实质上,切换场景等操作就是对显示列表的调整。例如将场景从MenuScene切换为LeveScene,实际上就是从显示列表中移除MenuScene对象,再加入LevelScene对象。 |
|