怎樣制作一個橫版格斗過關游戲 Cocos2d-x 2.0.4



本文實踐自 Allen Tan 的文章《 How To Make A Side-Scrolling Beat ‘Em Up Game Like Scott Pilgrim with Cocos2D – Part 1》,文中使用Cocos2D,我在這里使用Cocos2D-x 2.0.4進行學習和移植。

在這篇文章。將會學習到怎樣制作一個簡單的橫版格斗過關游戲。在這其中,學習怎樣跟蹤動畫狀態、碰撞盒、加入方向鍵、加入簡單敵人AI和很多其他其他的。

過程例如以下:
1.新建Cocos2d-win32project,project名為"PompaDroid",去除"Box2D"選項,勾選"Simple Audio Engine in Cocos Denshion"選項。
2.加入游戲場景類GameScene,派生自CCScene類。加入GameLayer類和HudLayer類,派生自CCLayer類。

刪除HelloWorldScene.hHelloWorldScene.cpp文件。


3.文件GameScene.h代碼例如以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
#include  "cocos2d.h"
#include  "GameLayer.h"
#include  "HudLayer.h"

class GameScene :  public cocos2d::CCScene
{
public:
    GameScene( void);
    ~GameScene( void);

     virtual  bool init();
    CREATE_FUNC(GameScene);

    CC_SYNTHESIZE(GameLayer*, _gameLayer, GameLayer);
    CC_SYNTHESIZE(HudLayer*, _hudLayer, HudLayer);
};

文件GameScene.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
#include  "GameScene.h"
using  namespace cocos2d;

GameScene::GameScene( void)
{
    _gameLayer =  NULL;
    _hudLayer =  NULL;
}

GameScene::~GameScene( void)
{
}

bool GameScene::init()
{
     bool bRet =  false;
     do 
    {
         CC_BREAK_IF(!CCScene::init());
         
         _gameLayer = GameLayer::create();
          this->addChild(_gameLayer,  0);
         _hudLayer = HudLayer::create();
          this->addChild(_hudLayer,  1);
         
         bRet =  true;
    }  while ( 0);

     return bRet;
}

4.HudLayer類添加一個方法:

1
CREATE_FUNC(HudLayer);
GameLayer 類添加一個方法:
1
CREATE_FUNC(GameLayer);
5.改動 AppDelegate.cpp 文件。代碼例如以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//#include "HelloWorldScene.h"
#include  "GameScene.h"

bool AppDelegate::applicationDidFinishLaunching()
{
     //...

     // create a scene. it's an autorelease object
     //CCScene *pScene = HelloWorld::scene();
    CCScene *pScene = GameScene::create();

     //...
}

6.編譯執行,此時僅僅是空空的界面。


7.下載本游戲所需資源。將資源放置"Resources"文件夾下;

8.用Tiled工具打開pd_tilemap.tmx。就能夠看到游戲的整個地圖:

地圖上有兩個圖層:Wall和Floor,即牆和地板。去掉每一個圖層前的打鈎,能夠查看層的組成。你會發現下數第四行是由兩個圖層一起組成的。每一個tile都是32x32大小。可行走的地板tile位於下數三行。
9.打開GameLayer.h文件,加入例如以下代碼:

1
2
3
4
bool init();
void initTileMap();

cocos2d::CCTMXTiledMap *_tileMap;

打開GameLayer.cpp,在構造函數,加入例如以下代碼:

1
_tileMap =  NULL;
加入例如以下代碼:

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
bool GameLayer::init()
{
     bool bRet =  false;
     do 
    {
        CC_BREAK_IF(!CCLayer::init());

         this->initTileMap();
        
        bRet =  true;
    }  while ( 0);

     return bRet;
}

void GameLayer::initTileMap()
{
    _tileMap = CCTMXTiledMap::create( "pd_tilemap.tmx");
    CCObject *pObject =  NULL;
    CCARRAY_FOREACH(_tileMap->getChildren(), pObject)
    {
        CCTMXLayer *child = (CCTMXLayer*)pObject;
        child->getTexture()->setAliasTexParameters();
    }
     this->addChild(_tileMap, - 6);
}

對全部圖層進行setAliasTexParameters設置,該方法是關閉抗鋸齒功能,這樣就能保持像素風格。
10.編譯執行,能夠看到地圖顯示在屏幕上。例如以下圖所看到的:

11.創建英雄。

在大多數2D橫版游戲中,角色有不同的動畫代表不同類型的動作。

我們須要知道什么時候播放哪個動畫。

這里採用狀態機來解決問題。狀態機就是某種通過切換狀態來改變行為的東西。單一狀態機在同一時間僅僅能有一個狀態,但能夠從一種狀態過渡到還有一種狀態。在這個游戲中。角色共同擁有五種狀態,空暇、行走、出拳、受傷、死亡,例如以下圖所看到的:

為了有一個完整的狀態流,每一個狀態應該有一個必要條件和結果。

比如:行走狀態不能突然轉變到死亡狀態,由於你的英雄在死亡前必須先受傷。
12.加入ActionSprite類,派生自CCSprite類,ActionSprite.h文件代碼例如以下:

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
#pragma once
#include  "cocos2d.h"
#include  "Defines.h"

class ActionSprite :  public cocos2d::CCSprite
{
public:
    ActionSprite( void);
    ~ActionSprite( void);

     //action methods
     void idle();
     void attack();
     void hurtWithDamage( float damage);
     void knockout();
     void walkWithDirection(cocos2d::CCPoint direction);

     //scheduled methods
     void update( float dt);

     //actions
    CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _idleAction, IdleAction);
    CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _attackAction, AttackAction);
    CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _walkAction, WalkAction);
    CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _hurtAction, HurtAction);
    CC_SYNTHESIZE_RETAIN(cocos2d::CCAction*, _knockedOutAction, KnockedOutAction);

     //states
    CC_SYNTHESIZE(ActionState, _actionState, ActionState);

     //attributes
    CC_SYNTHESIZE( float, _walkSpeed, WalkSpeed);
    CC_SYNTHESIZE( float, _hitPoints, HitPoints);
    CC_SYNTHESIZE( float, _damage, Damage);

     //movement
    CC_SYNTHESIZE(cocos2d::CCPoint, _velocity, Velocity);
    CC_SYNTHESIZE(cocos2d::CCPoint, _desiredPosition, DesiredPosition);

     //measurements
    CC_SYNTHESIZE( float, _centerToSides, CenterToSides);
    CC_SYNTHESIZE( float, _centerToBottom, CenterToBottom);
};

打開ActionSprite.cpp文件,構造函數例如以下:

1
2
3
4
5
6
7
8
ActionSprite::ActionSprite( void)
{
    _idleAction =  NULL;
    _attackAction =  NULL;
    _walkAction =  NULL;
    _hurtAction =  NULL;
    _knockedOutAction =  NULL;
}
各個方法實現臨時為空。以上代碼聲明了基本變量和方法,能夠分為下面幾類:

  • Actions:這些是每種狀態要運行的動作。

    這些動作是當角色切換狀態時,運行精靈動畫和其它觸發的事件。


    States:保存精靈的當前動作/狀態。使用ActionState類型。這個類型待會我們將會進行定義。
    Attributes:包括精靈行走速度值,受傷時降低生命點值。攻擊傷害值。
    Movement:用於計算精靈怎樣沿着地圖移動。
    Measurements:保存對精靈的實際圖像實用的測量值。須要這些值,是由於你將要使用的這些精靈畫布大小是遠遠大於內部包括的圖像。


    Action methods:不直接調用動作。而是使用這些方法觸發每種狀態。


    Scheduled methods:不論什么事須要在一定的時間間隔進行執行,比方精靈位置和速度的更新,等等。

新建一個頭文件Defines.h。代碼例如以下:

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
#pragma once
#include  "cocos2d.h"

// 1 - convenience measurements
#define SCREEN CCDirector::sharedDirector()->getWinSize()
#define CENTER ccp(SCREEN.width /  2, SCREEN.height /  2)
#define CURTIME  do {                                                        \
    timeval time;                                                           \
    gettimeofday(&time,  NULL);                                              \
     unsigned  long millisecs = (time.tv_sec *  1000) + (time.tv_usec /  1000); \
     return ( float)millisecs;                                                \
while ( 0)

// 2 - convenience functions
#define random_range(low, high) (rand() % (high - low +  1)) + low
#define frandom ( float)rand() / UINT64_C(0x100000000)
#define frandom_range(low, high) ((high - low) * frandom) + low

// 3 - enumerations
typedef  enum _ActionState {
    kActionStateNone =  0,
    kActionStateIdle,
    kActionStateAttack,
    kActionStateWalk,
    kActionStateHurt,
    kActionStateKnockedOut
} ActionState;

// 4 - structures
typedef  struct _BoundingBox {
    cocos2d::CCRect actual;
    cocos2d::CCRect original;
} BoundingBox;
簡要說明下:
①.定義了一些便利的宏,如直接使用SCREEN獲取屏幕大小;
②.定義了一些便利的函數,隨機返回整型或者浮點型;
③.定義ActionState類型,這個是ActionSprite可能處在不同狀態的類型枚舉;
④.定義BoundingBox結構體。將用於碰撞檢測。
打開 GameLayer.h 文件。加入例如以下代碼:
1
cocos2d::CCSpriteBatchNode *_actors;
打開 GameLayer.cpp 文件。在 init 函數里面加入例如以下代碼:
1
2
3
4
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile( "pd_sprites.plist");
_actors = CCSpriteBatchNode::create( "pd_sprites.pvr.ccz");
_actors->getTexture()->setAliasTexParameters();
this->addChild(_actors, - 5);

載入精靈表單,創建一個CCSpriteBatchNode。這個精靈表單包括我們的全部精靈。它的z值高於CCTMXTiledMap對象。這樣才干出如今地圖前。


加入Hero類,派生自ActionSprite類,加入例如以下代碼:

1
2
CREATE_FUNC(Hero);
bool init();
Hero 類的 init 函數的實現例如以下所看到的:

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
bool Hero::init()
{
     bool bRet =  false;
     do 
    {
        CC_BREAK_IF(!ActionSprite::initWithSpriteFrameName( "hero_idle_00.png"));

         int i;
         //idle animation
        CCArray *idleFrames = CCArray::createWithCapacity( 6);
         for (i =  0; i <  6; i++)
        {
            CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat( "hero_idle_%02d.png", i)->getCString());
            idleFrames->addObject(frame);
        }
        CCAnimation *idleAnimation = CCAnimation::createWithSpriteFrames(idleFrames,  1. 0 /  12. 0);
         this->setIdleAction(CCRepeatForever::create(CCAnimate::create(idleAnimation)));

         this->setCenterToBottom( 39. 0);
         this->setCenterToSides( 29. 0);
         this->setHitPoints( 100. 0);
         this->setDamage( 20. 0);
         this->setWalkSpeed( 80. 0);
        
        bRet =  true;
    }  while ( 0);

     return bRet;
}

我們用初始空暇精靈幀創建了英雄角色,配備了一個CCArray數組包括全部的屬於空暇動畫的精靈幀,然后創建一個CCAction動作播放來這個動畫。以每秒12幀的速率進行播放。接下去,為英雄設置初始屬性,包括精靈中心到邊究竟部的值。例如以下圖所看到的:

英雄的每一個精靈幀都在280x150像素大小的畫布上創建,但實際上英雄精靈僅僅占領這個空間的一部分。所以須要兩個測量值,以便更好的設置精靈的位置。須要額外的空間,是由於每一個動畫精靈繪制的方式是不同的,而有些就須要很多其它的空間。


打開GameLayer.h文件,加入頭文件聲明:

1
#include  "Hero.h"
GameLayer 類加入例如以下代碼:
1
Hero *_hero;
打開 GameLayer.cpp 文件,在構造函數加入例如以下代碼:
1
_hero =  NULL;
init 函數 this->addChild(_actors, -5); 后面加入例如以下代碼:
1
this->initHero();
加入 initHero 方法,代碼例如以下:
1
2
3
4
5
6
7
8
void GameLayer::initHero()
{
    _hero = Hero::create();
    _actors->addChild(_hero);
    _hero->setPosition(ccp(_hero->getCenterToSides(),  80));
    _hero->setDesiredPosition(_hero->getPosition());
    _hero->idle();
}
創建了一個英雄實例,加入到了精靈表單,並設置了設置。調用 idle 方法。讓其處於空暇狀態,執行空暇動畫。返回到 ActionSprite.cpp 文件,實現 idle 方法。代碼例如以下:
1
2
3
4
5
6
7
8
9
10
void ActionSprite::idle()
{
     if (_actionState != kActionStateIdle)
    {
         this->stopAllActions();
         this->runAction(_idleAction);
        _actionState = kActionStateIdle;
        _velocity = CCPointZero;
    }
}
這個 idle 方法僅僅有當ActionSprite不處於空暇狀態才干調用。當它觸發時,它會運行空暇動作,改變當前狀態到 kActionStateIdle ,而且把速度置零。
13.編譯執行,能夠看到英雄處於空暇狀態。

例如以下圖所看到的:

14.出拳動作。打開Hero.cpp文件,在init函數idle animation后面,加入例如以下代碼:

1
2
3
4
5
6
7
8
9
//attack animation
CCArray *attackFrames = CCArray::createWithCapacity( 3);
for (i =  0; i <  3; i++)
{
    CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat( "hero_attack_00_%02d.png", i)->getCString());
    attackFrames->addObject(frame);
}
CCAnimation *attackAnimation = CCAnimation::createWithSpriteFrames(attackFrames,  1. 0 /  24. 0);
this->setAttackAction(CCSequence::create(CCAnimate::create(attackAnimation), CCCallFunc::create( this, callfunc_selector(Hero::idle)),  NULL));
打開ActionSprite.cpp文件,實現attack方法,代碼例如以下:
1
2
3
4
5
6
7
8
9
void ActionSprite::attack()
{
     if (_actionState == kActionStateIdle || _actionState == kActionStateAttack || _actionState == kActionStateWalk)
    {
         this->stopAllActions();
         this->runAction(_attackAction);
        _actionState = kActionStateAttack;
    }
}
英雄僅僅有在空暇、攻擊、行走狀態才干進行出拳。確保英雄正在受傷時、或者死亡時不能進行攻擊。為了觸發attack方法,打開GameLayer.cpp文件,在init函數加入例如以下代碼:
1
this->setTouchEnabled( true);
重載ccTouchesBegan方法,代碼例如以下:
1
2
3
4
void GameLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
    _hero->attack();
}
15.編譯執行。點擊屏幕進行出拳。例如以下圖所看到的:

16.創建8個方向的方向鍵。

我們須要創建虛擬的8個方向的方向鍵來讓英雄在地圖上進行移動。

加入SimpleDPad類,派生自CCSprite類,SimpleDPad.h文件代碼例如以下:

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
#pragma once
#include  "cocos2d.h"

class SimpleDPad;

class SimpleDPadDelegate
{
public:
     virtual  void didChangeDirectionTo(SimpleDPad *simpleDPad, cocos2d::CCPoint direction) =  0;
     virtual  void isHoldingDirection(SimpleDPad *simpleDPad, cocos2d::CCPoint direction) =  0;
     virtual  void simpleDPadTouchEnded(SimpleDPad *simpleDPad) =  0;
};

class SimpleDPad :  public cocos2d::CCSprite,  public cocos2d::CCTargetedTouchDelegate
{
public:
    SimpleDPad( void);
    ~SimpleDPad( void);

     static SimpleDPad* dPadWithFile(cocos2d::CCString *fileName,  float radius);
     bool initWithFile(cocos2d::CCString *filename,  float radius);

     void onEnterTransitionDidFinish();
     void onExit();
     void update( float dt);

     virtual  bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
     virtual  void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
     virtual  void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);

     void updateDirectionForTouchLocation(cocos2d::CCPoint location);

    CC_SYNTHESIZE(SimpleDPadDelegate*, _delegate, Delegate);
    CC_SYNTHESIZE( bool, _isHeld, IsHeld);

protected:
     float _radius;
    cocos2d::CCPoint _direction;
};

對以上的一些聲明。解釋例如以下:

  • radius:圓形方向鍵的半徑。


    direction:當前所按下的方向。這是一個矢量。(-1.0, -1.0)是左下方向,(1.0, 1.0)是右上方向。
    delegate:方向鍵的托付,興許進行介紹。
    isHeld:布爾值表示玩家觸摸着方向鍵。

對於SimpleDPad類,使用了托付模式。意味着一個托付類(並不是SimpleDPad),將會處理由被托付類(SimpleDPad)啟動的任務。在某些你指定的點上,主要是當涉及到處理不論什么游戲相關的東西。SimpleDPad將會將職責傳遞給托付類。這使得SimpleDPad無需知道不論什么游戲邏輯,從而同意你在開發不論什么其它游戲時,能夠進行重用。

例如以下圖所看到的:

當SimpleDPad檢測到在方向鍵內的觸摸,它會計算觸摸的方向,然后發送消息到托付類指明方向。在這之后的不論什么事情都不是SimpleDPad所關心的了。為了實施這個模式。SimpleDPad須要至少了解其托付的有關信息。特別是將觸摸方向傳遞給托付的方法。

這是還有一種設計模式:協議。

能夠看到SimpleDPad的托付定義了所需的方法。在這樣的方式中,SimpleDPad強制其托付有三個指定的方法,以便確保每當它想傳遞東西放到托付中時,它能調用這些方法中的不論什么一種。其實,SimpleDPad也遵循一種協議,即CCTargetedTouchDelegate。當SimpleDPad被觸摸時,進行處理觸摸事件,而GameLayer將不會得到觸摸。

否則的話,在觸摸方向鍵的時候,英雄就會出拳攻擊,顯然。這不是希望看到的。打開SimpleDPad.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include  "SimpleDPad.h"
using  namespace cocos2d;

SimpleDPad::SimpleDPad( void)
{
    _delegate =  NULL;
}

SimpleDPad::~SimpleDPad( void)
{
}

SimpleDPad* SimpleDPad::dPadWithFile(CCString *fileName,  float radius)
{
    SimpleDPad *pRet =  new SimpleDPad();
     if (pRet && pRet->initWithFile(fileName, radius))
    {
         return pRet;
    }
     else
    {
         delete pRet;
        pRet =  NULL;
         return  NULL;
    }
}

bool SimpleDPad::initWithFile(CCString *filename,  float radius)
{
     bool bRet =  false;
     do 
    {
        CC_BREAK_IF(!CCSprite::initWithFile(filename->getCString()));
        
        _radius = radius;
        _direction = CCPointZero;
        _isHeld =  false;
         this->scheduleUpdate();

        bRet =  true;
    }  while ( 0);

     return bRet;
}

void SimpleDPad::onEnterTransitionDidFinish()
{
    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate( this1true);
}

void SimpleDPad::onExit()
{
    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate( this);
}

void SimpleDPad::update( float dt)
{
     if (_isHeld)
    {
        _delegate->isHoldingDirection( this, _direction);
    }
}

bool SimpleDPad::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    CCPoint location = pTouch->getLocation();

     float distanceSQ = ccpDistanceSQ(location,  this->getPosition());
     if (distanceSQ <= _radius * _radius)
    {
         this->updateDirectionForTouchLocation(location);
        _isHeld =  true;
         return  true;
    }
     return  false;
}

void SimpleDPad::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
    CCPoint location = pTouch->getLocation();
     this->updateDirectionForTouchLocation(location);
}

void SimpleDPad::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
    _direction = CCPointZero;
    _isHeld =  false;
    _delegate->simpleDPadTouchEnded( this);
}

void SimpleDPad::updateDirectionForTouchLocation(CCPoint location)
{
     float radians = ccpToAngle(ccpSub(location,  this->getPosition()));
     float degrees = - 1 * CC_RADIANS_TO_DEGREES(radians);

     if (degrees <=  22. 5 && degrees >= - 22. 5
    {
         //right
        _direction = ccp( 1. 00. 0);
    }
     else  if (degrees >  22. 5 && degrees <  67. 5)
    {
         //bottomright
        _direction = ccp( 1. 0, - 1. 0);
    }
     else  if (degrees >=  67. 5 && degrees <=  112. 5)
    {
         //bottom
        _direction = ccp( 0. 0, - 1. 0);
    }
     else  if (degrees >  112. 5 && degrees <  157. 5)
    {
         //bottomleft
        _direction = ccp(- 1. 0, - 1. 0);
    }
     else  if (degrees >=  157. 5 || degrees <= - 157. 5)
    {
         //left
        _direction = ccp(- 1. 00. 0);
    }
     else  if (degrees < - 22. 5 && degrees > - 67. 5)
    {
         //topright
        _direction = ccp( 1. 01. 0);
    }
     else  if (degrees <= - 67. 5 && degrees >= - 112. 5)
    {
         //top
        _direction = ccp( 0. 01. 0);
    }
     else  if (degrees < - 112. 5 && degrees > - 157. 5)
    {
         //topleft
        _direction = ccp(- 1. 01. 0);
    }
    _delegate->didChangeDirectionTo( this, _direction);
}
以上方法中,onEnterTransitionDidFinish注冊SimpleDPad托付類,onExit移除SimpleDPad托付類,update方法是當方向鍵被觸摸時,傳遞方向值到托付類。ccTouchBegan方法檢測觸摸位置是否在方向鍵圓內。假設是,則將isHeld置為true。並更新方向值。返回true以擁有觸摸事件優先權。ccTouchMoved當觸摸點移動時。更新方向值。

ccTouchEnded將isHeld置為false。重置方向,並通知托付觸摸結束。

updateDirectionForTouchLocation方法計算觸摸點到方向鍵中心距離值,轉換成角度,得到正確的方向值,然后傳遞值到托付。

打開HudLayer.h文件。加入頭文件聲明:

1
#include  "SimpleDPad.h"
加入例如以下代碼:
1
2
bool init();
CC_SYNTHESIZE(SimpleDPad*, _dPad, DPad);
打開HudLayer.cpp文件,加入例如以下代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
HudLayer::HudLayer( void)
{
    _dPad =  NULL;
}

bool HudLayer::init()
{
     bool bRet =  false;
     do 
    {
        CC_BREAK_IF(!CCLayer::init());

        _dPad = SimpleDPad::dPadWithFile(CCString::create( "pd_dpad.png"),  64);
        _dPad->setPosition(ccp( 64. 064. 0));
        _dPad->setOpacity( 100);
         this->addChild(_dPad);

        bRet =  true;
    }  while ( 0);

     return bRet;
}

以上代碼實例化SimpleDPad,而且加入到HudLayer上。如今GameScene同一時候控制GameLayer和HudLayer,但有時候想直接通過HudLayer訪問GameLayer。打開GameLayer.h文件,加入頭文件聲明:

1
2
#include  "SimpleDPad.h"
#include  "HudLayer.h"
GameLayer類聲明改動成例如以下:
1
class GameLayer :  public cocos2d::CCLayer,  public SimpleDPadDelegate
並加入下面聲明:

1
2
3
4
5
virtual  void didChangeDirectionTo(SimpleDPad *simpleDPad, cocos2d::CCPoint direction);
virtual  void isHoldingDirection(SimpleDPad *simpleDPad, cocos2d::CCPoint direction);
virtual  void simpleDPadTouchEnded(SimpleDPad *simpleDPad);

CC_SYNTHESIZE(HudLayer*, _hud, Hud);

以上方法的實現臨時為空。

這樣我們就在GameLayer中加入了HudLayer的引用,同一時候還讓GameLayer遵循SimpleDPad所創建的協議。打開GameScene.cpp文件,在init函數this->addChild(_hudLayer, 1);后面,加入例如以下代碼:

1
2
_hudLayer->getDPad()->setDelegate(_gameLayer);
_gameLayer->setHud(_hudLayer);
17.編譯執行,能夠看到左下角的虛擬方向鍵,例如以下圖所看到的:

別試着壓下方向鍵,英雄不會有不論什么反應。由於還未實現協議方法,這在第二部分將完畢。

參考資料:
1.How To Make A Side-Scrolling Beat ‘Em Up Game Like Scott Pilgrim with Cocos2D – Part 1http://www.raywenderlich.com/24155/how-to-make-a-side-scrolling
2.怎樣使用cocos2d制作類似Scott Pilgrim的2D橫版格斗過關游戲part1(翻譯) http://blog.sina.com.cn/s/blog_4b55f6860101a9b7.html
3.怎樣使用Cocos2d-x做一DNF類的游戲-part1 http://blog.csdn.net/jyzgo/article/details/8471306

很感謝以上資料,本樣例源碼附加資源下載地址http://download.csdn.net/detail/akof1314/5038013
如文章存在錯誤之處。歡迎指出,以便改正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM