Cocos2d-x 3.0 RPG 回合制游戏实战 (一)虚拟操作键(虚拟遥感)

     注:这个游戏是根据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.x<ActiveRect.origin.x+ActiveRect.size.width && touchPoint.y>ActiveRect.origin.y && touchPoint.y<ActiveRect.origin.y+ActiveRect.size.height) {
			return true;
		}
	}
    return false;
}
void JoyStick::updateTouchPoint(Point touchPoint)
{
    Point selfposition=this->getParent()->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));
    
}

下面是效果图:

点击屏幕,触摸时才会显示虚拟遥感,否侧隐藏






猜你喜欢

转载自blog.csdn.net/qqxj2012/article/details/18717951