重构前,我的控制器是这样子
Assets/MeowACT/Scripts/ThirdPerson/ThirdPerson.cs
using Cinemachine;
using UnityEngine;
namespace MeowACT
{
public class ThirdPerson : MonoBehaviour
{
public CharacterController CharacterCtr;
public Animator Anim;
public MeowACTInputController Input;
public GameObject CMCameraFollowTarget;
public GameObject PlayerFollowCamera;
public Camera MainCamera;
public GameObject BattleGUI;
public ThirdPersonAttributeManager AttributeManager;
public ThirdPersonEventManager EventManager;
private ThirdPersonActionController actionController;
private ThirdPersonLocomotionController locomotionController;
private ThirdPersonAnimationController animationController;
private ThirdPersonBattleController battleController;
private ThirdPersonUIController uiController;
private void Awake()
{
CharacterCtr = GetComponent<CharacterController>();
Anim = GetComponent<Animator>();
Input = gameObject.AddComponent<MeowACTInputController>();
CMCameraFollowTarget = transform.Find("PlayerCameraRoot").gameObject;
PlayerFollowCamera = GameObject.Find("PlayerFollowCamera");
PlayerFollowCamera.GetComponent<CinemachineVirtualCamera>().Follow = CMCameraFollowTarget.transform;
MainCamera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
BattleGUI = transform.Find("BattleGUI").gameObject;
BattleGUI.GetComponent<Canvas>().worldCamera = MainCamera;
BattleGUI.GetComponent<Canvas>().planeDistance = 1;
AttributeManager = new ThirdPersonAttributeManager(this);
EventManager = new ThirdPersonEventManager(this);
actionController = new ThirdPersonActionController(this);
locomotionController = new ThirdPersonLocomotionController(this);
animationController = new ThirdPersonAnimationController(this);
battleController = new ThirdPersonBattleController(this);
uiController = new ThirdPersonUIController(this);
animationController.AssignAnimationIDs();
AttributeManager.Init();
}
protected void Update()
{
actionController.TryAction();
locomotionController.ApplyGravity();
locomotionController.GroundedCheck();
locomotionController.Move();
locomotionController.RotateToMoveDir();
animationController.SetAnimatorValue();
}
protected void LateUpdate()
{
locomotionController.CameraRotate();
}
private void OnControllerColliderHit(ControllerColliderHit hit)
{
if (AttributeManager.canPush) PhysicsUtility.PushRigidBodies(hit, AttributeManager.pushLayers, AttributeManager.strength);
}
public void OnTryDoDamageAnimEvent()
{
EventManager.Fire("TryDoDamageEvent", null);
Debug.Log("OnTryDoDamageAnimEvent");
}
public void OnEndMeleeAttackAnimEvent()
{
actionController.FireEndMeleeAttackEvent();
Debug.Log("OnEndMeleeAttackAnimEvent");
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonActionController.cs
using UnityEngine;
namespace MeowACT
{
public class ThirdPersonActionController
{
public ThirdPerson Owner;
private float sprintTimeout = 0.5f;
private float attackTimeout = 1f;
public ThirdPersonActionController(ThirdPerson owner)
{
Owner = owner;
}
public void TryAction()
{
if(TrySprint())
return;
TryMeleeAttack();
}
private bool TrySprint()
{
if (Owner.Input.Sprint && !Owner.AttributeManager.IsSprinting && !Owner.AttributeManager.IsFreezingMove)
{
FireBeginSprintEvent();
var cotimer = TimerSystemSingleton.SingleInstance.CreateCoTimer(0,
delegate(object[] args) { FireAfterBeginSprintEvent(); });
cotimer.Start();
var timer = TimerSystemSingleton.SingleInstance.CreateTimer(sprintTimeout, false,
delegate(object[] args) { FireEndSprintEvent(); });
timer.Start();
return true;
}
return false;
}
private bool TryMeleeAttack()
{
if (Owner.Input.Attack && !Owner.AttributeManager.IsMeleeAttacking)
{
FireBeginMeleeAttackEvent();
return true;
}
return false;
}
private void FireBeginSprintEvent()
{
Owner.AttributeManager.IsSprinting = true;
Owner.AttributeManager.IsSprintBegin = true;
Owner.AttributeManager.IsSuperArmor = true;
Owner.AttributeManager.NRG -= Owner.AttributeManager.SprintCost;
Owner.EventManager.Fire("BeginSprintEvent", null);
}
private void FireAfterBeginSprintEvent()
{
Owner.AttributeManager.IsSprintBegin = false;
Owner.EventManager.Fire("AfterBeginSprintEvent", null);
}
private void FireEndSprintEvent()
{
Owner.AttributeManager.IsSprinting = false;
Owner.AttributeManager.IsSuperArmor = true;
Owner.EventManager.Fire("EndSprintEvent", null);
}
private void FireBeginMeleeAttackEvent()
{
Owner.AttributeManager.IsMeleeAttacking = true;
Owner.AttributeManager.IsFreezingMove = true;
Owner.AttributeManager.NRG -= Owner.AttributeManager.MeleeAttackCost;
Owner.EventManager.Fire("BeginMeleeAttackEvent", null);
}
public void FireEndMeleeAttackEvent()
{
Owner.AttributeManager.IsMeleeAttacking = false;
Owner.AttributeManager.IsFreezingMove = false;
Owner.EventManager.Fire("EndMeleeAttackEvent", null);
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonAnimationController.cs
using UnityEngine;
namespace MeowACT
{
public class ThirdPersonAnimationController
{
public ThirdPerson Owner;
private int animIDSpeed;
private int animIDGrounded;
private int animIDFreeFall;
private int animIDMeleeAttack;
private float moveAnimBlend;
private float moveAnimBlendSmoothVelocity;
private float moveAnimBlendSmoothTime = 0.2f;
public ThirdPersonAnimationController(ThirdPerson owner)
{
Owner = owner;
Owner.EventManager.BeginMeleeAttackEvent += OnBeginMeleeAttackEvent;
}
~ThirdPersonAnimationController()
{
Owner.EventManager.BeginMeleeAttackEvent -= OnBeginMeleeAttackEvent;
}
public void AssignAnimationIDs()
{
animIDSpeed = Animator.StringToHash("ForwardSpeed");
animIDGrounded = Animator.StringToHash("Grounded");
animIDFreeFall = Animator.StringToHash("FreeFall");
animIDMeleeAttack = Animator.StringToHash("Attack");
}
public void SetAnimatorValue()
{
Owner.Anim.SetBool(animIDGrounded, Owner.AttributeManager.IsGrounded);
if (Owner.AttributeManager.IsGrounded)
Owner.Anim.SetBool(animIDFreeFall, false);
else
Owner.Anim.SetBool(animIDFreeFall, true);
moveAnimBlend = Mathf.SmoothDamp(moveAnimBlend, Owner.AttributeManager.HorizontalVelocity.magnitude, ref moveAnimBlendSmoothVelocity, moveAnimBlendSmoothTime);
Owner.Anim.SetFloat(animIDSpeed, moveAnimBlend);
}
private void OnBeginMeleeAttackEvent(object[] args)
{
Owner.Anim.SetTrigger(animIDMeleeAttack);
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonAttributeManager.cs
using UnityEngine;
namespace MeowACT
{
public class ThirdPersonAttributeManager
{
public LayerMask pushLayers;
public bool canPush;
[Range(0.5f, 5f)] public float strength = 1.1f;
public Vector3 HorizontalVelocity;
public Vector3 VerticalVelocity;
private float hp;
public float MaxHP = 100f;
public float HP
{
get => hp;
set
{
Owner.EventManager.Fire("OnHPChangeEvent", new object[]{hp/MaxHP, value/MaxHP});
hp = value;
}
}
private float nrg;
public float MaxNRG = 100f;
public float NRG
{
get => nrg;
set
{
Owner.EventManager.Fire("OnNRGChangeEvent", new object[]{nrg/MaxNRG, value/MaxNRG});
nrg = value;
}
}
public float SprintCost = 10f;
public float MeleeAttackCost = 10f;
public bool IsGrounded = true;
public bool IsFreezingMove = false;
public bool IsSprinting = false;
public bool IsSprintBegin = false;
public bool IsMeleeAttacking = false;
public bool IsSuperArmor = false;
public ThirdPerson Owner;
public ThirdPersonAttributeManager(ThirdPerson owner)
{
Owner = owner;
}
public void Init()
{
HP = MaxHP;
NRG = MaxNRG;
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonBattleController.cs
using UnityEngine;
namespace MeowACT
{
public class ThirdPersonBattleController
{
public ThirdPerson Owner;
public ThirdPersonBattleController(ThirdPerson owner)
{
Owner = owner;
Owner.EventManager.TryDoDamageEvent += TryDoDamage;
}
~ThirdPersonBattleController()
{
Owner.EventManager.TryDoDamageEvent -= TryDoDamage;
}
public void MeleeAttack()
{
}
private void TryDoDamage(object[] args)
{
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonEventManager.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace MeowACT
{
public class ThirdPersonEventManager
{
public event Action<object[]> BeginSprintEvent
{
add => eventMap["BeginSprintEvent"] = value;
remove => eventMap["BeginSprintEvent"] = value;
}
public event Action<object[]> AfterBeginSprintEvent
{
add => eventMap["AfterBeginSprintEvent"] = value;
remove => eventMap["AfterBeginSprintEvent"] = value;
}
public event Action<object[]> EndSprintEvent
{
add => eventMap["EndSprintEvent"] = value;
remove => eventMap["EndSprintEvent"] = value;
}
public event Action<object[]> BeginMeleeAttackEvent
{
add => eventMap["BeginMeleeAttackEvent"] = value;
remove => eventMap["BeginMeleeAttackEvent"] = value;
}
public event Action<object[]> EndMeleeAttackEvent
{
add => eventMap["EndMeleeAttackEvent"] = value;
remove => eventMap["EndMeleeAttackEvent"] = value;
}
public event Action<object[]> TryDoDamageEvent
{
add => eventMap["TryDoDamageEvent"] = value;
remove => eventMap["TryDoDamageEvent"] = value;
}
public event Action<object[]> EndComboEvent
{
add => eventMap["EndComboEvent"] = value;
remove => eventMap["EndComboEvent"] = value;
}
public event Action<object[]> OnHPChangeEvent
{
add => eventMap["OnHPChangeEvent"] = value;
remove => eventMap["OnHPChangeEvent"] = value;
}
public event Action<object[]> OnNRGChangeEvent
{
add => eventMap["OnNRGChangeEvent"] = value;
remove => eventMap["OnNRGChangeEvent"] = value;
}
public event Action<object[]> BeginNRGRecoverEvent
{
add => eventMap["BeginNRGRecoverEvent"] = value;
remove => eventMap["BeginNRGRecoverEvent"] = value;
}
public event Action<object[]> EndNRGRecoverEvent
{
add => eventMap["EndNRGRecoverEvent"] = value;
remove => eventMap["EndNRGRecoverEvent"] = value;
}
public UnityEvent<object[]> TestEvent;
private Dictionary<string, Action<object[]>> eventMap = new Dictionary<string, Action<object[]>>();
public ThirdPerson Owner;
public ThirdPersonEventManager(ThirdPerson owner)
{
Owner = owner;
eventMap.Add("BeginSprintEvent", null);
eventMap.Add("AfterBeginSprintEvent", null);
eventMap.Add("EndSprintEvent", null);
eventMap.Add("BeginMeleeAttackEvent", null);
eventMap.Add("EndMeleeAttackEvent",null);
eventMap.Add("TryDoDamageEvent", null);
eventMap.Add("EndComboEvent", null);
eventMap.Add("OnHPChangeEvent", null);
eventMap.Add("OnNRGChangeEvent", null);
eventMap.Add("BeginNRGRecoverEvent", null);
eventMap.Add("EndNRGRecoverEvent", null);
}
public void Fire(string eventName, object[] args)
{
eventMap[eventName]?.Invoke(args);
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonLocomotionController.cs
using UnityEngine;
namespace MeowACT
{
public class ThirdPersonLocomotionController
{
private const float Threshold = 0.01f;
private float walkSpeed = 7f;
private float rotationSmoothTime = 0.2f;
private float rotationSmoothVelocity;
private Vector3 walkSmoothVelocity;
private float walkSmoothTime = 0.2f;
private float sprintSpeed = 15f;
private Vector3 sprintSmoothVelocity;
private float sprintSmoothTime = 0.5f;
private float gravity = -9.8f;
private float terminalVelocity = 53f;
private float groundedOffset = -0.14f;
private float groundedRadius = 0.28f;
private int groundLayers = 1;
private float cameraAngleOverride = 0f;
private float cameraRotSpeed = 25f;
private float topClamp = 70f;
private float bottomClamp = -30f;
private float cinemachinePitchSmoothTime = 0.1f;
private float cinemachineYawSmoothTime = 0.1f;
private bool isCameraFixed = false;
private float cinemachineTargetPitch;
private float cinemachineTargetYaw;
private Vector2 cinemachineCurrPY;
private float cinemachinePitchSmoothVelocity;
private float cinemachineYawSmoothVelocity;
public ThirdPerson Owner;
public ThirdPersonLocomotionController(ThirdPerson owner)
{
Owner = owner;
}
public void GroundedCheck()
{
var spherePosition = new Vector3(Owner.transform.position.x, Owner.transform.position.y - groundedOffset, Owner.transform.position.z);
Owner.AttributeManager.IsGrounded = Physics.CheckSphere(spherePosition, groundedRadius, groundLayers, QueryTriggerInteraction.Ignore);
}
public void ApplyGravity()
{
if (Owner.AttributeManager.IsGrounded && Owner.AttributeManager.VerticalVelocity.y < 0.0f)
Owner.AttributeManager.VerticalVelocity.y = -2f;
else if (Owner.AttributeManager.VerticalVelocity.y < terminalVelocity)
Owner.AttributeManager.VerticalVelocity.y += gravity * Time.deltaTime;
}
public void Move()
{
if (Owner.AttributeManager.IsFreezingMove)
{
Owner.AttributeManager.HorizontalVelocity = Vector3.zero;
return;
}
Owner.AttributeManager.HorizontalVelocity = Owner.AttributeManager.IsSprinting ? GetSprintSpeed() : GetNormalSpeed();
Owner.CharacterCtr.Move((Owner.AttributeManager.HorizontalVelocity + Owner.AttributeManager.VerticalVelocity) * Time.deltaTime);
}
private Vector3 GetSprintSpeed()
{
Vector3 inputDirection = new Vector3(Owner.Input.Move.x, 0.0f, Owner.Input.Move.y).normalized;
float targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg + cinemachineTargetYaw;
Vector3 targetDirection = Quaternion.Euler(0.0f, targetRotation, 0.0f) * Vector3.forward;
if (Owner.AttributeManager.IsSprintBegin)
{
if (Owner.Input.Move == Vector2.zero)
return Owner.transform.forward * sprintSpeed;
else
return targetDirection.normalized * sprintSpeed;
}
else
return Vector3.SmoothDamp(Owner.AttributeManager.HorizontalVelocity, Vector3.zero, ref sprintSmoothVelocity, sprintSmoothTime);
}
private Vector3 GetNormalSpeed()
{
Vector3 inputDirection = new Vector3(Owner.Input.Move.x, 0.0f, Owner.Input.Move.y).normalized;
float targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg + cinemachineTargetYaw;
Vector3 targetDirection = Quaternion.Euler(0.0f, targetRotation, 0.0f) * Vector3.forward;
Vector3 targetVelocity = (Owner.Input.Move == Vector2.zero) ? Vector3.zero : targetDirection * walkSpeed;
return Vector3.SmoothDamp(Owner.AttributeManager.HorizontalVelocity, targetVelocity, ref walkSmoothVelocity, walkSmoothTime);
}
public void RotateToMoveDir()
{
Vector3 inputDirection = new Vector3(Owner.Input.Move.x, 0.0f, Owner.Input.Move.y).normalized;
if (Owner.Input.Move != Vector2.zero)
{
float targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg + Owner.MainCamera.transform.eulerAngles.y;
float rotation = Mathf.SmoothDampAngle(Owner.transform.eulerAngles.y, targetRotation, ref rotationSmoothVelocity, rotationSmoothTime);
Owner.transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
}
public void CameraRotate()
{
if (Owner.Input.Look.sqrMagnitude >= Threshold && !isCameraFixed)
{
cinemachineTargetPitch += Owner.Input.Look.y * Time.deltaTime * cameraRotSpeed / 100.0f;
cinemachineTargetYaw += Owner.Input.Look.x * Time.deltaTime * cameraRotSpeed / 100.0f;
}
cinemachineTargetPitch = MathUtility.ClampAngle(cinemachineTargetPitch, bottomClamp, topClamp);
cinemachineTargetYaw = MathUtility.ClampAngle(cinemachineTargetYaw, float.MinValue, float.MaxValue);
cinemachineCurrPY.x = Mathf.SmoothDampAngle(cinemachineCurrPY.x, cinemachineTargetPitch,
ref cinemachinePitchSmoothVelocity, cinemachinePitchSmoothTime);
cinemachineCurrPY.y = Mathf.SmoothDampAngle(cinemachineCurrPY.y, cinemachineTargetYaw,
ref cinemachineYawSmoothVelocity, cinemachineYawSmoothTime);
Owner.CMCameraFollowTarget.transform.rotation = Quaternion.Euler(cinemachineCurrPY.x + cameraAngleOverride, cinemachineCurrPY.y, 0.0f);
}
}
}
Assets/MeowACT/Scripts/ThirdPerson/ThirdPersonUIController.cs
using UnityEngine;
namespace MeowACT
{
public class ThirdPersonUIController
{
public ThirdPerson Owner;
private UIBar hpBar;
private UIBar nrgBar;
public ThirdPersonUIController(ThirdPerson owner)
{
Owner = owner;
hpBar = Owner.transform.Find("HPBarRoot").Find("UIBar").GetComponent<UIBar>();
if(hpBar == null)
Debug.LogError("玩家 Perfab 身上没有血条");
nrgBar = Owner.transform.Find("NRGBarRoot").Find("UIBar").GetComponent<UIBar>();
if(nrgBar == null)
Debug.LogError("玩家 Perfab 身上没有体力条");
Owner.EventManager.OnHPChangeEvent += UpdateHPBar;
Owner.EventManager.OnNRGChangeEvent += UpdateNRGBar;
}
~ThirdPersonUIController()
{
Owner.EventManager.OnHPChangeEvent -= UpdateHPBar;
Owner.EventManager.OnNRGChangeEvent -= UpdateNRGBar;
}
private void UpdateHPBar(object[] args)
{
hpBar.SmoothValueAndShow((float) args[0], (float) args[1]);
}
private void UpdateNRGBar(object[] args)
{
nrgBar.SmoothValueAndShow((float)args[0], (float)args[1]);
}
}
}
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
namespace MeowACT
{
public class UIBar : MonoBehaviour
{
private const float AnimationDuration = 1f;
private const float AnimationSmoothTime = 0.2f;
private const float KeepSeconds = 0.4f;
private const float FadeOutDuration = 1f;
private const float FadeOutSmoothTime = 0.2f;
[SerializeField] private Image fillImage;
private CanvasGroup canvasGroup;
public float FillAmount => fillImage.fillAmount;
private void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
{
Debug.LogError("UI 缺少画布组");
}
}
public void SmoothAddAndShow(float add)
{
SmoothValueAndShow(Mathf.Clamp(fillImage.fillAmount + add, 0, 1));
}
public void SmoothValueAndShow(float toRatio)
{
SmoothValueAndShow(FillAmount, toRatio);
}
public void SmoothValueAndShow(float fromRatio, float toRatio)
{
fillImage.gameObject.SetActive(true);
StopAllCoroutines();
canvasGroup.alpha = 1f;
fillImage.fillAmount = fromRatio;
StartCoroutine(BarCo(toRatio, AnimationDuration, AnimationSmoothTime, KeepSeconds, FadeOutDuration,
FadeOutSmoothTime));
}
public void Reset()
{
StopAllCoroutines();
canvasGroup.alpha = 1f;
fillImage.fillAmount = 1f;
fillImage.gameObject.SetActive(false);
}
private IEnumerator BarCo(float value, float animationDuration, float animationSmoothTime, float keepDuration,
float fadeOutDuration, float fadeOutSmoothTime)
{
yield return fillImage.SmoothFillAmount(value, animationDuration, animationSmoothTime);
yield return new WaitForSeconds(keepDuration);
yield return canvasGroup.FadeToAlpha(0f, fadeOutDuration, fadeOutSmoothTime);
fillImage.gameObject.SetActive(false);
}
}
}
我是把逻辑全部都放到一个类里面了,从外面看就是
此外,UI,Animator,InputSetting 就不展示了
虽然我写得爽了,但是策划完全调不了
接下来要根据 ScriptableObject 的思想重构
|