轉載時請務必以超連結形式标明文章 原始出處 、作者資訊和本聲明。
資源為網上尋找的,僅研究學習用,若是侵犯版權請通知本人整改。
上一篇: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
大功告成:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiM5AzMzQzMzETOwIDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
接下來我提一個問題:Joystick和我們的Hero在不同層,如何讓這個搖杆控制我們的Hero呢?
實作的方法有很多.
這裡通過建立另一個Global,并将Joystick和Hero”注冊”上去,通過Joystick控制Global中的Hero,也就是直接控制Hero實作
Global是全局單類
代碼建構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
額,主角的狀态切換了,但是還是不能動?什麼情況
找到原因了…..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
結語
至此,我們終于實作了标題的效果:添加搖杆并控制Hero
不過還是有一堆BUG,比如主角能跑到天上,主角移出了地圖
地圖不會動等.
将在下一篇中消除這些BUG