Files
2026-02-21 16:45:37 +08:00

369 lines
6.4 KiB
C#

using UnityEngine;
namespace S_SnapTools
{
public class S_SnapToGrid : MonoBehaviour
{
public enum ESnapCondition
{
ON_UPDATE = 0,
WHEN_STILL = 1
}
[SerializeField]
private float m_epsilon = 0.001f;
[SerializeField]
private float m_maxVelocity_StillMode = 0.001f;
[SerializeField]
private float m_maxEulerVelocity_StillMode = 0.01f;
[SerializeField]
private float m_stillTimeBeforSnap_StillMode = 0.2f;
[SerializeField]
private Vector3 m_gridOffset = Vector3.zero;
[SerializeField]
private Vector3 m_gridCellSize = Vector3.one * 10f;
[SerializeField]
private Vector3 m_rotationOffset = Vector3.zero;
[SerializeField]
private Vector3 m_rotationStepSize = Vector3.one * 22.5f;
[SerializeField]
private ESnapCondition m_snapCondition;
[SerializeField]
private bool m_isInstantSnap;
[SerializeField]
private bool m_isSnapAxisX = true;
[SerializeField]
private bool m_isSnapAxisY = true;
[SerializeField]
private bool m_isSnapAxisZ = true;
[SerializeField]
private bool m_isSnapAxisXRotation = true;
[SerializeField]
private bool m_isSnapAxisYRotation = true;
[SerializeField]
private bool m_isSnapAxisZRotation = true;
private float m_stillTimePos;
private float m_stillTimeRot;
private Vector3 m_lastPosition = Vector3.zero;
private Vector3 m_lastEuler = Vector3.zero;
public float Epsilon
{
get
{
return m_epsilon;
}
set
{
m_epsilon = value;
}
}
public float MaxVelocity_StillMode
{
get
{
return m_maxVelocity_StillMode;
}
set
{
m_maxVelocity_StillMode = value;
}
}
public float MaxEulerVelocity_StillMode
{
get
{
return m_maxEulerVelocity_StillMode;
}
set
{
m_maxEulerVelocity_StillMode = value;
}
}
public float StillTimeBeforSnap_StillMode
{
get
{
return m_stillTimeBeforSnap_StillMode;
}
set
{
m_stillTimeBeforSnap_StillMode = value;
}
}
public Vector3 GridOffset
{
get
{
return m_gridOffset;
}
set
{
m_gridOffset = value;
}
}
public Vector3 GridCellSize
{
get
{
return m_gridCellSize;
}
set
{
m_gridCellSize = value;
}
}
public Vector3 RotationOffset
{
get
{
return m_rotationOffset;
}
set
{
m_rotationOffset = value;
}
}
public Vector3 RotationStepSize
{
get
{
return m_rotationStepSize;
}
set
{
m_rotationStepSize = value;
}
}
public ESnapCondition SnapCondition
{
get
{
return m_snapCondition;
}
set
{
m_snapCondition = value;
}
}
public bool IsInstantSnap
{
get
{
return m_isInstantSnap;
}
set
{
m_isInstantSnap = value;
}
}
public bool IsSnapAxisX
{
get
{
return m_isSnapAxisX;
}
set
{
m_isSnapAxisX = value;
}
}
public bool IsSnapAxisY
{
get
{
return m_isSnapAxisY;
}
set
{
m_isSnapAxisY = value;
}
}
public bool IsSnapAxisZ
{
get
{
return m_isSnapAxisZ;
}
set
{
m_isSnapAxisZ = value;
}
}
public bool IsSnapAxisXRotation
{
get
{
return m_isSnapAxisXRotation;
}
set
{
m_isSnapAxisXRotation = value;
}
}
public bool IsSnapAxisYRotation
{
get
{
return m_isSnapAxisYRotation;
}
set
{
m_isSnapAxisYRotation = value;
}
}
public bool IsSnapAxisZRotation
{
get
{
return m_isSnapAxisZRotation;
}
set
{
m_isSnapAxisZRotation = value;
}
}
public void DoSnap()
{
DoSnapPosition();
DoSnapRotation();
}
public void DoSnapPosition()
{
Vector3 o_snapTarget;
if (GetSnapTarget(base.transform.position, m_gridOffset, m_gridCellSize, m_isSnapAxisX, m_isSnapAxisY, m_isSnapAxisZ, out o_snapTarget))
{
if (m_isInstantSnap)
{
base.transform.position = o_snapTarget;
}
else
{
base.transform.position = Vector3.Lerp(base.transform.position, o_snapTarget, 0.5f);
}
m_lastPosition = base.transform.position;
}
}
public void DoSnapRotation()
{
Vector3 o_snapTarget;
if (GetSnapTarget(base.transform.localEulerAngles, m_rotationOffset, m_rotationStepSize, m_isSnapAxisXRotation, m_isSnapAxisYRotation, m_isSnapAxisZRotation, out o_snapTarget))
{
if (m_isInstantSnap)
{
base.transform.localEulerAngles = o_snapTarget;
}
else
{
base.transform.localEulerAngles = Vector3.Slerp(base.transform.localEulerAngles, o_snapTarget, 0.5f);
}
m_lastEuler = base.transform.localEulerAngles;
}
}
private void Start()
{
if (m_gridCellSize.x == 0f || m_gridCellSize.y == 0f || m_gridCellSize.z == 0f)
{
m_gridCellSize += Vector3.one * 0.1f;
Debug.LogError("S_SnapToGrid: Start: All components of the GridCellSize vector must be unequal 0!");
}
}
private void LateUpdate()
{
if (m_snapCondition == ESnapCondition.ON_UPDATE)
{
DoSnap();
return;
}
if (IsStill(base.transform.position, m_maxVelocity_StillMode, ref m_lastPosition, ref m_stillTimePos))
{
DoSnapPosition();
}
if (IsStill(base.transform.localEulerAngles, m_maxEulerVelocity_StillMode, ref m_lastEuler, ref m_stillTimeRot))
{
DoSnapRotation();
}
}
private bool IsStill(Vector3 p_currentValue, float p_maxV, ref Vector3 r_lastValue, ref float r_stillTime)
{
if ((r_lastValue - p_currentValue).magnitude / Time.deltaTime < p_maxV)
{
r_stillTime += Time.deltaTime;
}
else
{
r_stillTime = 0f;
}
r_lastValue = p_currentValue;
return r_stillTime >= m_stillTimeBeforSnap_StillMode;
}
private bool GetSnapTarget(Vector3 p_value, Vector3 p_offset, Vector3 p_stepSize, bool p_isSnapAxisX, bool p_isSnapAxisY, bool p_isSnapAxisZ, out Vector3 o_snapTarget)
{
Vector3 vector = p_value - p_offset;
float num = vector.x / p_stepSize.x;
float num2 = vector.y / p_stepSize.y;
float num3 = vector.z / p_stepSize.z;
if ((p_isSnapAxisX && num - Mathf.Floor(num) > m_epsilon) || (p_isSnapAxisY && num2 - Mathf.Floor(num2) > m_epsilon) || (p_isSnapAxisZ && num3 - Mathf.Floor(num3) > m_epsilon))
{
if (p_isSnapAxisX)
{
num = Mathf.Round(num);
}
if (p_isSnapAxisY)
{
num2 = Mathf.Round(num2);
}
if (p_isSnapAxisZ)
{
num3 = Mathf.Round(num3);
}
o_snapTarget = p_offset + Vector3.Scale(new Vector3(num, num2, num3), p_stepSize);
return true;
}
o_snapTarget = p_value;
return false;
}
}
}