一、前言
一般來說,我們在做一個稍微有點智能的實體的時候都會用到狀态機。這裡我沒有用到,但是我也為角色設定了幾種狀态。
如果大家看了上一節,也完成了角色的基本移動的話。對比過我一直說的《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)){<span style="white-space:pre"> </span>//是這個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);<span style="white-space:pre"> </span>//根據起點和終點的距離,設定小方塊的拉伸
}
}
重要的代碼後面已經添加了注釋,應該不難了解。
最後,附上我們優化完的控制效果。

本節結束。
我的csdn位址:http://blog.csdn.net/hezijian22
郵箱位址:[email protected]
如有問題或指教,歡迎與我交流,謝謝。