如何制作一个简单的游戏 Cocos2d-x 2.1.2
2013-06-28 13:56
561 查看
本文实践自 Ray Wenderlich 的文章《How
To Make A Simple iPhone Game with Cocos2D 2.X Tutorial》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.2进行学习和移植,前者是用Object-C所写,所以移植到Cocos2D-x会有些差异,比如某些函数、某些功能不能跟原文一样直接实现,需另转换方法实现。之前已经对Cocos2D-x的安装以及简单使用进行了介绍,这里不再介绍,直接进入主题。
步骤如下:
1.新建Cocos2d-win32工程,工程名为"SimpleGame",去除"Box2D"选项,勾选"Simple
Audio Engine in Cocos Denshion"选项;
2.编译运行,可以看到如下图所示:
3.下载本游戏所需的资源,将资源放置"Resources"目录下;
4.游戏需要一个白色的背景,最简单的方法是使用CCLayerColor,将HelloWorldScene.h文件"HelloWorld"类改为如下:
之后添加如下代码:
5.编译运行,可以看到玩家精灵在白色背景上,如下图所示:
6.接下来添加怪物,并且让怪物可以移动,我们在屏幕右边创建怪物,建立动作让它们向左移动,增加addMonster方法,代码如下:
在右边屏幕以随机的位置添加怪物精灵,注意计算精灵的位置坐标,默认描点在中心,不要让怪物截断了。然后再以2~4秒的随机总时间,让怪物从右边移动到左边,移动出边界后,即回调函数spriteMoveFinished,进行删除精灵对象,增加的spriteMoveFinished方法如下:
增加gameLogic方法,代码如下:
7.编译运行,可以看到右边怪物定时增加,并且以不同的速度向左边移动,如下图所示:
8.接着让玩家可以射击子弹,当用户在屏幕点击时,就让玩家往点击的方向进行发送子弹,用户的屏幕点击点并不是子弹移动的最终地,借用原文的一张图片来说明:
要让层可以支持触摸,需要在init方法,添加如下代码:
然后重载ccTouchesEnded方法,代码如下:
在HelloWorldScene.h添加如下函数:这个函数是系统回调函数方法名从.cpp文件中复制过来
9.编译运行,往屏幕点击,可以看到子弹发射出去,如下图所示:
10.当子弹碰到怪物时,怪物被消灭,子弹消失,即碰撞检测。需要在场景中跟踪目标和子弹,在HelloWorldScene.h声明如下:
在构造函数和析构函数,添加如下:
修改ccTouchesEnded函数,为子弹精灵添加标签,并加入到数组,代码如下:
然后修改spriteMoveFinished函数,增加如下代码:
添加如下方法:
遍历子弹数组,计算每一个子弹所可能遇到的怪物,用它们各自的边界框进行交叉检测,检测到交叉,则将怪物对象放入ToDelete(待删除)数组,不能在遍历的时候删除一个对象。若是子弹遇到了怪物,也需要放入ToDelete(待删除)数组。然后从场景和数组中移动掉。同样,也在init函数,安装定时器,代码如下:
11.编译运行,这时当子弹和怪物碰撞时,它们就会消失;
12.添加音效,在init函数添加背景音乐,代码如下:
在ccTouchesEnded函数,添加子弹音效,代码如下:
13.接下来,创建一个新的场景,来指示"You Win"或者"You Lose"。右键 工程,"Add"→"Class..."→"C++"→"Add","Base class"为CCLayerColor,"Class name"为GameOverLayer,如下图所示:
GameOverLayer.h文件代码为:
14.最后,为游戏添加一些游戏逻辑。记录玩家消灭怪物的数量,进而决定该玩家输赢。在HelloWorldScene.h文件中,添加如下:
在HelloWorldScene.cpp文件,HelloWorld()构造函数,添加如下代码:
添加头文件引用:
在update定时函数中,monstersToDelete循环removeChild(monster,
true)的后面添加被消灭怪物的计数,并判断胜利条件,代码如下:
== 1条件的后面,添加如下:
14.编译并运行,到此已完成了一个简单的游戏,包含音效,并带有胜利和失败的结束。游戏效果如下:
参考资料:
1.How To Make A Simple iPhone Game with Cocos2D 2.X Tutorial http://www.raywenderlich.com/25736/how-to-make-a-simple-iphone-game-with-cocos2d-2-x-tutorial
2.如何用Cocos2d来开发简单的IPhone游戏教程 http://www.cocoachina.com/bbs/read.php?tid-15554.html
3.Cocos2d Classic Tutorial Demo Revisit:(1) http://www.zilongshanren.com/cocos2d-classic-tutorial-demo-revisit-1/
非常感谢以上资料,本例子源代码附加资源下载地址:http://download.csdn.net/detail/akof1314/4857315
iOS版下载地址:http://vdisk.weibo.com/s/EE-jW
ios新版加注释下载地址: http://vdisk.weibo.com/s/BDn59yfnBUSz_
如文章存在错误之处,欢迎指出,以便改正。
To Make A Simple iPhone Game with Cocos2D 2.X Tutorial》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.2进行学习和移植,前者是用Object-C所写,所以移植到Cocos2D-x会有些差异,比如某些函数、某些功能不能跟原文一样直接实现,需另转换方法实现。之前已经对Cocos2D-x的安装以及简单使用进行了介绍,这里不再介绍,直接进入主题。
步骤如下:
1.新建Cocos2d-win32工程,工程名为"SimpleGame",去除"Box2D"选项,勾选"Simple
Audio Engine in Cocos Denshion"选项;
2.编译运行,可以看到如下图所示:
3.下载本游戏所需的资源,将资源放置"Resources"目录下;
4.游戏需要一个白色的背景,最简单的方法是使用CCLayerColor,将HelloWorldScene.h文件"HelloWorld"类改为如下:
1 | class HelloWorld : public cocos2d::CCLayerColor |
//主人公 cocos2d::CCSprite * _player; //敌人 cocos2d::CCSprite * _monster; //添加敌人的方法 void addMonster(); //移除精灵的函数 void spriteMoveFinished(CCNode *sender); //调用添加敌人的函数 void gameLogic( float dt );首先添加玩家,让玩家位于左边屏幕中间,将HelloWorldScene.cpp文件的init函数,改为如下:
bool HelloWorld::init() { bool bRet = false; do { //将背景设置为白色 CC_BREAK_IF(! CCLayerColor::initWithColor(ccc4(255, 255, 255, 255))); //获取屏幕的大小 CCSize winSize = CCDirector::sharedDirector()->getWinSize(); //初始化一个精灵作为主人公 _player = CCSprite::create("player.png"); //设置精灵的位置 _player->setPosition(ccp(_player->getContentSize().width / 2, winSize.height / 2)); //将精灵添加到当前层上 this->addChild(_player); //添加定时器每秒执行一次 this->schedule(schedule_selector(HelloWorld::gameLogic), 1.0); bRet = true; } while (0); return bRet; }
5.编译运行,可以看到玩家精灵在白色背景上,如下图所示:
6.接下来添加怪物,并且让怪物可以移动,我们在屏幕右边创建怪物,建立动作让它们向左移动,增加addMonster方法,代码如下:
void HelloWorld::addMonster() { //初始化敌人 _monster = CCSprite::create("monster.png"); //屏幕的尺寸 CCSize winSize = CCDirector::sharedDirector()->getWinSize(); //敌人出现的Y坐标的最小值 int minY = _monster->getContentSize().height / 2; //敌人出现的Y坐标的最大值 ,其中getContentSize()精灵图片的尺寸 int maxY = winSize.height - _monster->getContentSize().height / 2; //敌人出现的Y坐标的范围 int rangeY = maxY - minY; //计算随机值 int actualY = (rand() % rangeY) + minY; //设置敌人的坐标 _monster->setPosition(ccp(winSize.width + _monster->getContentSize().width / 2, actualY)); //将敌人添加到游戏层上 this->addChild(_monster); int minDuration = 2.0; int maxDuration = 4.0; int rangeDuration = maxDuration - minDuration; //计算一个随机数 int actualDuration = (rand() % rangeDuration) + minDuration; // 动作 第一个参数用多长时间执行完这个动作,第二个参数到达的位置 CCMoveTo *actionMove = CCMoveTo::create(actualDuration, ccp(-_monster->getContentSize().width / 2, actualY)); //动作执行完的回调方法, 哪个对象调用就将谁作为参数传过去 CCCallFuncN *actionMoveDone = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::spriteMoveFinished)); //执行动作 _monster->runAction(CCSequence::create(actionMove, actionMoveDone, NULL)); }
在右边屏幕以随机的位置添加怪物精灵,注意计算精灵的位置坐标,默认描点在中心,不要让怪物截断了。然后再以2~4秒的随机总时间,让怪物从右边移动到左边,移动出边界后,即回调函数spriteMoveFinished,进行删除精灵对象,增加的spriteMoveFinished方法如下:
void HelloWorld::spriteMoveFinished(CCNode *sender) { //获取精灵 CCSprite *sprite = (CCSprite*)sender; //将精灵移除 this->removeChild(sprite, true); }接下去就是定时创建怪物,在init函数返回之前,安装定时器,每秒执行一次,代码如下:
1 | this->schedule(schedule_selector(HelloWorld::gameLogic),1.0); |
void HelloWorld::gameLogic( float dt ) { //添加怪物 this->addMonster(); }
7.编译运行,可以看到右边怪物定时增加,并且以不同的速度向左边移动,如下图所示:
8.接着让玩家可以射击子弹,当用户在屏幕点击时,就让玩家往点击的方向进行发送子弹,用户的屏幕点击点并不是子弹移动的最终地,借用原文的一张图片来说明:
要让层可以支持触摸,需要在init方法,添加如下代码:
1 | this->setTouchEnabled(true); |
void HelloWorld::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) { //获取触摸的点 CCTouch *touch = (CCTouch*)pTouches->anyObject(); //获取触摸点的坐标 CCPoint location = this->convertTouchToNodeSpace(touch); //获取当前屏幕的大小 CCSize winSize = CCDirector::sharedDirector()->getWinSize(); //初始化子弹精灵 CCSprite *projectile = CCSprite::create("Projectile.png"); //子弹发射时的位置设置位置 projectile->setPosition(ccp(20, winSize.height / 2)); //得到的值是上图小Y和小X的值 CCPoint offset = ccpSub(location, projectile->getPosition()); if (offset.x <= 0) { return; } this->addChild(projectile); //得到长的X的值 int realX = winSize.width + projectile->getContentSize().width / 2; //计算出比率 float ratio = (float)offset.y / (float)offset.x; //得到实际Y的值 后面加的是子弹Y轴的坐标 只有加上子弹Y轴的坐标才是实际的Y int realY = realX * ratio + projectile->getPosition().y; CCPoint realDest = ccp(realX, realY); int offRealX = realX - projectile->getPosition().x; int offRealY = realY - projectile->getPosition().y; float length = sqrtf(offRealX * offRealX + offRealY * offRealY); float velocity = 480 / 1; float realMoveDuration = length / velocity; projectile->runAction(CCSequence::create(CCMoveTo::create(realMoveDuration, realDest),CCCallFuncN::create(this, callfuncN_selector(HelloWorld::spriteMoveFinished)), NULL)); }
在HelloWorldScene.h添加如下函数:这个函数是系统回调函数方法名从.cpp文件中复制过来
void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);首先,得到触摸点,然后创建子弹精灵,算出触摸点与子弹初始位置之差,若触摸点在初始位置的前方(即玩家前方),则添加子弹到层上。以同比例方法,计算出子弹飞向屏幕右边的最终坐标。然后再用勾股定理计算飞行长度,假定速度为每秒480像素,则计算出飞行总时间。之后就是让子弹执行给定的飞行动作,以及之后的删除自身调用。
9.编译运行,往屏幕点击,可以看到子弹发射出去,如下图所示:
10.当子弹碰到怪物时,怪物被消灭,子弹消失,即碰撞检测。需要在场景中跟踪目标和子弹,在HelloWorldScene.h声明如下:
//构造函数 HelloWorld(); //存放敌人的数组 cocos2d::CCArray *_monsters; //存放子弹的数组 cocos2d::CCArray *_projectiles; //每帧刷新的方法 void update(float delta);
在构造函数和析构函数,添加如下:
HelloWorld::HelloWorld() { //在构造函数中将指针置空,防止野指针,如果不置空调用,再没有初始化就调用就是野指针了 _monsters = NULL; _projectiles = NULL; }然后在init函数中初始化这两个数组:
//初始化存放敌人的数组 this->_monsters = CCArray::create(); //因为要再其他函数中使用,因此要retain一下 this->_monsters->retain(); //初始化存放子弹的数组 this->_projectiles = CCArray::create(); //因为要再其他函数中使用,因此要retain一下 this->_projectiles->retain(); //开启每帧更新的方法 this->scheduleUpdate();修改addMonster函数,为怪物精灵添加标签,并加入到数组,代码如下:
//设置敌人的tag值,tag就相当于一个记号 _monster->setTag(1); //添加到数组中,以便以后碰撞检测时使用 _monsters->addObject(_monster);
修改ccTouchesEnded函数,为子弹精灵添加标签,并加入到数组,代码如下:
//设置tag值,就相当于一个记号 projectile->setTag(2); //添加到子弹数组中,以便以后碰撞检测时使用 _projectiles->addObject(projectile);
然后修改spriteMoveFinished函数,增加如下代码:
//判断 if (sprite->getTag() == 1) { //从数组中移除 _monsters->removeObject(sprite); } else if (sprite->getTag() == 2) { //从数组中移除 _projectiles->removeObject(sprite); }
添加如下方法:
void HelloWorld::update(float delta) { //创建一个要删除子弹的数组 CCArray *projectilesToDelete = CCArray::create(); //创建2个临时的CCObject对象,用来接收遍历出来的对象 CCObject *pObject = NULL; CCObject *pObject2 = NULL; //遍历子弹数组 CCARRAY_FOREACH(_projectiles, pObject) { //得到子弹对象 CCSprite *projectile = (CCSprite*)pObject; //创建一个要删除敌人的数组 CCArray *monstersToDelete = CCArray::create(); //遍历敌人数组 CCARRAY_FOREACH(_monsters, pObject2) { //得到敌人对象 CCSprite *monster = (CCSprite*)pObject2; //碰撞检测,projectile->boundingBox()代表子弹碰撞盒子,intersectsRect判断是否相交的方法,monster->boundingBox()敌人的碰撞 if (projectile->boundingBox().intersectsRect(monster->boundingBox())) { //如果上述判断为真,说明子弹和敌人发生了碰撞,将敌人加入要删除敌人的数组 monstersToDelete->addObject(monster); //将子弹加入要删除敌人的数组 projectilesToDelete->addObject(projectile); } } //遍历要删除敌人的数组 CCARRAY_FOREACH(monstersToDelete, pObject2) { //得到敌人对象 CCSprite *monster = (CCSprite*)pObject2; //从数组中移除 _monsters->removeObject(monster); //从游戏层上移除 this->removeChild(monster, true); } //将要删除敌人的数组释放掉 monstersToDelete->release(); } //遍历要删除子弹的数组 CCARRAY_FOREACH(projectilesToDelete, pObject) { //得到子弹对象 CCSprite *projectile = (CCSprite*)pObject; //从数组中移除 _projectiles->removeObject(projectile); //从游戏层上移除 this->removeChild(projectile, true); } //将要删除子弹的数组释放掉 projectilesToDelete->release(); }
遍历子弹数组,计算每一个子弹所可能遇到的怪物,用它们各自的边界框进行交叉检测,检测到交叉,则将怪物对象放入ToDelete(待删除)数组,不能在遍历的时候删除一个对象。若是子弹遇到了怪物,也需要放入ToDelete(待删除)数组。然后从场景和数组中移动掉。同样,也在init函数,安装定时器,代码如下:
//开启每帧更新的方法 this->scheduleUpdate();
11.编译运行,这时当子弹和怪物碰撞时,它们就会消失;
12.添加音效,在init函数添加背景音乐,代码如下:
1 | CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background-music-aac.wav"); |
1 | CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("pew-pew-lei.wav"); |
GameOverLayer.h文件代码为:
class GameOverLayer : public cocos2d::CCLayerColor { public: //构造函数 GameOverLayer(void); ~GameOverLayer(void); //初始化游戏层 bool initWithWon(bool won); //创建场景 static cocos2d::CCScene* sceneWithWon(bool won); //创建游戏层 static GameOverLayer* createWithWon(bool won); //判断游戏结束的方法 void gameOverDone(); };GameOverLayer.cpp文件代码为:
#include"HelloWorldScene.h" using namespace cocos2d; GameOverLayer::GameOverLayer(void) { } GameOverLayer::~GameOverLayer(void) { } GameOverLayer* GameOverLayer::createWithWon(bool won) { GameOverLayer *pRet = new GameOverLayer(); if (pRet && pRet->initWithWon(won)) { pRet->autorelease(); return pRet; } else { CC_SAFE_DELETE(pRet); return NULL; } } bool GameOverLayer::initWithWon(bool won) { bool bRet = false; do { CC_BREAK_IF(! CCLayerColor::initWithColor(ccc4(255,255,255, 255))); char *message; //根据传过来的条件 won值判断 if (won) { message = "You Won!"; } else { message = "You Lose :["; } CCSize winSize = CCDirector::sharedDirector()->getWinSize(); CCLabelTTF *label = CCLabelTTF::create(message, "Arial", 32); label->setColor(ccc3(0, 0, 0)); label->setPosition(ccp(winSize.width / 2, winSize.height /2)); this->addChild(label); //停留3秒钟,执行gameOverDone函数 this->runAction(CCSequence::create(CCDelayTime::create(3), CCCallFunc::create(this, callfunc_selector(GameOverLayer::gameOverDone)), NULL)); bRet = true; } while (0); return bRet; } cocos2d::CCScene* GameOverLayer::sceneWithWon(bool won) { CCScene * scene = NULL; do { scene = CCScene::create(); CC_BREAK_IF(! scene); GameOverLayer *layer = GameOverLayer::createWithWon(won); CC_BREAK_IF(! layer); scene->addChild(layer); } while (0); return scene; } void GameOverLayer::gameOverDone() { //重新加载场景 CCDirector::sharedDirector()->replaceScene(HelloWorld::scene()); }游戏结束时,切换到以上所建的场景,场景上的层显示一个文本,在3秒之后返回到HelloWorld场景中。
14.最后,为游戏添加一些游戏逻辑。记录玩家消灭怪物的数量,进而决定该玩家输赢。在HelloWorldScene.h文件中,添加如下:
1 | int _monstersDestroyed; |
1 | _monstersDestroyed = 0; |
1 | #include"GameOverLayer.h" |
true)的后面添加被消灭怪物的计数,并判断胜利条件,代码如下:
//消灭一个敌人,让_monstersDestroyed加1; _monstersDestroyed++; //胜利条件 if (_monstersDestroyed > 30) { //创建创建,并传递参数:即胜利条件true CCScene *gameOverScene = GameOverLayer::sceneWithWon(true); //场景切换 CCDirector::sharedDirector()->replaceScene(gameOverScene); }最后为玩家添加失败条件,规定只要有一只怪物跑到左边屏幕里,则玩家失败,在spriteMoveFinished函数里,sprite->getTag()
== 1条件的后面,添加如下:
1 2 | CCScene *gameOverScene = GameOverLayer::sceneWithWon(false); CCDirector::sharedDirector()->replaceScene(gameOverScene); |
参考资料:
1.How To Make A Simple iPhone Game with Cocos2D 2.X Tutorial http://www.raywenderlich.com/25736/how-to-make-a-simple-iphone-game-with-cocos2d-2-x-tutorial
2.如何用Cocos2d来开发简单的IPhone游戏教程 http://www.cocoachina.com/bbs/read.php?tid-15554.html
3.Cocos2d Classic Tutorial Demo Revisit:(1) http://www.zilongshanren.com/cocos2d-classic-tutorial-demo-revisit-1/
非常感谢以上资料,本例子源代码附加资源下载地址:http://download.csdn.net/detail/akof1314/4857315
iOS版下载地址:http://vdisk.weibo.com/s/EE-jW
ios新版加注释下载地址: http://vdisk.weibo.com/s/BDn59yfnBUSz_
如文章存在错误之处,欢迎指出,以便改正。
相关文章推荐
- 如何制作一个简单的游戏 Cocos2d-x 2.0.4
- Cocos2d-x 2.0.4 如何制作一个简单的游戏
- Cocos2d-x 2.0.4 如何制作一个简单的游戏(2)
- Cocos2d-x 2.0.4 如何制作一个简单的游戏(3)
- 如何制作一个简单的游戏 Cocos2d-x 2.0.4
- 如何制作一个简单的游戏(2) Cocos2d-x 2.0.4
- 如何制作一个简单的游戏 Cocos2d-x 2.0.4
- 如何制作一个简单的游戏(3) Cocos2d-x 2.0.4
- Cocos2d-x 2.0.4 如何制作一个简单的游戏
- Cocos2d-x 2.0.4 如何制作一个简单的游戏(2)
- 如何制作一个简单的游戏(2) Cocos2d-x 2.0.4
- Cocos2d-x 2.0.4 如何制作一个简单的游戏(3)
- 如何制作一个简单的游戏 Cocos2d-x 2.0.4
- (译)如何使用cocos2d来制作一个塔防游戏:第一部分
- 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4
- 如何使用cocos2d-x来制作一个塔防游戏:第三部分
- 如何制作一个基于Tile的游戏 Cocos2d-x 2.0.4
- (译)如何使用GameCenter制作一个简单的多人游戏教程:第一部分
- 如何制作一个横版格斗过关游戏 Cocos2d-x 2.0.4
- 如何制作一个横版格斗过关游戏(2) Cocos2d-x 2.0.4