天天看點

Cocos3.4 橫版遊戲制作-《KillBear》-添加搖杆并控制Hero代碼建構A效果A代碼建構B效果B效果C結語

轉載時請務必以超連結形式标明文章 原始出處 、作者資訊和本聲明。

資源為網上尋找的,僅研究學習用,若是侵犯版權請通知本人整改。

上一篇:Cocos3.4 橫版遊戲制作-《KillBear》-加入Hero

在這一篇中,

上半部分我們将在控制層OperateLayer中加入一個搖杆,并通過搖杆控制Hero

下半部分我們控制Hero防止其跑出地圖和跑上牆

開發環境

  • win64 : vs2010
  • Cocos2d-x v3.4Final
  • TexturePackerGUI
  • MapEdit

代碼建構A

管理Operate

我們先做一個Joystick

搖杆Joystick

  • .h
class Joystick : public Sprite
{
public:
    Joystick();
    ~Joystick();
    virtual bool init();
    virtual void onTouchesBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *unused_event);
    virtual void onTouchesMoved(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *unused_event);
    virtual void onTouchesEnded(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event *unused_event); 
    void setJoystick(Vec2 point);
    CREATE_FUNC(Joystick);
private:
    void showJoystick();
    void hideJoystick();
    void updateJoystick(Touch* touch);
    int m_pJoystickr;
    int m_pJoystickR;
    Sprite *m_pJoystick;
    Sprite *m_pJoystickBg;
    Vec2 start;
};
           
  • .cpp
bool Joystick::init()
{
    bool ret = false;
    do {
        CC_BREAK_IF( !Sprite::init() );
        m_pJoystickBg = Sprite::create("JoystickBg.png");//背景
        m_pJoystick = Sprite::create("Joystick.png");//搖杆
        this->addChild(m_pJoystickBg, );
        this->addChild(m_pJoystick, );
        this->hideJoystick();
        //this->showJoystick();
        m_pJoystickR= m_pJoystickBg->getContentSize().width/;
        m_pJoystickr= m_pJoystick->getContentSize().width/;

        //新的API注冊這麼寫
        auto listener = EventListenerTouchAllAtOnce::create();
        listener->onTouchesBegan = CC_CALLBACK_2(Joystick::onTouchesBegan, this);
        listener->onTouchesMoved = CC_CALLBACK_2(Joystick::onTouchesMoved, this);
        listener->onTouchesEnded = CC_CALLBACK_2(Joystick::onTouchesEnded, this); 
        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

        ret = true;
    } while();

    return ret;
}

void Joystick::showJoystick()
{
    //顯示搖杆
    m_pJoystick->setVisible(true); 
    m_pJoystickBg->setVisible(true);
}

void Joystick::hideJoystick()
{
    //隐藏搖杆
    //m_pJoystick->setPosition(m_pJoystickBg->getPosition());
    m_pJoystick->setVisible(false);
    //m_pJoystickBg->setVisible(false);
    m_pJoystickBg->setVisible(true);
}


void Joystick::onTouchesBegan(const vector<Touch*>& touches, Event *unused_event)
{
    //按下事件處理
    std::vector<Touch*>::const_iterator touchIter = touches.begin();
    Touch* touch = (Touch*)(*touchIter);
    if(m_pJoystick->getBoundingBox().containsPoint(touch->getLocation()))
    {
        this->showJoystick();
        updateJoystick(touch);
        CCLOG("***************");
        CCLOG("update touch:%f %f",touch->getLocation().x,touch->getLocation().y);

        return;
    }
}

void Joystick::onTouchesMoved(const vector<Touch*>& touches, Event *unused_event)
{
    //移動時處理
    std::vector<Touch*>::const_iterator touchIter = touches.begin();
    Touch* touch = (Touch*)(*touchIter);
    if(m_pJoystick->isVisible())
    {
        updateJoystick(touch);
        return;
    }
}

void Joystick::onTouchesEnded(const vector<Touch*>& touches, Event *unused_event)
{
    //離開是處理
    //m_pJoystick->runAction(MoveTo::create(0.08f,start));
    //m_pJoystick->setPosition(start);
    //global->hero->onStop();
    this->hideJoystick();

}
void Joystick::setJoystick(Vec2 point)
{
    //将這個搖杆的放在某個坐标上
    start =point;
    m_pJoystickBg->setPosition(start);
    m_pJoystick->setPosition(m_pJoystickBg->getPosition());
}
void Joystick::updateJoystick(Touch* touch)
{
    //更新搖杆狀态
    //我用向量來判斷
    Vec2 hit = touch->getLocation();
    float distance = start.getDistance(hit);
    Vec2 direction = (hit - start).getNormalized();
    //為了防止搖杆移出搖杆背景
    if(distance < m_pJoystickr/)
    {
        m_pJoystick->setPosition(start + (direction * distance));
    }else if(distance >m_pJoystickr) {
        m_pJoystick->setPosition(start + (direction * m_pJoystickr));
    }else {
        m_pJoystick->setPosition(start + (direction * m_pJoystickr/));
    }

    //global->hero->onMove(direction,distance);
}
           

這個JoyStick的寫法我用了向量,不用笛卡爾坐标(xOy),我認為這樣寫更好了解它.

而且這個搖杆分為2段,

  • 某個範圍A内,随意移動
  • 超出最大範圍B-接觸點移出了搖杆背景時,将其設定在最大邊沿B處
  • 在這兩個範圍A-B之間,會沿着A的邊沿放置

最大的好處:我可以通過搖杆移動距離控制角色 (走),(跑)切換

相當的讨厭必須按2下才能讓角色執行跑動,自己寫簡單點行不行啊?

控制層OperateLayer

  • .h
  • .cpp

init中

auto m_pjoystick = Joystick::create();
        m_pjoystick->setJoystick(Vec2(,));
        this->addChild(m_pjoystick);
           

效果A

大功告成:

Cocos3.4 橫版遊戲制作-《KillBear》-添加搖杆并控制Hero代碼建構A效果A代碼建構B效果B效果C結語

接下來我提一個問題:Joystick和我們的Hero在不同層,如何讓這個搖杆控制我們的Hero呢?

實作的方法有很多.

這裡通過建立另一個Global,并将Joystick和Hero”注冊”上去,通過Joystick控制Global中的Hero,也就是直接控制Hero實作

Global是全局單類

Cocos3.4 橫版遊戲制作-《KillBear》-添加搖杆并控制Hero代碼建構A效果A代碼建構B效果B效果C結語

代碼建構B

首先引入一個Single.h

Other

唯一執行個體Single

這是一個優秀的單例執行個體(這是從别人的代碼中找到的)

  • .h
#ifndef _SINGLETON_H
#define _SINGLETON_H

using namespace std;

template <class T>
class Singleton
{
public:
    //擷取類的唯一執行個體
    static inline T* instance();
    //釋放類的唯一執行個體
    void release();
protected:
    Singleton(void){}
    ~Singleton(void){}
    static T* _instance;
};

template <class T>
inline T* Singleton<T>::instance()
{
        if(NULL == _instance){
            _instance = new T;
        }
    return _instance;
}

template <class T>
void Singleton<T>::release()
{
    if (!_instance)
        return;
    delete _instance;
    _instance = ;
}

//cpp檔案中需要先聲明靜态變量
#define DECLARE_SINGLETON_MEMBER(_Ty)   \
    template <> _Ty* Singleton<_Ty>::_instance = NULL;

#endif//_SINGLETON_H
           

全局類Global

我把後面需要用的都放進去了,頭檔案好說.

- .h

#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#include "cocos2d.h"
USING_NS_CC; 

#include "Singleton.h"
#include "GameLayer.h"
#include "OperateLayer.h"
#include "StateLayer.h"

//需引入以下類,否則在這些類中通路單例對象會報錯
class GameLayer;
class OperateLayer;
class StateLayer;
class Hero;
class Enemy;

//全局單例
class Global :public Singleton<Global>
{
public:
    Global(void);
    ~Global(void);

    //GameScene *gameScene;

    GameLayer *gameLayer;           //遊戲層
    OperateLayer *operateLayer;     //操作層
    StateLayer * stateLayer;        //狀态層
    Hero *hero;                     //英雄
    __Array *enemies;               //敵人
    TMXTiledMap *tileMap;           //地圖

    Point tilePosFromLocation(Vec2 MovePoint, TMXTiledMap *map = NULL);//将point轉換成地圖GID的point
    bool  tileAllowMove(Vec2 MovePoint);
};

#define global Global::instance()

#endif
           
  • .cpp
#include "Global.h"

DECLARE_SINGLETON_MEMBER(Global);
Global::Global(void)
{
}


Global::~Global(void)
{
    CC_SAFE_DELETE(gameLayer);
    CC_SAFE_DELETE(operateLayer);
    CC_SAFE_DELETE(stateLayer);
    CC_SAFE_DELETE(hero);
    CC_SAFE_DELETE(enemies);
    //CC_SAFE_DELETE(tileMap);
    gameLayer = NULL;           
    operateLayer= NULL; 
    stateLayer= NULL;       
    hero= NULL;             
    enemies= NULL;      
    tileMap= NULL;      
}
Point Global::tilePosFromLocation(Point MovePoint, TMXTiledMap *map) 
{
    Point point = MovePoint - map->getPosition();
    Point pointGID = Vec2::ZERO;
    pointGID.x = (int) (point.x / map->getTileSize().width); 
    pointGID.y = (int) ((map->getMapSize().height * map->getTileSize().height - point.y) / map->getTileSize().height); 
    return pointGID; 
}

bool Global::tileAllowMove(Point MovePoint)
{
    TMXLayer *floor = global->tileMap->getLayer("Floor");
    Point tileGid = tilePosFromLocation(MovePoint,global->tileMap);
    auto allowpoint =floor->getTileGIDAt(tileGid);
    if( == allowpoint)
    {
        return false;
    }
    return true;
}

           

在需要用到的地方注冊他比如GameLayer中:

  • .h

根據Global.h中所定義的,在對應cpp中需要添加諸如

- .cpp

GameLayer::GameLayer()
{
    global->gameLayer=this;
}
           
OperateLayer::OperateLayer()
{
    global->operateLayer=this;
}
           
StateLayer::StateLayer()
{
    global->stateLayer = this;
}
           

………需要添加的地方………太多了 還是看代碼吧.

不過後來如果有新的頭檔案我就扔上一個.

目前需要添加的頭檔案

MapLayer

GameLayer

StateLayer

OpreateLayer

Hero

JoyStick

角色Role

Hero

更新我們的Hero,添加下面代碼

- .h

void onMove(Vec2 direction, float distance);
    void onStop();
    void onAttack(int number);
    void updateSelf();
           
  • .cpp
void Hero::onMove(Vec2 direction, float distance)//移動調用
{
    this->setFlippedX(direction.x <  ? true : false);
    this->runWalkAction();
    Vec2 velocity = direction * (distance <  ?  : );
    this->setVelocity(velocity);
}
void Hero::onStop()//站立
{
    this->runIdleAction();
    this->setVelocity(Vec2::ZERO);
}
void Hero::onAttack(int number)//執行攻擊
{
    this->runNomalAttackA();
}
void Hero::updateSelf()//重新整理自己
{
    if(this->getCurrActionState() == ACTION_STATE_WALK)
    {
        Vec2 currentP= this->getPosition();             //目前坐标
        Vec2 expectP = currentP + this->getVelocity();  //期望坐标
        Vec2 actualP = expectP;                         //實際坐标

        this->setPosition(actualP);
        this->setLocalZOrder( Director::getInstance()->getVisibleSize().height - this->getPositionY());
    }
}
           

之後我們在Joystick中調用Hero的onMove,就可以讓其移動了

其他代碼我們後期再用

控制Operate

Joystick

去掉裡面的onTouchesEnded,updateJoystick中關于global->hero的//

實作Joystick控制Global中的hero

效果B

Cocos3.4 橫版遊戲制作-《KillBear》-添加搖杆并控制Hero代碼建構A效果A代碼建構B效果B效果C結語

額,主角的狀态切換了,但是還是不能動?什麼情況

找到原因了…..GameLayer中沒有更新主角坐标啊

Game

GameLayer

  • .h
void update(float dt);
    void updateHero(float dt);
           
  • .cpp

    init中啟動預設定時器update

this->scheduleUpdate();
           

然後是實作方法

void GameLayer::update(float dt)
{
    this->updateHero(dt);
}
           

而updateHero

void GameLayer::updateHero(float dt)
{
    m_pHero->updateSelf();//自更新狀态
}
           

效果C

Cocos3.4 橫版遊戲制作-《KillBear》-添加搖杆并控制Hero代碼建構A效果A代碼建構B效果B效果C結語

結語

至此,我們終于實作了标題的效果:添加搖杆并控制Hero

不過還是有一堆BUG,比如主角能跑到天上,主角移出了地圖

地圖不會動等.

将在下一篇中消除這些BUG