接下来要处理武器层逻辑,即要开始进行战斗系统开发。关于状态转换,前面我们写好的状态机框架已经足够,接下来最基础的便是伤害判定。

思路分析

首先我们整个框架采用了类似MVC思想的架构,模型层、控制器、武器层分开。武器层要处理的是伤害判定,模型层处理动画事件的一些逻辑,角色控制层则书写整个伤害逻辑。

首先,项目运行时,会以“控制器层——模型层——武器层”的顺序执行Init方法初始化。当攻击进行时,首先模型层会触发动画事件:StartSkillHit函数,模型层又会相应地调用控制层的伤害逻辑代码、以及开启武器层的伤害判定逻辑。

代码示例

武器层代码

plaintext
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
49
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Weapon_Controller : MonoBehaviour
{
// 拖入碰撞体来编辑
[SerializeField] private new Collider collider;
private List<string> enemyTagList;
private List<IHurt> enemyList = new List<IHurt>();
private Action<IHurt, Vector3> OnHitAction;

//初始化时传入敌人列表、受伤事件
public void Init(List<string> enemyList, Action<IHurt, Vector3> OnHitAction)
{
collider.enabled = false;
this.enemyTagList = enemyList;
this.OnHitAction = OnHitAction;
}

public void StartSkillHit()
{
collider.enabled = true;
}

public void StopSkillHit()
{
collider.enabled=false;
enemyList.Clear();
}

private void OnTriggerStay(Collider other)
{
//打击对象标签
if(enemyTagList.Contains(other.tag))
{
IHurt enemy = other.GetComponentInParent<IHurt>();
if (enemy != null && !enemyList.Contains(enemy))
{
Debug.Log("攻击到了");
//通知模型层处理这些
OnHitAction?.Invoke(enemy,other.ClosestPoint(transform.position));
enemyList.Add(enemy);
}
}
}
}

模型层代码

plaintext
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player_Model : MonoBehaviour
{
public Animator Animator;
private ISkillOwner skillOwner;
[SerializeField] Weapon_Controller[] weapons;
private void Awake()
{
if (Animator == null) Debug.Log("你忘记托Aniamto组件啦");
Animator.applyRootMotion = true;
}

public void Init(ISkillOwner skillOwner, List<string> enemyList)
{
//获得战斗宿主
this.skillOwner = skillOwner;
for(int i = 0; i < weapons.Length; i++)
{
//初始化武器,传入敌人列表和事件
weapons[i].Init(enemyList, skillOwner.OnHit);
}
}

#region 根运动
private Action<Vector3, Quaternion> rootMotionAction;
//注册根运动
//这里的逻辑是,每次自动执行OnAnimatorMove函数传入跟运动数据,从而调用外部函数,Action只是个桥梁用于接收外部方法
public void SetRootMotionAction(Action<Vector3, Quaternion> rootMotionAction)
{
this.rootMotionAction = rootMotionAction;
}
public void ClearRootMotionAction()
{
this.rootMotionAction = null;
}


//动画本身有数据、且播放会自动调用,自动填充动画数据
private void OnAnimatorMove()
{
rootMotionAction?.Invoke(Animator.deltaPosition,Animator.deltaRotation);
}
#endregion

# region 动画事件
private void FootStep()
{
GamePoolManager.MainInstance.TryGetPoolItem("Walk");
}

private void RunStep()
{
GamePoolManager.MainInstance.TryGetPoolItem("Run");
}

//技能
private void StartSkillHit(int weaponIndex)
{
//技能执行,还没写具体技能执行要干嘛
skillOwner.StartSkillHit(weaponIndex);
//开第几把武器执行碰撞检测等逻辑
weapons[weaponIndex].StartSkillHit();
}

private void StopSkillHit(int weaponIndex)
{
skillOwner.StopSkillHit(weaponIndex);
weapons[weaponIndex].StopSkillHit();
}

private void SkillCanSwitch()
{
skillOwner.SkillCanSwitch();
}
#endregion
}

控制器层代码

plaintext
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour, StateMachineOwner,ISkillOwner,IHurt
{
//拖入角色模型
[SerializeField] private Player_Model player_Model;
//访问模型层接口
public Player_Model Model { get =>player_Model; }

//引入角色控制器
[SerializeField] private CharacterController character_Controller;
public CharacterController CharacterController { get => character_Controller; }
private StateMachine stateMachine;

[Header("配置信息")]
public float gravity = 9.8f;
public float rotateSpeed = 5f;
public float walk2runSpeed = 2f;
public float walkSpeed = 1f;
public float runSpeed = 1f;
public float groundCheckDistance = 1.5f;
public List<string> enemyList;

[HideInInspector]public Vector3 currentSpeed;
//初始化状态机
private void Start()
{
stateMachine = new StateMachine();
stateMachine.Init(this);
//初始化模型层
Model.Init(this,enemyList);
//注册默认状态
ChangeState(PlayerState.Idle);
}
//提供模型层播放动画的方法
public void PlayAnimation(string animation, float fixedtime = 0.25f)
{
player_Model.Animator.CrossFadeInFixedTime(animation, fixedtime);
}

//提供改变状态的方法,利用枚举
public void ChangeState(PlayerState state)
{
switch (state)
{
case (PlayerState.Idle):
stateMachine.ChangeState<Player_IdleState>();
break;
case(PlayerState.Move):
stateMachine.ChangeState<Player_MoveState>();
break;
case(PlayerState.Jump):
stateMachine.ChangeState<Player_JumpState>();
break;
case(PlayerState.AirDown):
stateMachine.ChangeState<Player_AirDownState>();
break;
case(PlayerState.Roll):
stateMachine.ChangeState<Player_RollState>();
break;
case(PlayerState.Attack):
stateMachine.ChangeState<Player_AttackState>();
break;
}
}

//清除移动速度
public void ClearCurrentSpeed()
{
currentSpeed = Vector3.zero;
}

//实现ISkillOwner

public void StartSkillHit(int weaponIndex)
{

}

public void StopSkillHit(int weaponIndex)
{

}

public void SkillCanSwitch()
{

}

public void OnHit(IHurt target, Vector3 hitPosition)
{

}
}

其它代码

plaintext
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ISkillOwner
{
void StartSkillHit(int weaponIndex)
{

}

void StopSkillHit(int weaponIndex)
{

}

void SkillCanSwitch()
{

}

void OnHit(IHurt target,Vector3 hitPosition)
{

}
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//可以受伤的单位都挂
public interface IHurt
{

}