217 lines
5.4 KiB
Plaintext
217 lines
5.4 KiB
Plaintext
|
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;
|
||
|
}
|
||
|
}
|