WXMC/.svn/pristine/d3/d3ae1efe8bfbc04fe0760f939d7cb742e7f1965d.svn-base

217 lines
5.4 KiB
Plaintext
Raw Normal View History

2024-12-04 16:18:46 +08:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysicsMovement : MonoBehaviour
{
#region Define
public const float OnGroundTestLength = 0.02f;
public const float OnGroundTestShiftLength = 0.02f;
[System.Serializable]
public struct AccelerationBindSetting
{
public PhysicMaterial OtherMaterial;
public AccelerationSetting Setting;
}
[System.Serializable]
public struct AccelerationSetting
{
public float DestAcc;
public float DragAcc;
}
#endregion
#region Interface
public Vector3 DestVelocity
{
get => m_destVelocity;
set
{
m_destVelocity = value;
}
}
public bool IsOnGround
{
get
{
return m_dummyHitted;
}
}
#endregion
#region Setting
public AccelerationSetting InAirAccSetting;
public AccelerationSetting DefaultGroundAccSetting;
public List<AccelerationBindSetting> AdditionalGroundSettings;
#endregion
#region Movement
private AccelerationSetting GetCurrentAccSetting()
{
if (!m_dummyHitted)
{
return InAirAccSetting;
}
else
{
if (m_settingsDic.ContainsKey(m_dummyHit.collider.material))
{
return m_settingsDic[m_dummyHit.collider.material];
}
else
{
return DefaultGroundAccSetting;
}
}
}
private Vector3 CalcYAxis(Vector3 xaxis)
{
Vector3 result;
result.y = xaxis.y;
// Rotate 90 deg
result.x = -xaxis.z;
result.z = xaxis.x;
return result;
}
private float CalcProjLength(Vector3 dest, Vector3 fromProj)
{
return Vector3.Dot(fromProj, dest) / dest.magnitude;
}
private float CalcAccOnAxis(float destSpeed, float curSpeed, ref AccelerationSetting accSetting)
{
if (destSpeed > curSpeed)
{
float offset = destSpeed - curSpeed;
float possibleDecreaseSpeed = accSetting.DestAcc * Time.fixedDeltaTime;
if (possibleDecreaseSpeed > offset)
{
possibleDecreaseSpeed = offset;
}
return possibleDecreaseSpeed / Time.fixedDeltaTime;
}
else if (destSpeed == curSpeed)
{
return 0.0f;
}
else
{
float offset = curSpeed - destSpeed;
float possibleIncreaseSpeed = accSetting.DragAcc * Time.fixedDeltaTime;
if (possibleIncreaseSpeed > offset)
{
possibleIncreaseSpeed = offset;
}
return -possibleIncreaseSpeed / Time.fixedDeltaTime;
}
}
private Vector3 GetApplyAcc(Vector3 currentVel, Vector3 destVel)
{
Vector3 result = Vector3.zero;
AccelerationSetting accSetting = GetCurrentAccSetting();
float curSpeed = currentVel.magnitude;
float destSpeed = destVel.magnitude;
if (Mathf.Approximately(destSpeed, 0.0f))
{
if (Mathf.Approximately(curSpeed, 0.0f))
{
return Vector3.zero;
}
float possibleDecreaseSpeed = accSetting.DragAcc * Time.fixedDeltaTime;
if (possibleDecreaseSpeed > curSpeed)
{
possibleDecreaseSpeed = curSpeed;
}
result = -currentVel.normalized * (possibleDecreaseSpeed / Time.fixedDeltaTime);
}
else
{
Vector3 destDir = destVel.normalized;
float destProj = CalcProjLength(destDir, currentVel);
result += destDir * CalcAccOnAxis(destSpeed, destProj, ref accSetting);
Vector3 destYDir = CalcYAxis(destDir);
float destYProj = CalcProjLength(destYDir, currentVel);
result += destYDir * CalcAccOnAxis(0.0f, destYProj, ref accSetting);
}
result.y = 0.0f;
return result;
}
private void GetOnGround()
{
// Do not touch these code
Vector3 originalPos = m_rigidbody.position;
m_rigidbody.position += Vector3.up * OnGroundTestShiftLength;
m_dummyHitted = m_rigidbody.SweepTest(Vector3.down, out m_dummyHit, OnGroundTestLength + OnGroundTestShiftLength);
m_rigidbody.position = originalPos;
}
private bool m_dummyHitted;
private RaycastHit m_dummyHit;
private Rigidbody m_rigidbody;
private Vector3 m_destVelocity;
private Vector3 m_fixedUpdateVelocity;
private Dictionary<PhysicMaterial, AccelerationSetting> m_settingsDic = new Dictionary<PhysicMaterial, AccelerationSetting>();
private void FixedUpdate_Movement()
{
GetOnGround();
Vector3 currentVel = m_rigidbody.velocity;
Vector3 applyAcc = GetApplyAcc(currentVel, m_fixedUpdateVelocity);
m_rigidbody.AddForce(applyAcc, ForceMode.Acceleration);
}
#endregion
private void Awake()
{
m_rigidbody = GetComponent<Rigidbody>();
foreach (var setting in AdditionalGroundSettings)
{
m_settingsDic.Add(setting.OtherMaterial, setting.Setting);
}
AdditionalGroundSettings.Clear();
}
private void FixedUpdate()
{
FixedUpdate_Movement();
}
private void LateUpdate()
{
m_fixedUpdateVelocity = m_destVelocity;
m_destVelocity = Vector3.zero;
}
}