建筑学院app网站,杭州优化外包,微信小程序订货系统,诚信通与网站建设区别玩家控制脚本设计思路
1. 代码演变过程
1.1 初始阶段#xff1a;单一Player类实现
最初的设计可能是一个包含所有功能的Player类#xff1a;
public class Player : MonoBehaviour
{private CharacterController controller;private Animator animator;[SerializeField] …玩家控制脚本设计思路
1. 代码演变过程
1.1 初始阶段单一Player类实现
最初的设计可能是一个包含所有功能的Player类
public class Player : MonoBehaviour
{private CharacterController controller;private Animator animator;[SerializeField] private float speed 4f;private Vector3 move;private float gravity -9.81f;private Vector3 velocity;void Awake(){controller GetComponentCharacterController();animator GetComponentAnimator();}void Update(){HandleMovement();HandleGravity();}private void HandleMovement(){float horizontal Input.GetAxis(Horizontal);float vertical Input.GetAxis(Vertical);move new Vector3(horizontal, 0, vertical);// ... 其他移动逻辑}
}这种设计的问题
所有功能耦合在一起代码复用性差难以扩展新角色类型维护成本高
1.2 第一次重构提取基类
识别出通用功能创建抽象基类
public abstract class Character : MonoBehaviour
{protected CharacterController controller;protected Animator animator;[SerializeField] protected float speed 4f;protected Vector3 move;protected float gravity -9.81f;protected Vector3 velocity;protected virtual void Awake(){controller GetComponentCharacterController();animator GetComponentAnimator();}protected virtual void Update(){HandleMovement();}protected abstract void HandleMovement();
}1.3 当前架构功能模块化
1.3.1 Character基类最终版本
public abstract class Character : MonoBehaviour
{// 基础组件protected CharacterController controller;protected Animator animator;// 移动相关参数[SerializeField] protected float speed 4f;protected Vector3 move;// 物理相关参数protected float gravity -9.81f; protected Vector3 velocity; protected virtual void Awake(){controller GetComponentCharacterController();animator GetComponentAnimator();} protected virtual void Update(){HandleMovement();}// 抽象方法强制子类实现protected abstract void HandleMovement();
}1.3.2 Player类最终版本
public class Player : Character
{#region 移动系统[SerializeField] private float speedMax 6f;private float currentSpeed;private bool isShift;#endregion#region 跳跃系统private bool isGrounded;[SerializeField] private float jumpHeight 3f;[SerializeField] private LayerMask groundMask;[SerializeField] private Transform groundCheck;[SerializeField] private float groundDistance 0.15f;#endregion#region 攻击系统private bool isAttacking;private float lastAttackTime;#endregionprotected override void Update(){isGrounded Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);base.Update();HandleGravity();HandleAttack();}#region 移动系统实现protected override void HandleMovement(){if(isAttacking){move.Set(0, 0, 0);animator.SetFloat(Speed, 0);return;}// 基础移动输入float horizontal Input.GetAxis(Horizontal);float vertical Input.GetAxis(Vertical);move new Vector3(horizontal, 0, vertical);// 移动规范化if(move.magnitude 1f){move move.normalized;}// 45度视角调整move Quaternion.Euler(0, -45f, 0) * move;// 角色朝向if(move ! Vector3.zero){transform.rotation Quaternion.LookRotation(move);}// 冲刺系统HandleSprint();// 应用移动controller.Move(move * currentSpeed * Time.deltaTime);// 动画控制animator.SetFloat(Speed, move.magnitude);animator.SetBool(IsShift, isShift);}private void HandleSprint(){if(Input.GetKey(KeyCode.LeftShift)){currentSpeed speedMax;isShift true;}else {currentSpeed speed;isShift false;}}#endregion#region 重力系统实现private void HandleGravity(){animator.SetBool(isAir, !isGrounded);if(isGrounded Input.GetButtonDown(Jump)){velocity.y jumpHeight;}velocity.y gravity * Time.deltaTime;controller.Move(velocity * Time.deltaTime);}#endregion#region 战斗系统实现private void HandleAttack(){if(Input.GetButtonDown(Fire1)){if(!isAttacking){isAttacking true;animator.SetTrigger(Attack);}else{string triggerName animator.GetCurrentAnimatorClipInfo(0)[0].clip.name;float triggerProgress animator.GetCurrentAnimatorStateInfo(0).normalizedTime;// 连击系统if(triggerName ! LittleAdventurerAndie_ATTACK_03 triggerProgress 0.3f triggerProgress 0.7f){animator.SetTrigger(Attack);}}}}// 动画事件触发的特效public void PlayBlade01() VFXManager.instance.Play(Particle Sword Blade 01);public void PlayBlade02() VFXManager.instance.Play(Particle Sword Blade 02);public void PlayBlade03() VFXManager.instance.Play(Particle Sword Blade 03);private void OnAttackEnd(){isAttacking false;}#endregion
}2. 详细设计分析
2.1 基类设计要点 组件封装 将CharacterController和Animator组件封装在基类中使用protected访问级别允许子类直接访问在Awake中统一初始化 移动系统框架 定义基础移动变量speed, move, velocity提供抽象的HandleMovement()方法实现基础的Update循环 物理系统基础 封装重力相关参数提供基础的物理运动框架
2.2 Player类实现分析 移动系统 protected override void HandleMovement()
{// 1. 状态检查if(isAttacking) { ... }// 2. 输入处理float horizontal Input.GetAxis(Horizontal);float vertical Input.GetAxis(Vertical);// 3. 移动计算move new Vector3(horizontal, 0, vertical);// 4. 规范化处理if(move.magnitude 1f) { move move.normalized; }// 5. 视角调整move Quaternion.Euler(0, -45f, 0) * move;// 6. 朝向控制if(move ! Vector3.zero) { ... }// 7. 移动应用controller.Move(move * currentSpeed * Time.deltaTime);// 8. 动画更新animator.SetFloat(Speed, move.magnitude);
}跳跃系统 private void HandleGravity()
{// 1. 地面检测animator.SetBool(isAir, !isGrounded);// 2. 跳跃输入if(isGrounded Input.GetButtonDown(Jump)){velocity.y jumpHeight;}// 3. 重力应用velocity.y gravity * Time.deltaTime;controller.Move(velocity * Time.deltaTime);
}战斗系统 private void HandleAttack()
{// 1. 攻击输入检测if(Input.GetButtonDown(Fire1)){// 2. 状态检查if(!isAttacking){// 3. 开始攻击isAttacking true;animator.SetTrigger(Attack);}else{// 4. 连击处理string triggerName animator.GetCurrentAnimatorClipInfo(0)[0].clip.name;float triggerProgress animator.GetCurrentAnimatorStateInfo(0).normalizedTime;if(可以连击条件){animator.SetTrigger(Attack);}}}
}3. 系统交互
3.1 状态管理
移动状态与攻击状态互斥跳跃状态可以与其他状态叠加使用布尔值控制状态转换
3.2 动画系统
使用参数控制动画过渡 Speed: 控制移动动画IsShift: 控制冲刺动画isAir: 控制跳跃动画Attack: 触发攻击动画
3.3 特效系统
通过动画事件触发特效使用VFXManager统一管理特效播放
4. 总结
当前的代码架构展现了良好的面向对象设计原则
单一职责原则每个类和方法都有明确的职责开闭原则通过继承和抽象方法支持扩展里氏替换原则子类可以替换父类而不影响程序正确性
后续优化方向
引入状态模式管理角色状态使用事件系统解耦模块间通信将配置数据抽离到ScriptableObject优化性能关键点