cocos2dx3.2开发 RPG《Flighting》(六)角色的状态和控制效果

一、前言
一般来说,我们在做一个稍微有点智能的实体的时候都会用到状态机。这里我没有用到,但是我也为角色设置了几种状态。
如果大家看了上一节,也完成了角色的基本移动的话。对比过我一直说的《BattleHeart》之后,你会发现,现在的控制移动操作也太挫了,既没有那一条拉出来的导航线,也没有角色被选中的效果。所以接下来我们要对我们的基本控制操作加入一些效果。

二、正文
1、角色的状态
来来去去我们的角色无非几种基本状态 待机、移动、攻击、受伤、死亡。所以我们定义一个抽象类。声明了所有的状态对应的函数。

#ifndef _ROLEPROTOCOL_H_  
#define _ROLEPROTOCOL_H_  
class RoleProtocol{  
public:  
    virtual void stand() = 0;  
    virtual void move() = 0;  
    virtual void attack() = 0;  
    virtual void skill() = 0;  
    virtual void injured(int effect,int damage=0) = 0;  
    virtual void die() = 0;  
};  
#endif  

```

我们的Role类也做出相应的修改,继承RoleProtocol并且重写实现这些接口
在Role里面定义状态枚举类,并且增加一个成员变量表示当前角色的状态
public:  
    enum ROLE_STAT{  
        ROLE_STAND,  
        ROLE_MOVE,  
        ROLE_ATTACK,  
        ROLE_SKILL,  
        ROLE_INJURED,  
        ROLE_DIE,  
        ROLE_NULL  
    };  

```

ROLE_STAT en_stat;  //当前状态  

```

记得上一节的最后我们的两个方法move()和stand(),他们的由来就是上面所说的,下面看他们两个的实现
void Role::stand(){  
    if(m_arm && en_stat!=ROLE_STAND){  
        m_arm->getAnimation()->play("stand");  
        CCLOG("id=%d:stand",m_id);  
        en_stat = ROLE_STAND;  
    }  
}  
void Role::move(){  
    if(m_arm && en_stat!=ROLE_MOVE){  
        en_stat = ROLE_MOVE;  
        m_arm->getAnimation()->play("walk");  
    }  
}  

```

很简单,就是先判断是不是已经在播放站立或行走动画了,如果是,没必要在播放(不然会定在那里不动),如果不是,则播放动画。
现在暂时会用到的就这两种状态,其他状态以后用到的时候会在清楚说明。

2、控制效果
如果按现在的操作,点击选中我们的角色之后,要拉出去到目标点,再放开手(原本BattleHeart就是这样操作的)。
那么在视觉上起码也要有点效果提醒用户。
1)选中的高亮效果
实现思路:
在Role里面设置一个属性m_isHL,还有一个初始不可见的Sprite,m_select_circle
Layer中检测到Role被点击之后,设置m_isHL为true,Role的update函数会时刻检测m_isHL,如果为true的话,m_select_circle变得可见。
需要注意的是,还有很多小细节小逻辑需要处理,例如什么时候m_isHL设置为false,用户点击空白区域的时候(就是没有选中Role)怎么处理等等,不过也很简单,相信大家自己也能写出来。

2)拖出去的导航线
实现思路:
当触摸事件为move的时候,就是已经onTouchBegan选中角色了,鼠标在移动但是左键没有松开的时候。
在起点(角色的位置)和终点(鼠标的位置)之间画一条线。这里给出我的代码供大家参考。
bool Role::onTouchBegan(Touch* touch,Event* event){  
    if(!m_controlable){  
        return false;  
    }  
    if(m_arm){  
        Point point = touch->getLocationInView();  
        point = Director::getInstance()->convertToGL(point);  
        m_endPoint = point;  
  
        CCLOG("TOUCH POINT PX = %f,PY = %f",point.x,point.y);  
          
        Rect heroRect = getBoundingBox();  
  
        if(heroRect.containsPoint(point)){      //是这个if  
            m_trace = Sprite::create("color.png");        
            m_trace->setAnchorPoint(Point(0,0.5f));  
            this->addChild(m_trace,0);  
            CCLOG("CLICK MY HERO");  
            setHeightLight(true);  
            return true;  
        }else{  
            CCLOG("NOT CONTAIN");  
            return false;  
        }  
    }  
    return false;  
}  

```

onTouchBegan里面判断如果点中角色(上面代码那个if里面),会创建一个叫m_trace的Sprite。
m_trace开始的时候只是很小的一块矩形("color.png"只是很小的一块矩形,并不是一条线)。
void Role::onTouchMoved(Touch* touch,Event* event){  
    Point point = touch->getLocationInView();  
    point = Director::getInstance()->convertToGL(point);  
    m_endPoint = point;  
      
}  

```

明显,onTouchMoved里面就是设置m_endPoint而已(m_endPoint就是导航线的终点)

void Role::onTouchEnded(Touch* touch,Event* event){  
    if(m_trace){  
        m_trace->removeFromParentAndCleanup(true);  
        m_trace = nullptr;  
        setHeightLight(false);  
    }  
}  

```

onTouchEnded的触发表明已经松开鼠标左键。m_trace(导航线)应该消失了

关于导航线重要的还是下面的update函数
update中调用update_trace
void Role::update_trace(){  
    if(m_trace){  
        if(getBoundingBox().containsPoint(m_endPoint)){  
            m_endPoint = this->getPosition();  
        }  
        Point begin(CCDirector::getInstance()->convertToGL(this->getPosition()));  
        Point end(CCDirector::getInstance()->convertToGL(m_endPoint));  
        m_trace->setRotation(CC_RADIANS_TO_DEGREES(ccpToAngle(end - begin)));    //根据起点和终点,设置旋转角度  
        m_trace->setScaleX(ccpDistance(begin,end)/m_trace->getContentSize().width);   //根据起点和终点的距离,设置小方块的拉伸  
    }  
}  

```

重要的代码后面已经添加了注释,应该不难理解。

最后,附上我们优化完的控制效果。

![](http://img.blog.csdn.net/20150110174130635?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGV6aWppYW4yMg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)

本节结束。
我的csdn地址:http://blog.csdn.net/hezijian22
邮箱地址:578690286@qq.com
如有问题或指教,欢迎与我交流,谢谢。