接下来要处理武器层逻辑,即要开始进行战斗系统开发。关于状态转换,前面我们写好的状态机框架已经足够,接下来最基础的便是伤害判定。
思路分析 首先我们整个框架采用了类似MVC思想的架构,模型层、控制器、武器层分开。武器层要处理的是伤害判定,模型层处理动画事件的一些逻辑,角色控制层则书写整个伤害逻辑。 首先,项目运行时,会以“控制器层——模型层——武器层”的顺序执行Init方法初始化。当攻击进行时,首先模型层会触发动画事件:StartSkillHit函数,模型层又会相应地调用控制层的伤害逻辑代码、以及开启武器层的伤害判定逻辑。
代码示例 武器层代码
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); } } } }
模型层代码
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 }
控制器层代码
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) { } }
其它代码
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 { }