技能伤害入口函数
技能伤害函数写在EntityBase
里面,转到SkillMgr
里面分担EntityBase
的逻辑,此函数被StateAttack
调用
EntityBase
:
1 2 3 4
| public virtual void AttackDamage(int skillID) { skillMgr.AttackDamage(this, skillID); }
|
SkillMgr
:
1 2 3 4
| public void AttackDamage(EntityBase entity,int skillID) {
}
|
StateAttack
:
1 2 3 4 5
| public void Process(EntityBase entity, params object[] args) { entity.AttackDamage((int)args[0]); entity.AttackEffect((int)args[0]); }
|
技能伤害点配置
在一次技能中,可能会造成多段伤害,我们将每段伤害称为一次“技能伤害点(skillAction
)”。
在skill.xml
增加skillAction
节点,这个节点指向当前skill的skillaction列表
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <item ID="101"> <skillName>穿刺</skillName> <skillTime>900</skillTime> <aniAction>1</aniAction> <fx>dagger_skill1</fx> <skillMoveList>1011</skillMoveList> <skillActionList>1011|1011</skillActionList> </item> </root>
|
增加skillaction
配置
1 2 3 4 5 6 7 8 9
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <item ID="1011"> <delayTime>100</delayTime> <radius>2.5</radius> <angle>360</angle> </item> <item/> </root>
|
注册技能点运算函数
优化技能伤害API,将之前的AttackEffect
和AttackDamage
都合并到SkillAttack
EntityBase
:
1 2 3 4
| public virtual void SkillAttack(int skillID) { skillMgr.SkillAttack(this, skillID); }
|
StateAttack
:
1 2 3 4
| public void Process(EntityBase entity, params object[] args) { entity.SkillAttack((int)args[0]); }
|
SkillMgr
:
1 2 3 4 5
| public void SkillAttacck(EntityBase entity,int skillID) { AttackDamage(entity,skillID); AttackEffect(entity,skillID); }
|
在SkillMgr
的AttackDamage
里面应用skillaction
的配置数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public void AttackDamage(EntityBase entity,int skillID) { SkillCfg skillCfg = resSvc.GetSkillCfg(skillID); List<int> skillActionList = skillCfg.skillActionList; int sum = 0; for (int i = 0; i < skillActionList.Count; i++) { SkillActionCfg skillActionCfg = resSvc.GetSkillActionCfg(skillActionList[i]); sum += skillActionCfg.delayTime; if(sum > 0) { timerSvc.AddTimeTask(tid => { SkillAction(entity, skillActionCfg.ID); }, sum); } else { SkillAction(entity,skillActionCfg.ID); } } } public void SkillAction(EntityBase entity, int actionID) {
}
|
伤害运算
在本例中,基于Entity的逻辑,伤害的运算都在Entity内部完成,Entity都是一个个独立的类,最好不使用Unity的触发器。
获取怪物Entity
我们的玩家Entity和怪物Entity都是在BattleMgr
里面创建的,我们在里面把创建的怪物Entity缓存起来,并返回给SkillMgr
修改BattleMgr
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| private Dictionary<string,EntityMonster> entityMonsterDic = new Dictionary<string,EntityMonster>(); public void LoadMonsterByWaveID(int waveID) { for (int i = 0; i < mapCfg.monsterList.Count; i++) { MonsterData md = mapCfg.monsterList[i]; if(md.mWave == waveID) { entityMonsterDic.Add(m.name, em); } } }
public List<EntityMonster> GetEntityMonsters() { List<EntityMonster> entityMonsters = new List<EntityMonster>(); foreach (var item in entityMonsterDic) { entityMonsters.Add(item.Value); } return entityMonsters; }
|
修改SkillMgr
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public void SkillAction(EntityBase entity, int actionID) { List<EntityMonster> entityMonsters = entity.battleMgr.GetEntityMonsters(); SkillActionCfg skillActionCfg = resSvc.GetSkillActionCfg(actionID); for (int i = 0; i < entityMonsters.Count; i++) { EntityMonster em = entityMonsters[i]; if(InRange(entity.GetPos(),em.GetPos(),skillActionCfg.radius) && InAngle(entity.GetTrans(),em.GetPos(),skillActionCfg.angle)) { } } } private void CalcDamage(EntityBase entity,int damage) {
} private bool InRange(Vector3 from,Vector3 to,float range) { float dis = Vector3.Distance(from, to); if (dis <= range) { return true; } return false; } private bool InAngle(Transform trans,Vector3 to,float angle) { if (angle == 360) { return true; } else { Vector3 start = trans.forward; Vector3 dir = (to - start).normalized;
float ang = Vector3.Angle(start, dir); if (ang <= angle / 2) { return true; } return false; } }
|
EntityBase
里面添加GetPos()
和GetTrans()
,返回对应Controller内部的值即可,这里省略
配置技能伤害数据
技能伤害数据指的是技能对角色本身数据的加成,伤害加成只是技能加成中的一部分,技能加成可能还包括增加暴击率等,这里只用伤害加成举例。
技能伤害数据是写在skill.xml
配置里的,我们的skillaction.xml
只保存技能的行为信息,这样能更好的复用skill action。
skill.xml
配置添加skillDamageList
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <item ID="101"> <skillName>穿刺</skillName> <skillTime>900</skillTime> <aniAction>1</aniAction> <fx>dagger_skill1</fx> <skillMoveList>1011</skillMoveList> <skillActionList>1011|1011</skillActionList> <skillDamageList>26|36</skillDamageList> </item> </root>
|
为了能拿到伤害数据,需要拿到skllCfg
,修改一下SkillMgr
的SkillAction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public void SkillAction(EntityBase entity,SkillCfg skillCfg,int skillAcIndex) { SkillActionCfg skillActionCfg = resSvc.GetSkillActionCfg(skillCfg.skillActionList[skillAcIndex]); int damage = skillCfg.skillDamageList[skillAcIndex]; List<EntityMonster> entityMonsters = entity.battleMgr.GetEntityMonsters(); for (int i = 0; i < entityMonsters.Count; i++) { EntityMonster em = entityMonsters[i]; if(InRange(entity.GetPos(),em.GetPos(),skillActionCfg.radius) && InAngle(entity.GetTrans(),em.GetPos(),skillActionCfg.angle)) { CalcDamage(entity, damage); } } } public void AttackDamage(EntityBase entity,int skillID) { SkillCfg skillCfg = resSvc.GetSkillCfg(skillID); List<int> skillActionList = skillCfg.skillActionList; int sum = 0; for (int i = 0; i < skillActionList.Count; i++) { SkillActionCfg skillActionCfg = resSvc.GetSkillActionCfg(skillActionList[i]); sum += skillActionCfg.delayTime; int index = i; if(sum > 0) { timerSvc.AddTimeTask(tid => { SkillAction(entity, skillCfg,index); }, sum); } else { SkillAction(entity,skillCfg,index); } } }
|
这里之所以要传递Index,是因为skill.xml
配置中skillactionList
和skillDamageList
是一一对应的,skillaction和skilldamage一一对应
技能配置增加伤害类型
在本例的设计中,物理攻击和魔法攻击是分开的,我们在技能配置中将dmgType
配置进去
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <item ID="101"> <skillName>穿刺</skillName> <skillTime>900</skillTime> <aniAction>1</aniAction> <fx>dagger_skill1</fx> <dmgType>1</dmgType> <skillMoveList>1011</skillMoveList> <skillActionList>1011|1011</skillActionList> <skillDamageList>26|36</skillDamageList> </item> </root>
|
在Constant
类中添加DamageType
1 2 3 4 5 6
| public enum DamageType { None, AD=1, AP=2, }
|
BaseData
中的SkillCfg
1 2 3 4 5 6 7 8 9 10 11
| public class SkillCfg : BaseData<SkillCfg> { public string skillName; public int skillTime; public int aniAction; public string fx; public DamageType dmgType; public List<int> skillMoveList; public List<int> skillActionList; public List<int> skillDamageList; }
|
这部分的解析使用element.InnerText.Equals("1")
再加if……else……
解析的
运算伤害
修改SkillMgr
的CalcDamage
函数,增加伤害目标entity和skillcfg参数
1
| private void CalcDamage(EntityBase caster,EntityBase target,SkillCfg skillCfg,int damage){}
|
BaseData
增加战斗用的BattleProps
,这个类不用继承BaseData
,其中包含了PlayerData
和MonsterData中用来战斗的数据,使用这个类是因为PlayerData
包含了太多的数据,在战斗中最好不要直接引用
1 2 3 4 5 6 7 8 9 10 11
| public class BattleProps { public int hp; public int ad; public int ap; public int addef; public int apdef; public int dodge; public int pierce; public int critical; }
|
在EntityBase
中定义好BattleProps
和HP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| private BattleProps entityProps; private int hp;
public BattleProps BattleProps { get { return entityProps; } protected set { entityProps = value; } } public int HP { get { return hp; } protected set { hp = value; } }
public virtual void SetBattleProps(BattleProps battleProps) { hp = battleProps.hp; this.entityProps = battleProps; }
|
在BattleMgr
中先给entityPalyer
的BattleProp
赋值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private void LoadPlayer(MapCfg mapCfg) {
PlayerData pd = GameRoot.Instance.PlayerData; BattleProps playerBatProps = new BattleProps { hp = pd.hp, ad = pd.ad, ap = pd.ap, addef = pd.addef, apdef = pd.apdef, dodge = pd.dodge, pierce = pd.pierce, critical = pd.critical, };
entitySelfPlayer = new EntityPlayer { battleMgr = this, stateMgr = stateMgr, skillMgr = skillMgr, }; entitySelfPlayer.SetBattleProps(playerBatProps); }
|