cocos2dx 3d開源項目 fantasyWarrior3D 從零走起 6完結 [AttackManager&GameMaster],cocos2dx開源遊戲
[AttackCommand]1. 聲明基本的碰撞體,作為角色釋放的攻擊單位
BasicCollider = class("BasicCollider", function() local node = cc.Node:create() node:setCascadeColorEnabled(true) return nodeend)
function BasicCollider:ctor() self.minRange = 0 --the min radius of the fan self.maxRange = 150 --the max radius of the fan self.angle = 120 --arc of attack, in radians self.knock = 150 --default knock, knocks 150 units self.mask = 1 --1 is Heroes, 2 is enemy, 3 ?? self.damage = 100 self.facing = 0 --this is radians self.duration = 0 self.curDuration = 0 self.speed = 0 --traveling speed} self.criticalChance = 0end
每個角色的具體參數都在GlobalVariables.lua中配置
angle 攻擊角度,非常有用,關係到技能和攻擊的作用範圍
maxRange 攻擊的作用範圍
這兩個參數就可以決定了一個 "技能的作用地區",可以很方便得實現如"扇形"等攻擊地區
這樣攻擊技能的生效不一定需要BasicCollider和目標“碰撞”才觸發,只要敵人站在攻擊地區就可以算打到了。
speed 攻擊體移動的速度,對於戰士的攻擊或法師的“冰牆”則speed為0
duration 期間
DOTTimer 持續傷害的cd
還可以增加一個屬性maxTarget,來決定一個技能是單體吸收還是能夠穿透目標,
作用在多個目標上面。比如dota裡 大牛“衝擊波” 巫妖的“連環霜凍”等
2. AttackManager 所有被釋放的攻擊單位都放在 AttackManager 中
solveAttacks 攻擊單位的幀迴圈
主要幹了3件事:
[1]判斷是否“打到了”
onCollide 攻擊生效:條件是 距離 和角度滿足
_myPos 會不斷隨著遊戲進行更新
function Actor:baseUpdate(dt)
self._myPos = getPosTable(self)
...
end
計算攻擊單位轉向目標需要的角度
local angle = radNormalize(cc.pToAngleSelf(cc.pSub(mpos,apos)))
計算攻擊單位的朝向
local afacing = radNormalize(attack.facing)
判斷是否在攻擊區
if(afacing + attack.angle/2)>angle and angle > (afacing- attack.angle/2) then
attack:onCollide(monster)
end
[2]根據duration判斷逾時
onTimeOut 移除攻擊單位
[3]根據speed更新位置
onUpdate
3. 繼承基本的攻擊單位,來實現各種角色技能那麼來看一下法師的"冰牆"怎麼做的
Mage:specialAttack()
其中
local pos1 = getPosTable(self)local pos2 = getPosTable(self)local pos3 = getPosTable(self)pos1.x = pos1.x+130pos2.x = pos2.x+330pos3.x = pos3.x+530pos1 = cc.pRotateByAngle(pos1, self._myPos, self._curFacing)pos2 = cc.pRotateByAngle(pos2, self._myPos, self._curFacing)pos3 = cc.pRotateByAngle(pos3, self._myPos, self._curFacing)
pRotateByAngle 返回點以pos1 以self._myPos為旋轉軸點,按逆時針方向旋轉self._curFacing弧度,
這樣最終得到三個點,他們在 法師 和目標的連線上,與法師的距離分別為130 330 530。在這3個點建立了3個MageIceSpikes
MageIceSpikes.create
隨機由10個冰刺組成,並且添加粒子效果
屬性:
_specialAttack = { minRange = 0, maxRange = 140, angle = DEGREES_TO_RADIANS(360), knock = 75, damage = 250, mask = EnumRaceType.HERO, duration = 4.5, speed = 0, criticalChance = 0.05, DOTTimer = 0.75, --it will be able to hurt every 0.5 seconds curDOTTime = 0.75, DOTApplied = false },
[GameMaster]
GameMaster:init() 從中可以看到
統一把角色建立好,再分批放出來
self:AddHeros()
self:addMonsters()
logicUpdate 幀迴圈
主要負責控制英雄的前進和小怪的重新整理
local battleSiteX = {-2800,-1800,-800}
設定了觸發地點 和 重新整理地點
stage為 1~7
隨機刷怪 or 向右跑
stage == 7 清掉小怪
stage == 8 給予警告
警告結束後就顯示boss了 showBoss()
可以配置性不太強,所以這裡就不具體分析代碼了
[ParticleManager]plist包含兩部分內容:粒子系統屬性和粒子紋理
1. 粒子屬性載入和建立Quad粒子物件在啟動的時候調用AddPlistData 載入粒子的plist檔案,並且緩衝為map格式
從介面實現來看,如果直接從緩衝的map來建立粒子的話,就省去了讀檔案的時間,起到最佳化的作用
ParticleSystemQuad * ParticleSystemQuad::create(ValueMap &dictionary)
{
ParticleSystemQuad *ret = new (std::nothrow) ParticleSystemQuad();
if (ret && ret->initWithDictionary(dictionary))
{
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return ret;
}
2. 粒子紋理由FX.plist和FX.png 提供
給產生好的quad設定紋理
magic:setTextureWithRect(magicf:getTexture(), magicf:getRect())
3. 關於控制台的error在調試的時候,控制台一直在報bug,於是乎就去看了下源碼的時下,順便瞧瞧lua函數ParticleSystemQuad:create的重載是怎麼實現的
error:
cc.ParticleSystemQuad:create argument #2 is 'table'; 'string' expected.
int lua_cocos2dx_ParticleSystemQuad_create(lua_State* tolua_S){ int argc = 0; bool ok = true;#if COCOS2D_DEBUG >= 1 tolua_Error tolua_err;#endif#if COCOS2D_DEBUG >= 1 if (!tolua_isusertable(tolua_S,1,"cc.ParticleSystemQuad",0,&tolua_err)) goto tolua_lerror;#endif argc = lua_gettop(tolua_S)-1; do { if (argc == 1) { std::string arg0; ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.ParticleSystemQuad:create"); if (!ok) { break; } cocos2d::ParticleSystemQuad* ret = cocos2d::ParticleSystemQuad::create(arg0); object_to_luaval<cocos2d::ParticleSystemQuad>(tolua_S, "cc.ParticleSystemQuad",(cocos2d::ParticleSystemQuad*)ret); return 1; } } while (0); ok = true; do { if (argc == 0) { cocos2d::ParticleSystemQuad* ret = cocos2d::ParticleSystemQuad::create(); object_to_luaval<cocos2d::ParticleSystemQuad>(tolua_S, "cc.ParticleSystemQuad",(cocos2d::ParticleSystemQuad*)ret); return 1; } } while (0); ok = true; do { if (argc == 1) { cocos2d::ValueMap arg0; ok &= luaval_to_ccvaluemap(tolua_S, 2, &arg0, "cc.ParticleSystemQuad:create"); if (!ok) { break; } cocos2d::ParticleSystemQuad* ret = cocos2d::ParticleSystemQuad::create(arg0); object_to_luaval<cocos2d::ParticleSystemQuad>(tolua_S, "cc.ParticleSystemQuad",(cocos2d::ParticleSystemQuad*)ret); return 1; } } while (0); ok = true;
看了源碼重載的思路就比較清晰了:先判斷參數個數,再對通過函數luaval_to_std_string對L棧裡的參數分別進行嘗試性得取,直到某個類型正確取到值
ok &= luaval_to_std_string(tolua_S, 2,&arg0, "cc.ParticleSystemQuad:create");
而error log就是在嘗試得過程中函數 luaval_to_native_err 報出來的
if (!tolua_iscppstring(L,lo,0,&tolua_err)) {#if COCOS2D_DEBUG >=1 luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);#endif ok = false; }
稍微想一下,其實這段代碼是可以最佳化的嘛,可以先把所有要嘗試分支都試試,如果都沒有正確再報錯。
[manager]
維護了所有的角色對象,主要負責處理碰撞事件
collisionDetect 幀迴圈
collision(sprite)->solveCollision
確保兩個角色之間的距離小於兩者"腰圍" _radius之合,並且根據兩者"體重" _mass 計算彈開的距離
isOutOfBound(sprite) 確保角色不會出螢幕
G =
{
winSize = cc.Director:getInstance():getWinSize(),
bloodPercentDropSpeed = 2,
activearea = {left = -2800, right = 1000, bottom = 100, top = 700},
}
getFocusPointOfHeros 擷取英雄的“平均位置” 作為攝像機焦點
參考:
《粒子》