注:这个游戏是根据http://code4app.com/ios/RPG%E5%9B%9E%E5%90%88%E5%88%B6%E6%88%98%E6%96%97%E6%B8%B8%E6%88%8F/527b41e86803fa9d28000002 使用Cocos2d-x 3.0beta重新实现的,而原游戏则使用Cocos2d-iphone
为什么将虚拟操作键放在第一篇呢?原因很简单,就目前而言,几乎绝大多数IOS ,Android等智能手机RPG游戏都有虚拟键来控制主角的移动,攻击等操作。所以本游戏也不例外。
废话不多说,上代码来的实际些。
1.虚拟键的设计
Config.h
/*******自定义创建scene的宏********/
#define CREATE_SCENE(__TYPE__) \
static Scene* scene() \
{ \
Scene *scene = Scene::create(); \
__TYPE__ *layer = __TYPE__::create() ; \
scene->addChild(layer); \
return scene; \
} \
#define winSize Director::getInstance()->getWinSize()
JoyStick.h
#ifndef __JoyStick__H_H
#define __JoyStick__H_H
#include "cocos2d.h"
#include "Config.h"
using namespace std;
USING_NS_CC;
class JoyStick;
//JoyStick的代理类
class JoyStickDelegate
{
public:
virtual void onJoyStickUpdate(Node*sender,float angle,Point direction,float power) =0;
};
class JoyStick:public Sprite
{
private:
CC_SYNTHESIZE(Sprite *, Ball, bBall); //更随手势转动的球
CC_SYNTHESIZE(Sprite *, Dock, dDock); //底座
CC_SYNTHESIZE(int, MoveAreaRadius, mMoveAreaRadius); //移动半径
CC_SYNTHESIZE(int, BallRadius, bBallRadius); //球半径
CC_SYNTHESIZE(Rect, ActiveRect, aActiveRect);
CC_SYNTHESIZE(int, ActiveRadius, aActiveRadius);
CC_SYNTHESIZE(Point, CurrentPoint, cCurrentPoint);
CC_SYNTHESIZE(bool, IsFollowTouch, iIsFollowTouch);
CC_SYNTHESIZE(bool, IsCanVisible, iIsCanVisible);
CC_SYNTHESIZE(bool, IsAutoHide, iIsAutoHide);
CC_SYNTHESIZE(bool, IsTouched, iIsTouched);
CC_SYNTHESIZE(bool, HasAnimation, hHasAnimation);
CC_SYNTHESIZE(float, Power, pPower);
CC_SYNTHESIZE(float, Angle, aAngle);
CC_SYNTHESIZE(Point, Direction, dDirection);
CC_SYNTHESIZE(JoyStickDelegate*, _delegate, Delegate);//代理
public:
// 自定义实例函数
static JoyStick * createJoyStick(const string&dockName,const string&ballName,int ballradius,int movearearadius,bool isfollowtouch,bool iscanvisible,bool isautohide,bool hasanimation);
/**********
函数参数说明:
1.参数dockName :底座背景图名称
2.参数ballName :旋转球名称
3.参数ballradius :旋转球的半径
4.参数movearearadius :旋转球活动半径
5.参数isfollowtouch :是否跟随触摸
6.参数iscanvisible :是否可见
7.参数isautohide :是否自动隐藏(即用户没有操作英雄时,隐藏操作键)
8.参数hasanimation :是否带动画
**********/
void initWithBallRadius(int ballradius,int movearearadius,bool isfollowtouch,bool iscanvisible,bool isautohide,bool hasanimation) ;
void setBallTexture(const string&imageName);
void setDockTexture(const string&imageName);
void setHitAreaWithRadius(int radius);
void setHitAreaWithRect(Rect rect);
void startTimer(float dt);
void stopTimer(float dt);
void timerUpdate(float dt);
void myTouchBegan(Point touchPoint);
void resetTexturePosition();
bool containsTouchLocation(Touch *touch) ;
void updateTouchPoint(Point touchPoint);
virtual bool onTouchBegan(Touch *touch, Event *unused_event);
virtual void onTouchMoved(Touch *touch, Event *unused_event);
virtual void onTouchEnded(Touch *touch, Event *unused_event);
virtual void onEnter();
virtual void onExit();
};
#endif /* defined(__JoyStick__H_H) */
#include "JoyStick.h"
//实例函数
JoyStick * JoyStick::createJoyStick(const string&dockName,const string&ballName,int ballradius,int movearearadius,bool isfollowtouch,bool iscanvisible,bool isautohide,bool hasanimation)
{
JoyStick* joystick = new JoyStick();
if (joystick)
{
joystick->autorelease();
joystick->initWithBallRadius(ballradius, movearearadius, isfollowtouch, iscanvisible, isautohide, hasanimation);
joystick->setDockTexture(dockName);
joystick->setBallTexture(ballName);
return joystick;
}
CC_SAFE_DELETE(joystick);
return NULL;
}
//JokStick的初始化
void JoyStick::initWithBallRadius(int ballradius,int movearearadius,bool isfollowtouch,bool iscanvisible,bool isautohide,bool hasanimation)
{
if (!Sprite::init())
{
return;
}
BallRadius=ballradius;
MoveAreaRadius=movearearadius;
IsFollowTouch=isfollowtouch;
IsCanVisible=iscanvisible;
IsAutoHide=isautohide;
HasAnimation=hasanimation;
Power=0;
Angle=0;
this->setHitAreaWithRect(Rect(0, 0, winSize.width, winSize.height));
Ball =Sprite::create();
Dock =Sprite::create();
// 注意这里的添加层次需要注意,否则可能显示不出来
this->addChild(Dock);
this->addChild(Ball);
if(!IsCanVisible)
{
this->setVisible(false);
}
else
{
if (IsAutoHide)
{
this->setVisible(false);
}
}
}
void JoyStick::setBallTexture(const string&imageName)
{
Ball->removeAllChildrenWithCleanup(true);
Sprite *balltexture=Sprite::create(imageName);
Ball->addChild(balltexture,1,1);
}
void JoyStick::setDockTexture(const string&imageName)
{
Dock->removeAllChildrenWithCleanup(true);
Sprite *docktexture=Sprite::create(imageName);
Dock->addChild(docktexture,-10);
}
void JoyStick::setHitAreaWithRadius(int radius)
{
ActiveRect=Rect(0, 0, 0, 0);
ActiveRadius=radius;
}
void JoyStick::setHitAreaWithRect(Rect rect)
{
ActiveRect=rect;
ActiveRadius=0;
}
void JoyStick::startTimer(float dt)
{
this->schedule(schedule_selector(JoyStick::timerUpdate));
}
void JoyStick::stopTimer(float dt)
{
this->unschedule(schedule_selector(JoyStick::timerUpdate));
}
void JoyStick::timerUpdate(float dt)
{
_delegate->onJoyStickUpdate(this, Angle, Direction, Power);
}
void JoyStick::myTouchBegan(Point touchPoint)
{
CurrentPoint = touchPoint;
IsTouched=true;
if(IsAutoHide && IsCanVisible){
this->setVisible(true);
}
if(IsFollowTouch)
{
this->setPosition(touchPoint);
}
Ball->stopAllActions();
this->updateTouchPoint(touchPoint);
this->startTimer(0);
}
void JoyStick::resetTexturePosition()
{
Power=0;
Angle=0;
CurrentPoint=Point(0,0);
if (!IsAutoHide && IsCanVisible && HasAnimation)
{
MoveTo *action =MoveTo::create(0.5, Point(0,0));
Ball->runAction(EaseElasticOut::create(action));
}
else
{
Ball->setPosition(Point(0,0));
}
}
bool JoyStick::containsTouchLocation(Touch *touch)
{
Point touchPoint = touch->getLocation();
if (ActiveRadius>0)
{
if (touchPoint.getDistance(this->getParent()->convertToWorldSpace(this->getPosition()))< ActiveRadius) {
return true;
}
}
if(ActiveRect.size.width>0 && ActiveRect.size.height>0){
if (touchPoint.x>ActiveRect.origin.x && touchPoint.xActiveRect.origin.y && touchPoint.ygetParent()->convertToWorldSpace(this->getPosition());
if (touchPoint.getDistance(Point(selfposition.x,selfposition.y)) > (MoveAreaRadius-BallRadius))
{
CurrentPoint =Point::ZERO+(Point(touchPoint.x-selfposition.x,touchPoint.y-selfposition.y)-Point::ZERO).normalize()*(MoveAreaRadius-BallRadius);
}
else
{
CurrentPoint = Point(touchPoint.x-selfposition.x,touchPoint.y-selfposition.y);
}
Ball->setPosition(CurrentPoint);
Angle=atan2(Ball->getPositionY(), Ball->getPositionX())/(3.14159/180);
Power=Ball->getPosition().getDistance(Point::ZERO)/(MoveAreaRadius-BallRadius);
Direction=Point(cos(Angle * (3.14159/180)),sin(Angle * (3.14159/180)));
}
bool JoyStick::onTouchBegan(Touch * touch,Event * event)
{
if (!this->containsTouchLocation(touch))
{
return false;
}
Point touchPoint =touch->getLocation();
this->myTouchBegan(touchPoint);
return true;
}
void JoyStick::onTouchMoved(Touch * touch,Event * event)
{
Point touchPoint =touch->getLocation();
if (IsTouched)
{
this->updateTouchPoint(touchPoint);
}
}
void JoyStick::onTouchEnded(Touch * touch,Event * event)
{
if (IsTouched)
{
if(IsAutoHide && IsCanVisible)
{
this->setVisible(false);
}
IsTouched=false;
this->stopTimer(0);
this->resetTexturePosition();
}
}
void JoyStick::onEnter()
{
//开启单点触摸事件监听
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->setSwallowTouches(false);
touchListener->onTouchBegan = CC_CALLBACK_2(JoyStick::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(JoyStick::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(JoyStick::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
Sprite::onEnter();
}
void JoyStick::onExit()
{
_eventDispatcher->removeAllEventListeners();
Sprite::onExit();
}
如何使用JoyStick?
TileLayer是瓷砖地图场景
TileLayer.h
#ifndef __TitleLayer_Layer_H__
#define __TitleLayer_Layer_H__
#include "cocos2d.h"
#include "Config.h"
#include "JoyStick.h"
#include "Hero.h"
using namespace cocos2d;
class TileLayer :public Layer,public JoyStickDelegate
{
public:
//主角
Hero *hero;
//虚拟遥感
JoyStick * joystick;
bool check;
/*检测主角的位置移动*/
float movestar,moveend,movedistance;
public:
virtual void onJoyStickUpdate(Node*sender,float angle,Point direction,float power);
public:
CC_SYNTHESIZE_RETAIN(TMXTiledMap*, tileMap, TileMap);
CC_SYNTHESIZE_RETAIN(ProgressTimer*, heroHP, HeroHP);
CC_SYNTHESIZE_RETAIN(ProgressTimer*, heroEXP, HeroEXP);
public:
void addJoyStick();
void addHero();
void addMap(int mapIndex);
public:
virtual bool init();
virtual void onEnter();
virtual void onExit();
virtual bool onTouchBegan(Touch *pTouch, Event *pEvent);
virtual void onTouchMoved(Touch *pTouch, Event *pEvent);
virtual void onTouchEnded(Touch *pTouch, Event *pEvent);
CREATE_SCENE(TileLayer);
CREATE_FUNC(TileLayer);
};
#endif // __TitleLayer_Layer_H__
#include "TileLayer.h"
bool TileLayer::init()
{
if ( !Layer::init() )
{
return false;
}
check=true;
this->addJoyStick();
this->addMap(1);
this->addHero();
return true;
}
void TileLayer::addJoyStick()
{
joystick =JoyStick::createJoyStick("analogue_bg.png", "analogue_handle.png", 25, 65, false, true, true, true);
joystick->setScale(0.6);
joystick->setPosition(101,110);
joystick->setDelegate(this);
this->addChild(joystick);
}
void TileLayer::addHero()
{
hero=Hero::createHeroEntity(HERO_0);
hero->setPosition(Point(80,100));
hero->runAction(RepeatForever::create(hero->getStandAnimate()));
this->addChild(hero,2);
}
void TileLayer::onEnter()
{
this->setTouchEnabled(true);
this->setTouchMode(Touch::DispatchMode ::ONE_BY_ONE);
Layer::onEnter();
}
void TileLayer::onExit()
{
Layer::onExit();
}
bool TileLayer::onTouchBegan(Touch *pTouch, Event *pEvent)
{
// CCLOG("TileLayer touched began!");
Point touchPoit=pTouch->getLocation();
joystick->setPosition(touchPoit);
return true;
}
void TileLayer::onTouchMoved(Touch *pTouch, Event *pEvent)
{
//CCLOG("TileLayer touched moved!");
}
void TileLayer::onTouchEnded(Touch *pTouch, Event *pEvent)
{
// CCLOG("TileLayer touched ended!");
}
//添加tile地图
void TileLayer::addMap(int mapIndex)
{
string mapName =String::createWithFormat("map_%d.tmx",mapIndex)->getCString();
this->tileMap =TMXTiledMap::create(mapName);
this->addChild(tileMap,-2);
}
#pragma mark -初始化摇杆
/*初始化摇杆。angle用来控制角色朝向,direction用来设置移动坐标,power为力度用于控制速度快慢*/
void TileLayer::onJoyStickUpdate(Node*sender,float angle,Point direction,float power)
{
if (check==true)
{
check=false;
hero->stopAllActions();
CallFunc *callback =CallFunc::create([&]() {
check= true;
hero->stopAllActions();
hero->runAction(RepeatForever::create(hero->getStandAnimate()));
});
hero->runAction(Sequence::create(hero->getRunAnimate(),callback,NULL) );
}
if (angle>-30&&angle<=30)
{
hero->setFlippedX(false);
}
else if (angle>30&&angle<=60)
{
hero->setFlippedX(false);
}
else if (angle>60&&angle<=120)
{
if (angle<=90)
{
hero->setFlippedX(false);
}else
{
hero->setFlippedX(true);
}
}
else if (angle>120&&angle<=150)
{
hero->setFlippedX(true);
}
else if ((angle>150&&angle<=180)||(angle>-180&&angle<=-150))
{
hero->setFlippedX(true);
}
else if (angle>-150&&angle<=-120)
{
hero->setFlippedX(true);
}
else if (angle>-120&&angle<=-60)
{
if (angle>=-90)
{
hero->setFlippedX(false);
}
else{
hero->setFlippedX(true);
}
}
else if (angle>-60&&angle<=-30)
{
hero->setFlippedX(false);
}
/*精灵坐标点*/
float nextx=hero->getPositionX();
float nexty=hero->getPositionY();
/*控制主角移动速度*/
nextx+=direction.x * (power*2);
nexty+=direction.y * (power*2);
/*为移动背景而准备的*/
moveend=nextx;
movedistance=direction.x;
/*角色移动边界*/
float sprity=320-35;
float spritx=480-30;
if (nexty>=sprity) {
nexty=sprity;
}
if (nexty<=35) {
nexty=35;
}
if(nextx<=30){
nextx=30;
}
if(nextx>=spritx){
nextx=spritx;
}
hero->setPosition(Point(nextx,nexty));
}
点击屏幕,触摸时才会显示虚拟遥感,否侧隐藏