项目GitHub仓库地址:
https://github.com/m969/EGamePlay
战斗行动
-
我们抽象出一个战斗行动 CombatAction 的概念,我们将造成伤害、给予治疗、赋给效果、施放技能等由战斗实体发起的操作称为战斗行动。
-
越是复杂的战斗越是会在这些战斗行动的过程中插入各种效果和计算,如果只是简单的用一套方法调用走下来的话,我们后期会很难抉择某个效果是应该写在这个方法里还是写在那个方法里,是应该写在攻击者的流程里还是应该写在受击者的流程里。无论写在哪里都可能会有些许的别扭、不优雅。
-
抽象出这个战斗行动概念后,我们就可以把这些纠结的效果和计算放进战斗行动里,这样更加优雅,流程更清晰。
-
CombatAction独立于战斗实体,存储着此次战斗行动所需要用到的所有数据,并持有相关战斗实体的引用。
[
LabelText
(
"行动类型"
)
]
public
enum
ActionType
{
[
LabelText
(
"施放技能"
)
]
SpellSkill
,
[
LabelText
(
"造成伤害"
)
]
CauseDamage
,
[
LabelText
(
"给予治疗"
)
]
GiveCure
,
[
LabelText
(
"赋给效果"
)
]
AssignEffect
,
}
/// <summary>
/// 战斗行动概念,造成伤害、治疗英雄、赋给效果等属于战斗行动,需要继承自CombatAction
/// 战斗行动由战斗实体主动发起,包含本次行动所需要用到的所有数据,并且会触发一系列行动点事件
/// </summary>
public
class
CombatAction
{
public
ActionType
ActionType
{
get
;
set
;
}
public
CombatEntity
Creator
{
get
;
set
;
}
public
CombatEntity
Target
{
get
;
set
;
}
public
virtual
void
ApplyAction
(
)
{
}
}
-
伤害行动示例:
/// <summary>
/// 伤害行动
/// </summary>
public
class
DamageAction
:
CombatAction
{
//伤害公式
public
string
Formula
{
get
;
set
;
}
//伤害数值
public
int
DamageValue
{
get
;
set
;
}
//前置处理
private
void
PreProcess
(
)
{
DamageValue
=
int
.
Parse
(
Formula
)
;
}
//应用伤害
public
void
ApplyDamage
(
)
{
PreProcess
(
)
;
Target
.
ReceiveDamage
(
this
)
;
PostProcess
(
)
;
}
//后置处理
private
void
PostProcess
(
)
{
//触发 造成伤害后 行动点
Creator
.
TriggerActionPoint
(
ActionPointType
.
PostCauseDamage
,
this
)
;
//触发 承受伤害后 行动点
Target
.
TriggerActionPoint
(
ActionPointType
.
PostReceiveDamage
,
this
)
;
}
}
行动点
-
一次战斗行动CombatAction会经过并触发相关战斗实体一系列行动点 ActionPoint 。
-
比如一次造成伤害的战斗行动会触发攻击者 造成伤害行动点 和受击者的 承受伤害行动点 ,一次给予治疗的战斗行动会触发施术者 给予治疗行动点 和受术者 接受治疗行动点 。 ``` /// <summary> /// 行动点,一次战斗行动会触发战斗实体一系列的行动点 /// </summary> public sealed class ActionPoint {
public
List
<
Action
<
CombatAction
>
>
Listeners
{
get
;
set
;
}
=
new
List
<
Action
<
CombatAction
>
>
(
)
;
-
}
-
/// <summary> /// 行动点类型 /// </summary> public enum ActionPointType {
PreCauseDamage
,
//造成伤害前
PreReceiveDamage
,
//承受伤害前
PostCauseDamage
,
//造成伤害后
PostReceiveDamage
,
//承受伤害后
-
}
-
/// <summary> /// 行动点管理器,在这里管理一个战斗实体所有行动点的添加监听、移除监听、触发流程 /// </summary> public sealed class ActionPointManager {
private
Dictionary
<
ActionPointType
,
ActionPoint
>
ActionPoints
{
get
;
set
;
}
=
new
Dictionary
<
ActionPointType
,
ActionPoint
>
(
)
;
public
void
Initialize
(
)
{
ActionPoints
.
Add
(
ActionPointType
.
PostCauseDamage
,
new
ActionPoint
(
)
)
;
ActionPoints
.
Add
(
ActionPointType
.
PostReceiveDamage
,
new
ActionPoint
(
)
)
;
}
public
void
AddListener
(
ActionPointType
actionPointType
,
Action
<
CombatAction
>
action
)
{
ActionPoints
[
actionPointType
]
.
Listeners
.
Add
(
action
)
;
}
public
void
RemoveListener
(
ActionPointType
actionPointType
,
Action
<
CombatAction
>
action
)
{
ActionPoints
[
actionPointType
]
.
Listeners
.
Remove
(
action
)
;
}
public
void
TriggerActionPoint
(
ActionPointType
actionPointType
,
CombatAction
action
)
{
foreach
(
var
item
in
ActionPoints
[
actionPointType
]
.
Listeners
)
{
item
.
Invoke
(
action
)
;
}
}
}
```
世界法则
-
为了便于理解战斗行动这个概念,这里引入一个世界法则的理念。
-
我们要明确伤害行动和技能行动等都是凌驾于战斗实体之上的法则行动,这些行动的结果由游戏世界的规则法则决定,而不由战斗实体决定。
-
就比如你赤手重拳出击,你这一击是对敌人造成伤害还是对自己造成伤害取决于你攻击的对象,你自己是没有办法决定的。如果你攻击的是一个鸡蛋,那么鸡蛋会被打碎而你毫发无伤,但如果你攻击的是一个铁球,那么结果会变成铁球毫发无伤而你痛得甩手。这就是现实世界的法则。
-
战斗实体发起战斗行动,游戏世界法则决定行动的结果。
往期文章:
-
如何实现一个灵活、通用的战斗(技能)系统——序章
-
如何实现一个灵活、通用的战斗(技能)系统——数值系统
-
如何实现一个灵活、通用的战斗(技能)系统——数值系统(升级版)
827

被折叠的 条评论
为什么被折叠?



