技能伤害入口函数

技能伤害函数写在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,将之前的AttackEffectAttackDamage都合并到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);
}

SkillMgrAttackDamage里面应用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内部完成,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)
{
//获取场景中所有的怪物Entity
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,修改一下SkillMgrSkillAction

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];//skillaction的Index和skillDamage的Index一一对应
//获取场景中所有的怪物Entity
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配置中skillactionListskillDamageList是一一对应的,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……解析的

运算伤害

修改SkillMgrCalcDamage函数,增加伤害目标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中定义好BattlePropsHP

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
{
//通知UI
hp = value;
}
}
/// <summary>
/// 设置此Entity的战斗属性
/// </summary>
public virtual void SetBattleProps(BattleProps battleProps)
{
hp = battleProps.hp;
this.entityProps = battleProps;
}

BattleMgr中先给entityPalyerBattleProp赋值:

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);//+++
//...
}