16.创建8个方向的方向键。我们需要创建虚拟的8个方向的方向键来让英雄在地图上进行移动。添加SimpleDPad类,派生自CCSprite类,SimpleDPad.h文件代码如下:


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

//SimpleDPad也遵循一种协议,即CCTargetedTouchDelegate。当SimpleDPad被触摸时,进行处理触摸事件,而GameLayer将不会得到触摸。 否则的话,在触摸方向键的时候,英雄就会出拳攻击,显然,这不是希望看到的。
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);
    //isHeld:布尔值表示玩家触摸着方向键。
    CC_SYNTHESIZE(bool, _isHeld, IsHeld);
    
protected:
    //虚拟手柄的半径
    float _radius;
    //当前所按下的方向。这是一个矢量,(-1.0, -1.0)是左下方向,(1.0, 1.0)是右上方向。
    cocos2d::CCPoint _direction;
};


对以上的一些声明,解释如下:

  • radius:圆形方向键的半径。
    direction:当前所按下的方向。这是一个矢量,(-1.0, -1.0)是左下方向,(1.0, 1.0)是右上方向。
    delegate:方向键的委托,后续进行介绍。
    isHeld:布尔值表示玩家触摸着方向键。

对于SimpleDPad类,使用了委托模式。意味着一个委托类(并非SimpleDPad),将会处理由被委托类(SimpleDPad)启动的任务。在某些你指定的点上,主要是当涉及到处理任何游戏相关的东西,SimpleDPad将会将职责传递给委托类。这使得SimpleDPad无需知道任何游戏逻辑,从而允许你在开发任何其他游戏时,可以进行重用。如下图所示:

2d格斗 python 2D格斗黄油_cocos2d-x


当SimpleDPad检测到在方向键内的触摸,它会计算触摸的方向,然后发送消息到委托类指明方向。在这之后的任何事情都不是SimpleDPad所关心的了。为了实施这个模式,SimpleDPad需要至少了解其委托的有关信息,特别是将触摸方向传递给委托的方法。这是另一种设计模式:协议。可以看到SimpleDPad的委托定义了所需的方法,在这种方式中,SimpleDPad强制其委托有三个指定的方法,以便确保每当它想传递东西放到委托中时,它能调用这些方法中的任何一种。事实上,SimpleDPad也遵循一种协议,即CCTargetedTouchDelegate。当SimpleDPad被触摸时,进行处理触摸事件,而GameLayer将不会得到触摸。否则的话,在触摸方向键的时候,英雄就会出拳攻击,显然,这不是希望看到的。打开SimpleDPad.cpp文件,添加如下代码:

USING_NS_CC;
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()
{
    //这里的三个参数,第一个:是哪个对象进行触摸注册,第二个:触摸优先级   第三个是否吞噬掉本次触摸事件  为true时时吞噬调触摸事件 就是不让触摸事件向下传递
    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,1, true);
}
//在程序移除该类时,移除触摸事件的代理
void SimpleDPad::onExit()
{
    CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);
}
//update方法是当方向键被触摸时,
void SimpleDPad::update(float dt)
{
    //_isHeld是控制手柄是否被触摸的开关
    if (_isHeld)
    {
        //传递方向值到委托类   方向值为 _direction
        _delegate->isHoldingDirection(this, _direction);
    }
}
//触摸开始时执行该方法
bool SimpleDPad::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
    //获取触摸的坐标点
    CCPoint location = pTouch->getLocation();
    //计算触摸点和当前类即虚拟手柄对象中心点的距离  ,this->getPosition()获取的是精灵中心点的坐标
    float distanceSQ = ccpDistanceSQ(location, this->getPosition());
  //    判断触摸点是否在虚拟手柄精灵内
    if (distanceSQ <= _radius * _radius)
    {
        //updateDirectionForTouchLocation方法计算触摸点到方向键中心距离值,转换成角度,得到正确的方向值,然后传递值到委托。
        //因此需要将触摸点的坐标传过去
        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);
}
//CCPoint location  参数是手指触摸屏幕的坐标点
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.0,0.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.0,0.0);
    }
    else if (degrees < -22.5 && degrees > -67.5)
    {
        //topright右上
        _direction = ccp(1.0,1.0);
    }
    else if (degrees <= -67.5 && degrees >= -112.5)
    {
        //top上
        _direction = ccp(0.0,1.0);
    }
    else if (degrees < -112.5 && degrees > -157.5)
    {
        //topleft左上
        _direction = ccp(-1.0,1.0);
    }
    //将得到的方向传递到采用代理的类中, _ direction就是得到的方向
    _delegate->didChangeDirectionTo(this, _direction);
}

以上方法中,

onEnterTransitionDidFinish 注册SimpleDPad委托类, onExit 移除SimpleDPad委托类, update 方法是当方向键被触摸时,传递方向值到委托类。 ccTouchBegan 方法检测触摸位置是否在方向键圆内,如果是,则将isHeld置为true,并更新方向值,返回true以拥有触摸事件优先权。 ccTouchMoved 当触摸点移动时,更新方向值。 ccTouchEnded 将isHeld置为false,重置方向,并通知委托触摸结束。 updateDirectionForTouchLocation 方法计算触摸点到方向键中心距离值,转换成角度,得到正确的方向值,然后传递值到委托。

打开HudLayer.h文件,添加头文件声明:

#include       "SimpleDPad.h"


添加如下代码:

bool init();       
 CC_SYNTHESIZE(SimpleDPad*, _dPad, DPad);      

 HudLayer();


打开HudLayer.cpp文件,添加如下代码:

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.0,64.0));
        //透明度
        _dPad->setOpacity(100);
        //将精灵加到层上
        this->addChild(_dPad);
        
        bRet = true;
    } while (0);
    
    return bRet;
}

以上代码实例化SimpleDPad,并且添加到HudLayer上。现在GameScene同时控制GameLayer和HudLayer,但有时候想直接通过HudLayer访问GameLayer。打开GameLayer.h文件,添加头文件声明:

#include       "SimpleDPad.h"       
#include       "HudLayer.h"


将GameLayer类声明修改成如下:

class GameLayer :        public cocos2d::CCLayer,        public


并添加以下声明:

virtual        void didChangeDirectionTo(SimpleDPad *simpleDPad, cocos2d::CCPoint direction);       
virtual        void isHoldingDirection(SimpleDPad *simpleDPad, cocos2d::CCPoint direction);       
virtual        void simpleDPadTouchEnded(SimpleDPad *simpleDPad);       //下面方法是为了在GameLayer中添加了HudLayer的引用 就是可以对HudLayer进行操作


以上方法的实现暂时为空。

在GameLayer.cpp中添加如下方法

void didChangeDirectionTo(SimpleDPad *simpleDPad, cocos2d::CCPoint direction)
{
    
}
void isHoldingDirection(SimpleDPad *simpleDPad, cocos2d::CCPoint direction)
{
    
}
void simpleDPadTouchEnded(SimpleDPad *simpleDPad)
{
    
}

这样我们就在

GameLayer 中添加了

HudLayer 的引用,同时还让

GameLayer 遵循

SimpleDPad 所创建的协议。打开

GameScene.cpp 文件,在

init 函数

this->addChild(_hudLayer, 1); 后面,添加如下代码:

//设置代理对象为游戏层_gameLayer


       _hudLayer->getDPad()->setDelegate(_gameLayer);       
 _gameLayer->setHud(_hudLayer);




17.编译运行,可以看到左下角的虚拟方向键,如下图所示:

2d格斗 python 2D格斗黄油_2d格斗 python_02


别试着压下方向键,英雄不会有任何反应,因为还未实现协议方法,这在第二部分将完成。

代码例子 http://vdisk.weibo.com/s/BDn59yfnBVkAS