当前位置:首页 > 资讯 > 热门博客 > 正文

如何制作一个简单的游戏 Cocos2d-x 2.0.4

发表于: 2013-06-08   作者:杜甲同学   来源:转载   浏览次数:
摘要:  本文实践自RayWenderlich的文章《HowToMakeASimpleiPhoneGamewithCocos2D2.XTutorial》,文中使用Cocos2D,我在这里使用Cocos2D-x2.0.4进行学习和移植,前者是用Object-C所写,所以移植到Cocos2D-x会有些差异,比如某些函数、某些功能不能跟原文一样直接实现,需另转换方法实现。之前已经对Cocos2D-x的安装以及简

  本文实践自 Ray Wenderlich 的文章《How To Make A Simple iPhone Game with Cocos2D 2.X Tutorial》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.0.4进行学习和移植,前者是用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

首先添加玩家,让玩家位于左边屏幕中间,将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();
            //初始化一个精灵作为主人公
            CCSprite *player = CCSprite::create("Player.png", CCRectMake(0, 0, 27, 40));
            //设置精灵的位置
            player->setPosition(ccp(player->getContentSize().width / 2, winSize.height / 2));
            //将精灵添加到当前层上
            this->addChild(player);
                            
            bRet = true;
        } while (0);
                        
        return bRet;
}

5.编译运行,可以看到玩家精灵在白色背景上,如下图所示:


6.接下来添加怪物,并且让怪物可以移动,我们在屏幕右边创建怪物,建立动作让它们向左移动,增加 addMonster方法,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

void HelloWorld::addMonster()
{
   CCSprite *monster = CCSprite::create( "Target.png");

   CCSize winSize = CCDirector::sharedDirector()->getWinSize();
int minY = monster->getContentSize().height / 2;
int maxY = winSize.height - monster->getContentSize().height / 2;
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方法如下:

1
2
3
4
5

void HelloWorld::spriteMoveFinished(CCNode *sender)
{
   CCSprite *sprite = (CCSprite*)sender;
this->removeChild(sprite, true);
}

接下去就是定时创建怪物,在init函数返回之前,安装定时器,每秒执行一次,代码如下:

1

this->schedule(schedule_selector(HelloWorld::gameLogic), 1. 0);

增加gameLogic方法,代码如下:

1
2
3
4

void HelloWorld::gameLogic( float dt )
{
this->addMonster();
}

7.编译运行,可以看到右边怪物定时增加,并且以不同的速度向左边移动,如下图所示:

8.接着让玩家可以射击子弹,当用户在屏幕点击时,就让玩家往点击的方向进行发送子弹,用户的屏幕点击点并不是子弹移动的最终地,借用原文的一张图片来说明:

要让层可以支持触摸,需要在init方法,添加如下代码:

1

this->setTouchEnabled( true);

然后重载ccTouchesEnded方法,代码如下:


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));
}

首先,得到触摸点,然后创建子弹精灵,算出触摸点与子弹初始位置之差,若触摸点在初始位置的前方(即玩家前方),则添加子弹到层上。以同比例方法,计算出子弹飞向屏幕右边的最终坐标。然后再用勾股定理计算飞行长度,假定速度为每秒480像素,则计算出飞行总时间。之后就是让子弹执行给定的飞行动作,以及之后的删除自身调用。
9.编译运行,往屏幕点击,可以看到子弹发射出去,如下图所示:

10.当子弹碰到怪物时,怪物被消灭,子弹消失,即碰撞检测。需要在场景中跟踪目标和子弹,在HelloWorldScene.h声明如下:

1
2

cocos2d::CCArray *_monsters;
cocos2d::CCArray *_projectiles;

在构造函数和析构函数,添加如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

HelloWorld::HelloWorld()
{
   _monsters = NULL;
   _projectiles = NULL;
}

HelloWorld::~HelloWorld()
{
if (_monsters)
   {
       _monsters->release();
       _monsters = NULL;
   }
if (_projectiles)
   {
       _projectiles->release();
       _projectiles = NULL;
   }
}

然后在init函数中初始化这两个数组:

1
2
3
4

this->_monsters = CCArray::create();
this->_monsters->retain();
this->_projectiles = CCArray::create();
this->_projectiles->retain();

修改addMonster函数,为怪物精灵添加标签,并加入到数组,代码如下:

1
2

monster->setTag( 1);
_monsters->addObject(monster);

修改ccTouchesEnded函数,为子弹精灵添加标签,并加入到数组,代码如下:

1
2

projectile->setTag( 2);
_projectiles->addObject(projectile);

然后修改spriteMoveFinished函数,增加如下代码:

1
2
3
4
5
6
7
8

if (sprite->getTag() == 1)
{
   _monsters->removeObject(sprite);
}
else if (sprite->getTag() == 2)
{
   _projectiles->removeObject(sprite);
}

添加如下方法:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

void HelloWorld::update( float dt)
{
   CCArray *projectilesToDelete = CCArray::create();

   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;

          if (projectile->boundingBox().intersectsRect(monster->boundingBox()))

           {
               monstersToDelete->addObject(monster);
           }          
       }

       CCARRAY_FOREACH(monstersToDelete, pObject2)
       {
           CCSprite *monster = (CCSprite*)pObject2;
           _monsters->removeObject(monster);
this->removeChild(monster, true);
       }

if (monstersToDelete->count() > 0)
       {
           projectilesToDelete->addObject(projectile);
       }

       monstersToDelete->release();
   }

   CCARRAY_FOREACH(projectilesToDelete, pObject)
   {
       CCSprite *projectile = (CCSprite*)pObject;
       _projectiles->removeObject(projectile);
this->removeChild(projectile, true);
   }

   projectilesToDelete->release();
}

遍历子弹数组,计算每一个子弹所可能遇到的怪物,用它们各自的边界框进行交叉检测,检测到交叉,则将怪物对象放入ToDelete(待删除)数组,不能在遍历的时候删除一个对象。若是子弹遇到了怪物,也需要放入ToDelete(待删除)数组。然后从场景和数组中移动掉。同样,也在init函数,安装定时器,代码如下:

1

this->schedule(schedule_selector(HelloWorld::update));

11.编译运行,这时当子弹和怪物碰撞时,它们就会消失;
12.添加音效,在init函数添加背景音乐,代码如下:

1

CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic( "background-music-aac.wav");

ccTouchesEnded函数,添加子弹音效,代码如下:

1

CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect( "pew-pew-lei.wav");

13.接下来,创建一个新的场景,来指示"You Win"或者"You Lose"。右键 工程,"Add"→"Class..."→"C++"→"Add","Base class"为CCLayerColor,"Class name"为GameOverLayer,如下图所示:

GameOverLayer.h文件代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#pragma once
#include "cocos2d.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文件代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

#include "GameOverLayer.h"
#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;
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);

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;

HelloWorldScene.cpp文件,HelloWorld()构造函数,添加如下代码:

1

_monstersDestroyed = 0;

添加头文件引用:

1

#include "GameOverLayer.h"

update定时函数中,monstersToDelete循环removeChild(monster, true)的后面添加被消灭怪物的计数,并判断胜利条件,代码如下:

1
2
3
4
5
6

_monstersDestroyed++;
if (_monstersDestroyed > 30)
{
   CCScene *gameOverScene = GameOverLayer::sceneWithWon( true);
   CCDirector::sharedDirector()->replaceScene(gameOverScene);
}

最后为玩家添加失败条件,规定只要有一只怪物跑到左边屏幕里,则玩家失败,在spriteMoveFinished函数里,sprite->getTag() == 1条件的后面,添加如下:

1
2

CCScene *gameOverScene = GameOverLayer::sceneWithWon( false);
CCDirector::sharedDirector()->replaceScene(gameOverScene);

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

如文章存在错误之处,欢迎指出,以便改正。


如何制作一个简单的游戏 Cocos2d-x 2.0.4

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
在第一篇《如何使用CCRenderTexture创建动态纹理》基础上,增加创建动态山丘,原文《How To Create
写了几章教程 准备先写几个例子和游戏玩玩 这几天博客更新比较慢 主要公司项目紧 本例子从cocos2d的
如何使用cocos2d-x制作一个山寨Angry Birds游戏:第一部分 注:本教程由Ray博客上的教程"微创新"而
  本次教程参考文章:http://www.cnblogs.com/zilongshanren/archive/2011/06/09/2074962.html  
本教程基于子龙山人翻译的cocos2d的IPHONE教程,用cocos2d-x for XNA引擎重写,加上我一些加工制作
三、添加一个精灵 我们先用个简单的方式,把player, projectile, target三个PNG文件拷贝到 D:\Work7
到本系列文章的前四篇为止,我们已经完成了一个简单的游戏,Ray Wenderlic的那篇文章也翻译完了。但
写这几篇文章主要是看了这个系列的文章: http://www.raywenderlich.com/352/how-to-make-a-simple-
游戏基础场景搭建 Loading,进入主菜单然后再进入选关界面最后进入游戏,红色箭头的流程。 退出,Ba
地图编辑器的使用 首先先来介绍一下使用地图编辑器tIDE Tile Map Editor来生成TMX文件。tIDE Tile M
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号