358 lines
9.8 KiB
Plaintext
358 lines
9.8 KiB
Plaintext
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class PhysicsMovement2D : MonoBehaviour
|
|
{
|
|
|
|
#region Define
|
|
|
|
public const float OnGroundTestLength = 0.02f;
|
|
|
|
[System.Serializable]
|
|
public struct AccelerationBindSetting
|
|
{
|
|
public PhysicMaterial OtherMaterial;
|
|
public AccelerationSetting Setting;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public struct AccelerationSetting
|
|
{
|
|
public float DestAcc;
|
|
public float DragAcc;
|
|
}
|
|
|
|
private enum Collider2DTypes { None, Box, Sphere, Capsule };
|
|
|
|
#endregion
|
|
|
|
#region Interface
|
|
|
|
public Vector2 DestVelocity
|
|
{
|
|
get => m_destVelocity;
|
|
|
|
set
|
|
{
|
|
m_destVelocity = value;
|
|
}
|
|
}
|
|
|
|
public bool IsOnGround
|
|
{
|
|
get
|
|
{
|
|
return m_dummyHitted;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Setting
|
|
|
|
public bool MoveOnXY = false;
|
|
|
|
public AccelerationSetting InAirAccSetting;
|
|
public AccelerationSetting DefaultGroundAccSetting;
|
|
public List<AccelerationBindSetting> AdditionalGroundSettings;
|
|
|
|
#endregion
|
|
|
|
#region Movement
|
|
|
|
private AccelerationSetting GetCurrentAccSetting()
|
|
{
|
|
if (!m_dummyHitted)
|
|
{
|
|
return InAirAccSetting;
|
|
}
|
|
else
|
|
{
|
|
return DefaultGroundAccSetting;
|
|
}
|
|
}
|
|
|
|
private Vector2 CalcYAxis(Vector2 xaxis)
|
|
{
|
|
Vector2 result;
|
|
|
|
// Rotate 90 deg
|
|
result.x = -xaxis.y;
|
|
result.y = xaxis.x;
|
|
|
|
return result;
|
|
}
|
|
|
|
private float CalcProjLength(Vector2 dest, Vector2 fromProj)
|
|
{
|
|
return Vector2.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 Vector2 GetApplyAcc(Vector2 currentVel, Vector2 destVel)
|
|
{
|
|
Vector2 result = Vector2.zero;
|
|
|
|
AccelerationSetting accSetting = GetCurrentAccSetting();
|
|
|
|
if (MoveOnXY)
|
|
{
|
|
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
|
|
{
|
|
Vector2 destDir = destVel.normalized;
|
|
float destProj = CalcProjLength(destDir, currentVel);
|
|
result += destDir * CalcAccOnAxis(destSpeed, destProj, ref accSetting);
|
|
|
|
Vector2 destYDir = CalcYAxis(destDir);
|
|
float destYProj = CalcProjLength(destYDir, currentVel);
|
|
result += destYDir * CalcAccOnAxis(0.0f, destYProj, ref accSetting);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float curSpeed = Mathf.Abs(currentVel.x);
|
|
float destSpeed = Mathf.Abs(destVel.x);
|
|
|
|
if (Mathf.Approximately(destVel.x, 0.0f))
|
|
{
|
|
if (currentVel.x < 0.0f)
|
|
{
|
|
result -= Vector2.right * CalcAccOnAxis(destSpeed, curSpeed, ref accSetting);
|
|
}
|
|
else
|
|
{
|
|
result += Vector2.right * CalcAccOnAxis(destSpeed, curSpeed, ref accSetting);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector2 destDir = destVel.normalized;
|
|
|
|
float destProj = currentVel.x;
|
|
if (destVel.x < 0.0f)
|
|
{
|
|
destProj *= -1.0f;
|
|
}
|
|
|
|
result += destDir * CalcAccOnAxis(destSpeed, destProj, ref accSetting);
|
|
}
|
|
|
|
result.y = 0.0f;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private void GetOnGround()
|
|
{
|
|
// Jumping is disable in XY mode
|
|
if (MoveOnXY)
|
|
{
|
|
m_dummyHitted = true;
|
|
return;
|
|
}
|
|
|
|
Collider2D compareCollider = null;
|
|
int addCount = 0;
|
|
|
|
// Do not touch these code
|
|
switch (m_colliderType)
|
|
{
|
|
case Collider2DTypes.None:
|
|
{
|
|
Vector2 colliderPos = m_rigidbody.position;
|
|
m_dummyHitted = Physics2D.Raycast(m_rigidbody.position, Vector2.down, OnGroundTestLength);
|
|
return;
|
|
}
|
|
case Collider2DTypes.Box:
|
|
{
|
|
Vector3 colliderPos3 = m_boxCollider.transform.position;
|
|
Vector2 colliderPos = new Vector2(colliderPos3.x, colliderPos3.y);
|
|
addCount = Physics2D.OverlapBoxNonAlloc(colliderPos + Vector2.down * OnGroundTestLength, m_boxCollider.size, m_boxCollider.transform.eulerAngles.z, m_dummyContainer);
|
|
compareCollider = m_boxCollider;
|
|
}
|
|
break;
|
|
case Collider2DTypes.Sphere:
|
|
{
|
|
Vector3 colliderPos3 = m_circleCollider.transform.position;
|
|
Vector2 colliderPos = new Vector2(colliderPos3.x, colliderPos3.y);
|
|
addCount = Physics2D.OverlapCircleNonAlloc(colliderPos + Vector2.down * OnGroundTestLength, m_circleCollider.radius, m_dummyContainer);
|
|
compareCollider = m_circleCollider;
|
|
}
|
|
break;
|
|
case Collider2DTypes.Capsule:
|
|
{
|
|
Vector3 colliderPos3 = m_capsuleCollider.transform.position;
|
|
Vector2 colliderPos = new Vector2(colliderPos3.x, colliderPos3.y);
|
|
addCount = Physics2D.OverlapCapsuleNonAlloc(colliderPos + Vector2.down * OnGroundTestLength, m_capsuleCollider.size, m_capsuleCollider.direction, m_capsuleCollider.transform.eulerAngles.z, m_dummyContainer);
|
|
compareCollider = m_capsuleCollider;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
int noneSelfCollider = 0;
|
|
for (int i = 0; i < addCount; i++)
|
|
{
|
|
if (m_dummyContainer[i])
|
|
{
|
|
if (m_dummyContainer[i] != compareCollider)
|
|
{
|
|
noneSelfCollider++;
|
|
}
|
|
m_dummyContainer[i] = null;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_dummyHitted = noneSelfCollider > 0;
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool m_dummyHitted;
|
|
private RaycastHit2D m_dummyHit;
|
|
private Collider2D[] m_dummyContainer = new Collider2D[10];
|
|
|
|
private Rigidbody2D m_rigidbody;
|
|
|
|
private Collider2DTypes m_colliderType;
|
|
private CircleCollider2D m_circleCollider;
|
|
private BoxCollider2D m_boxCollider;
|
|
private CapsuleCollider2D m_capsuleCollider;
|
|
|
|
protected Vector2 m_destVelocity;
|
|
private Vector2 m_fixedUpdateVelocity;
|
|
|
|
private Dictionary<PhysicMaterial, AccelerationSetting> m_settingsDic = new Dictionary<PhysicMaterial, AccelerationSetting>();
|
|
|
|
public Rigidbody2D RigidBody
|
|
{
|
|
get
|
|
{
|
|
return m_rigidbody;
|
|
}
|
|
}
|
|
|
|
private void FixedUpdate_Movement()
|
|
{
|
|
GetOnGround();
|
|
|
|
Vector2 currentVel = m_rigidbody.velocity;
|
|
Vector2 applyAcc = GetApplyAcc(currentVel, m_fixedUpdateVelocity);
|
|
m_rigidbody.AddForce(applyAcc * m_rigidbody.mass, ForceMode2D.Force);
|
|
}
|
|
|
|
#endregion
|
|
|
|
private T FindComponent<T>()
|
|
{
|
|
T result = GetComponent<T>();
|
|
if (result == null)
|
|
{
|
|
return GetComponentInChildren<T>();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
m_rigidbody = GetComponent<Rigidbody2D>();
|
|
|
|
m_circleCollider = FindComponent<CircleCollider2D>();
|
|
if (m_circleCollider)
|
|
{
|
|
m_colliderType = Collider2DTypes.Sphere;
|
|
}
|
|
else
|
|
{
|
|
m_boxCollider = FindComponent<BoxCollider2D>();
|
|
if (m_boxCollider)
|
|
{
|
|
m_colliderType = Collider2DTypes.Box;
|
|
}
|
|
else
|
|
{
|
|
m_capsuleCollider = FindComponent<CapsuleCollider2D>();
|
|
if (m_capsuleCollider)
|
|
{
|
|
m_colliderType = Collider2DTypes.Capsule;
|
|
}
|
|
else
|
|
{
|
|
m_colliderType = Collider2DTypes.None;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = Vector2.zero;
|
|
}
|
|
}
|