using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
///
/// 角色控制器
///
public class PlayerController : MonoBehaviour
{
#region 序列化
public Rigidbody[] m_RigsToLift;
public ConstantForce m_LeftKneeForce;
public ConstantForce m_RightKneeForce;
[Header("Gravity")]
public Vector3 m_ExtraGravity;
[Header("TurnBody")]
public float m_TorqueForce;
[Header("Stand")]
public float m_StandHeight;
public float m_StandUpForceMultiplier;
public AnimationCurve m_StandUpForceCurve;
[Header("Move")]
public float m_HorizontalMoveForce;
public float m_JumpForce;
public float m_SwitchLegInterval;
public float m_LegAngle;
public float m_TorsoForce;
[Header("动画")]
public JointAnimation m_MoveAnimation;
#endregion
#region 公有字段
[NonSerialized] public CharacterInformation info;
public Vector3 forward
{
get
{
return -transform.forward;
}
}
#endregion
#region 私有字段
private Rigidbody[] m_AllRigidBodies;
private Rigidbody m_HipRigidBody;
private Rigidbody m_HeadRigidBody;
private Rigidbody m_TorsoRigidBody;
private Rigidbody m_LegLeftRigidBody;
private Rigidbody m_LegRightRigidBody;
private Quaternion m_TowardDirection; // 朝向角度
private bool m_LastMove;
private bool m_DoJump;
private bool m_DoMoveLeft;
private bool m_DoMoveRight;
private float m_StepSwitchTimer;
private bool m_IsLeftForward;
private float m_FallenGravityFactor;
#endregion
private void Awake()
{
InitRigidBodies();
m_HipRigidBody = transform.Find("Rigidbodies/Hip").GetComponent();
m_HeadRigidBody = transform.Find("Rigidbodies/Head").GetComponent();
m_TorsoRigidBody = transform.Find("Rigidbodies/Torso").GetComponent();
m_LegLeftRigidBody = transform.Find("Rigidbodies/Leg_Left").GetComponent();
m_LegRightRigidBody = transform.Find("Rigidbodies/Leg_Right").GetComponent();
info = GetComponent();
m_TowardDirection = Quaternion.Euler(0, -90, 0);
m_DoJump = false;
m_LastMove = false;
}
private void Update()
{
m_DoMoveLeft = false;
m_DoMoveRight = false;
if (Input.GetKey(KeyCode.A))
{
m_TowardDirection = Quaternion.Euler(0, -90, 0);
}
if (Input.GetKey(KeyCode.D))
{
m_TowardDirection = Quaternion.Euler(0, 90, 0);
}
if (Input.GetKeyDown(KeyCode.W))
{
m_DoJump = true;
}
if (Input.GetKey(KeyCode.A))
{
m_DoMoveLeft = true;
}
if (Input.GetKey(KeyCode.D))
{
m_DoMoveRight = true;
}
m_StepSwitchTimer += Time.deltaTime;
if(m_StepSwitchTimer > m_SwitchLegInterval && Vector3.Angle(m_LegLeftRigidBody.transform.up, m_LegRightRigidBody.transform.up) > m_LegAngle)
{
m_IsLeftForward = !m_IsLeftForward;
m_StepSwitchTimer = m_StepSwitchTimer - m_SwitchLegInterval;
}
}
private void FixedUpdate()
{
StandUp();
TurnBody();
OnMove();
}
private void OnMove()
{
if (!(m_DoMoveLeft || m_DoMoveRight || m_DoJump))
{
m_LastMove = false;
return;
}
//if (info.sinceTurn != 0)
//{
// return;
//}
if (!m_LastMove) // enter move
{
m_StepSwitchTimer = 0;
m_LastMove = true;
}
m_MoveAnimation.Animate();
if(m_DoMoveLeft)
{
MoveLeft();
}
if (m_DoMoveRight)
{
MoveRight();
}
if (m_DoJump)
{
Jump();
m_DoJump = false;
}
}
void MoveLeft()
{
DoActionToAllRigidbodies((rig, i) => {
rig.AddForce(Vector3.left * m_HorizontalMoveForce * Time.fixedDeltaTime, ForceMode.Acceleration);
});
m_TorsoRigidBody.AddForce(Vector3.left * m_TorsoForce, ForceMode.Force);
}
void MoveRight()
{
DoActionToAllRigidbodies((rig, i) =>
{
rig.AddForce(Vector3.right * m_HorizontalMoveForce * Time.fixedDeltaTime, ForceMode.Acceleration);
});
m_TorsoRigidBody.AddForce(Vector3.right * m_TorsoForce, ForceMode.Force);
}
void Jump()
{
if(info.isGrounded || info.sinceGrounded < 0.2f)
{
Debug.Log("Jump");
DoActionToAllRigidbodies((rig) => {
rig.AddForce(Vector3.up * m_JumpForce * Time.fixedDeltaTime, ForceMode.VelocityChange);
});
}
}
private void StandUp()
{
if (!info.isGrounded) // air
{
m_FallenGravityFactor += Time.fixedDeltaTime;
//m_FallenGravityFactor = Mathf.Clamp(m_FallenGravityFactor, 0, 1);
ApplyExtraGravity();
}
else // grounded
{
m_FallenGravityFactor = 0;
//Vector3 standUpForce = m_StandUpForce * Vector3.up * (m_StandHeight - info.shortestDistanceFromHeadToGround);
float headHeight = info.HeadRayCast();
if(headHeight < m_StandHeight)
{
float t = 1 - (m_StandHeight - headHeight) / m_StandHeight;
t = Mathf.Clamp(t, 0, 1);
//Debug.Log(t);
Vector3 standUpForce = m_StandUpForceMultiplier * m_StandUpForceCurve.Evaluate(t) * Vector3.up;
for (int i = 0; i < m_RigsToLift.Length; i++)
{
m_RigsToLift[i].AddForce(info.GetTotalMass() * standUpForce + info.GetTotalMass() * -Physics.gravity, ForceMode.Force);
}
}
}
if(info.sinceGrounded < 0.3f)
{
m_LeftKneeForce.enabled = true;
m_RightKneeForce.enabled = true;
}
else
{
m_LeftKneeForce.enabled = false;
m_RightKneeForce.enabled = false;
}
}
private void TurnBody()
{
Vector3 properForward = m_TowardDirection * -Vector3.forward;
float angel = Vector3.Angle(m_HipRigidBody.transform.forward, properForward);
Vector3 dir = Vector3.Cross(m_HipRigidBody.transform.forward, properForward);
if(Mathf.Abs(angel) < 5f)
{
info.sinceTurn = 0;
}
if(dir.y > 0)
{
m_HipRigidBody.AddTorque(Vector3.up * angel * m_TorqueForce, ForceMode.Acceleration) ;
}
else if(dir.y < 0)
{
m_HipRigidBody.AddTorque(-Vector3.up * angel * m_TorqueForce, ForceMode.Acceleration);
}
}
///
/// 初始化rigidbody
///
private void InitRigidBodies() //初始化刚体,编号
{
this.m_AllRigidBodies = base.GetComponentsInChildren();
DoActionToAllRigidbodies((rig, i) => {
});
IgnoreCollision();
}
///
/// 屏蔽身体各部件之间的碰撞
///
public void IgnoreCollision()
{
for (int i = 0; i < m_AllRigidBodies.Length - 1; i++)
{
for (int j = i + 1; j < m_AllRigidBodies.Length; j++)
{
Collider collider1 = m_AllRigidBodies[i].GetComponent();
Collider collider2 = m_AllRigidBodies[j].GetComponent();
Physics.IgnoreCollision(collider1, collider2, true);
}
}
}
private void ApplyExtraGravity()
{
DoActionToAllRigidbodies((rig) => {
rig.AddForce(m_ExtraGravity * m_FallenGravityFactor, ForceMode.Acceleration);
});
}
private void DoActionToAllRigidbodies(Action action)
{
DoActionToAllRigidbodies((rig, i) => {
action(rig);
});
}
private void DoActionToAllRigidbodies(Action action)
{
for (int i = 0; i < m_AllRigidBodies.Length; ++i)
{
if (action != null)
{
action(m_AllRigidBodies[i], i);
}
}
}
public bool StepLeft()
{
return m_IsLeftForward;
}
public bool StepRight()
{
return !m_IsLeftForward;
}
}