cocos2d-x 血泪史(1) 先从helloworld 切换到menu 吧
就用我的这个猥琐的这款打飞机的游戏来说吧。其实在我看来微信打飞机弱爆了,就只是3种类型的飞机在顶部随机位置出现然后随机速度往下掉撞到玩家控制的保证屏幕上只有一发子弹的射弹速度固定的飞机就会gameover被击爆就会加分然后分数传到服务器跟小伙伴们炫耀的游戏,看,弱爆了把,一句话就说完了~
我是典型的过度复杂化设计的程序猿,什么意思,就是程序越复杂越带感,功能越复杂越带感,代码越乱越带感,所以。。。 骚年们在看这套血泪史的时候要慎重啊,要保持着写代码万事从简的心态,忘掉一切杂念,不过度设计,写出四两拨千斤的代码。
好吧,那么到底有多复杂呢?
得有个游戏主界面的菜单吧,得有个关卡设计吧,得有区域地图世界地图吧,得有个几十种敌机类型各种套路的boss吧,主角飞机得有几种供选择吧,得有打怪升级出装备吧,得有技能树吧。。。 是不是感觉顿时高端大气上档次了呢~啊哈哈哈哈哈哈哈,是不是想说“卧槽这大制作啊”,好吧,那么就从第一个主界面的菜单开始吧.
首先你的代码没做什么修改的话运行出来应该是这样的:
看起来挺不错呢。
那么来看下代码把,项目里面应该有这样的文件:
AppMacros: 看刚开始的那大坨注释,提供了两种情况,这里我们选第一种,就是固定的设计分辨率来对应多个不同分辨率的资源,也就是说写代码的时候始终认为所有设备的分辨率都一样的,就照这个分辨率写就行了,资源可以准备多套。这样做对码农们来说太棒了,让美工们准备多套资源去吧哇哈哈哈哈~。
因为我们这个是竖屏打飞机的游戏,所以把里面的那些分辨率改成竖屏,像这样:
1 #ifndef __APPMACROS_H__ 2 #define __APPMACROS_H__ 3 4 #include "cocos2d.h" 5 6 /* For demonstrating using one design resolution to match different resources, 7 or one resource to match different design resolutions. 8 9 [Situation 1] Using one design resolution to match different resources. 10 Please look into Appdelegate::applicationDidFinishLaunching. 11 We check current device frame size to decide which resource need to be selected. 12 So if you want to test this situation which said in title '[Situation 1]', 13 you should change ios simulator to different device(e.g. iphone, iphone-retina3.5, iphone-retina4.0, ipad, ipad-retina), 14 or change the window size in "proj.XXX/main.cpp" by "CCEGLView::setFrameSize" if you are using win32 or linux plaform 15 and modify "proj.mac/AppController.mm" by changing the window rectangle. 16 17 [Situation 2] Using one resource to match different design resolutions. 18 The coordinates in your codes is based on your current design resolution rather than resource size. 19 Therefore, your design resolution could be very large and your resource size could be small. 20 To test this, just define the marco 'TARGET_DESIGN_RESOLUTION_SIZE' to 'DESIGN_RESOLUTION_2048X1536' 21 and open iphone simulator or create a window of 480x320 size. 22 23 [Note] Normally, developer just need to define one design resolution(e.g. 960x640) with one or more resources. 24 */ 25 26 #define DESIGN_RESOLUTION_480X320 0 27 #define DESIGN_RESOLUTION_1024X768 1 28 #define DESIGN_RESOLUTION_2048X1536 2 29 #define DESIGN_RESOLUTION_1136X640 4 // iphone5 30 #define DESGIN_RESOLUTION_1366X768 8 // 16:9 31 32 /* If you want to switch design resolution, change next line */ 33 #define TARGET_DESIGN_RESOLUTION_SIZE DESGIN_RESOLUTION_1366X768 34 35 typedef struct tagResource 36 { 37 cocos2d::CCSize size; 38 char directory[100]; 39 }Resource; 40 41 static Resource smallResource = { cocos2d::CCSizeMake(320, 480), "iphone" }; 42 static Resource mediumResource = { cocos2d::CCSizeMake(768, 1366), "iphone5" }; 43 static Resource largeResource = { cocos2d::CCSizeMake(1536, 2048), "ipadhd" }; 44 45 #if (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_480X320) 46 static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(320, 480); 47 #elif (TARGET_DESIGN_RESOLUTION_SIZE == DESGIN_RESOLUTION_1366X768) 48 static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(768, 1366); 49 #elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_2048X1536) 50 static cocos2d::CCSize designResolutionSize = cocos2d::CCSizeMake(1536, 2048); 51 #else 52 #error unknown target design resolution! 53 #endif 54 55 // The font size 24 is designed for small resolution, so we should change it to fit for current design resolution 56 #define TITLE_FONT_SIZE (cocos2d::CCEGLView::sharedOpenGLView()->getDesignResolutionSize().width / smallResource.size.width * 24) 57 58 #endif /* __APPMACROS_H__ */
由于最近土豪太多,所以打算用mediumResource 了,就用iphone5 的吧,等等,768*1366 是个啥,和笔记本分辨率一样,iphone5 是640*1136 好么,嗯。。。我想说的是。。。不要在意这些细节[猥琐]。。由于上面赋值给那个Resource 的directory 的值是iphone5 不是原来的ipad,那么找到项目所在目录,里面有个Resources 文件夹,把下面那个ipad 文件夹重命名成 iphone5 就ok 了。
AppDelegate.h/.cpp: 一个继承于cocos2d::CCApplication 的类,实现了applicationDidFinishLaunching, applicationDidEnterBackground 还有applicationWillEnterForeground 这三个在CCApplication 的父类CCApplicationProtocol 里定义的的虚方法。嗯,光看名字也知道这几个方法干啥的。。。就像windows store app 的项目里面有个叫App 的东西继承于windows.ui.xaml.application 然后里面有OnLauched, OnSuspending, OnActived 一个意思,跑题了?~....
然后applicationDidFinishLaunching 这个方法里面有一大坨代码,没错,这里就是主要的地方了,首先把director 和那个View 关联起来,然后根据AppMacros 里定义的东西设置了designResolution,然后又根据屏幕大小设置了资源目录,接着设置显示fps,最后用director 的runWithScene 方法传入个HelloWorldScene 的实例就跑起来了~
HelloWorldScene.h/.cpp: 这是个诡异的文件,因为文件名明明叫HelloWorldScene 怎么着里面也得有个叫HelloWorldScene 的class 吧,进去一看是个继承于 CCLayer 的叫HelloWorld 的类。里面有个静态方法返回个CCScene 的指针:
static cocos2d::CCScene* scene();
然后去cpp 里看下实现,是实例化了HelloWorld 这个Layer 然后把它加到(addChild) 刚刚实例化的一个CCScene,再返回这个CCScene。。。 为啥要这么做呢,为啥不创建个HelloWorldScene 继承于CCScene 呢,根据我的初步判断,写demo 的人一定是偷懒了,想着干脆弄个静态方法一次把scene layer 什么的全create 完得了于是就这样了。。。。 其实后来想想,可能还想告诉我们这样一个道理:当用到CCScene,CCLayer 什么的不一定非要被继承着用,直接拿来用往里面塞东西就行了(喂,这叫什么道理,这是道理么,怎么没感觉到什么教育意义呢)
HelloWorld 还有个virtual bool init() 方法,这个干嘛的呢?进去一看,这什么乱七八糟的,不过还好注释很全,不过其实没有注释也不难理解。。。 就是调用addChild 方法给自己加了个关闭按钮(MenuItem),还有一个叫Hello World 的Label,然后一张背景图,没什么特别:
1 bool HelloWorld::init() 2 { 3 ////////////////////////////// 4 // 1. super init first 5 if ( !CCLayer::init() ) 6 { 7 return false; 8 } 9 10 CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); 11 CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); 12 13 ///////////////////////////// 14 // 2. add a menu item with "X" image, which is clicked to quit the program 15 // you may modify it. 16 17 // add a "close" icon to exit the progress. it's an autorelease object 18 CCMenuItemImage *pCloseItem = CCMenuItemImage::create( 19 "CloseNormal.png", 20 "CloseSelected.png", 21 this, 22 menu_selector(HelloWorld::menuCloseCallback)); 23 24 pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 , 25 origin.y + pCloseItem->getContentSize().height/2)); 26 27 // create menu, it's an autorelease object 28 CCMenu* pMenu = CCMenu::create(pCloseItem, NULL); 29 pMenu->setPosition(CCPointZero); 30 this->addChild(pMenu, 1); 31 32 ///////////////////////////// 33 // 3. add your codes below... 34 35 // add a label shows "Hello World" 36 // create and initialize a label 37 38 CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", TITLE_FONT_SIZE); 39 40 // position the label on the center of the screen 41 pLabel->setPosition(ccp(origin.x + visibleSize.width/2, 42 origin.y + visibleSize.height - pLabel->getContentSize().height)); 43 44 // add the label as a child to this layer 45 this->addChild(pLabel, 1); 46 47 // add "HelloWorld" splash screen" 48 // Change it to COCOS LOGO 49 CCSprite* pSprite = CCSprite::create("Logo.png"); 50 pSprite->setScale(2.f); 51 // position the sprite on the center of the screen 52 pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); 53 54 return true; 55 }
需要注意的是,init 方法是重写的基类方法,所以务必调用下基类的init,就像上面那样调用CCLayer::init(),也就是告诉我们如果以后继承引擎里的类并且重写方法,不想覆盖原方法记得去做个调用,当然也有例外,貌似像那些以Delegate 结尾的类的一些虚方法必须重写,不然会被引擎用assert 强制报错...
main.h/.cpp: 这个就没啥好说的了,实例化了上面的那个AppDelegate,然后设置在win32 下的FrameSize,这里就改成768*1366 吧,还有个setFrameZoomFactor 方法的调用,如果运行起来感觉窗口太高了超出屏幕分辨率(你的笔记本或者程序猿专用工作站),把参数改小点就ok 了。还有最顶端那个// uncomment below line, open debug console 把它下面那几行注释去掉,运行的时候能看到debug 控制台,看到调用CCLog 打出来的东西。
=======================================好了,接下来就是见证奇级的时刻========================
==========================喂,说了半天只是说原来项目template 生成的东西啊==========================
==============================说好的加Menu 什么的呢======================================
===========================================吐槽为什么会是这种格式,感觉根本停不下来啊============
一般情况下我们见到的大制作,都会刚开始给些个华丽的splash 界面,显示下xxx 工作室,xxx 游戏,xxx 显卡芯片标志,xxx 引擎什么的,然后淡入淡出再搞个华丽的CG 还死活不让你任意键继续,那么我们也来个华丽的“淡入淡出”~ 深入浅出什么的就算了。。
HERES THE PLAN: 首先显示下cocos2d-x 的logo,然后淡入淡出到我们的主menu。
so easy,从cocos2d官网上麻溜的弄下来张logo,然后放到Resources/iphone5 那个文件夹(为什么这里用/ 而不用\,因为只有windows 用\,日语操作系统还用¥呢!!丧心病狂!!所以为了避免移植到其他平台出问题,而且win32 下也是能认得/ 的,所以以后子目录都用/ 了)
接下来把HelloWorldScene.cpp 里面添加关闭按钮那段注释掉,helloworld 的label 那段也注释掉,再把添加Sprite 的那个里面的HelloWorld.png 换成我们的Logo.png,好了~ 编译运行:
哈哈,看起来很屌的样子,接下来就是淡入淡出什么的了,留着下篇再说吧,lulu 睡了~