rabidus-test/Assets/Dreamteck/Splines/Core/TransformModule.cs

350 lines
12 KiB
C#
Raw Normal View History

2023-07-24 16:38:13 +03:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
namespace Dreamteck.Splines
{
[System.Serializable]
public class TransformModule : ISerializationCallbackReceiver
{
public Vector2 offset
{
get { return _offset; }
set
{
if (value != _offset)
{
_offset = value;
_hasOffset = _offset != Vector2.zero;
if (targetUser != null)
{
targetUser.Rebuild();
}
}
}
}
public Vector3 rotationOffset
{
get { return _rotationOffset; }
set
{
if (value != _rotationOffset)
{
_rotationOffset = value;
_hasRotationOffset = _rotationOffset != Vector3.zero;
if (targetUser != null)
{
targetUser.Rebuild();
}
}
}
}
public bool hasOffset
{
get { return _hasOffset; }
}
public bool hasRotationOffset
{
get { return _hasRotationOffset; }
}
public Vector3 baseScale
{
get { return _baseScale; }
set
{
if (value != _baseScale)
{
_baseScale = value;
if (targetUser != null)
{
targetUser.Rebuild();
}
}
}
}
public bool is2D
{
get { return _2dMode; }
set
{
_2dMode = value;
}
}
[SerializeField]
[HideInInspector]
private bool _hasOffset = false;
[SerializeField]
[HideInInspector]
private bool _hasRotationOffset = false;
[SerializeField]
[HideInInspector]
private Vector2 _offset;
[SerializeField]
[HideInInspector]
private Vector3 _rotationOffset = Vector3.zero;
[SerializeField]
[HideInInspector]
private Vector3 _baseScale = Vector3.one;
[SerializeField]
[HideInInspector]
private bool _2dMode = false;
public enum VelocityHandleMode { Zero, Preserve, Align, AlignRealistic }
public VelocityHandleMode velocityHandleMode = VelocityHandleMode.Zero;
public SplineSample splineResult
{
get
{
return _splineResult;
}
set
{
_splineResult = value;
}
}
private SplineSample _splineResult;
public bool applyPositionX = true;
public bool applyPositionY = true;
public bool applyPositionZ = true;
public bool applyPosition2D = true;
public bool retainLocalPosition = false;
public Spline.Direction direction = Spline.Direction.Forward;
public bool applyPosition
{
get
{
if (_2dMode)
{
return applyPosition2D;
}
return applyPositionX || applyPositionY || applyPositionZ;
}
set
{
applyPositionX = applyPositionY = applyPositionZ = applyPosition2D = value;
}
}
public bool applyRotationX = true;
public bool applyRotationY = true;
public bool applyRotationZ = true;
public bool applyRotation2D = true;
public bool retainLocalRotation = false;
public bool applyRotation
{
get
{
if (_2dMode)
{
return applyRotation2D;
}
return applyRotationX || applyRotationY || applyRotationZ;
}
set
{
applyRotationX = applyRotationY = applyRotationZ = applyRotation2D = value;
}
}
public bool applyScaleX = false;
public bool applyScaleY = false;
public bool applyScaleZ = false;
public bool applyScale
{
get
{
return applyScaleX || applyScaleY || applyScaleZ;
}
set
{
applyScaleX = applyScaleY = applyScaleZ = value;
}
}
[HideInInspector]
public SplineUser targetUser = null;
//These are used to save allocations
private static Vector3 position = Vector3.zero;
private static Quaternion rotation = Quaternion.identity;
public void ApplyTransform(Transform input)
{
input.position = GetPosition(input.position);
input.rotation = GetRotation(input.rotation);
input.localScale = GetScale(input.localScale);
}
public void ApplyRigidbody(Rigidbody input)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
ApplyTransform(input.transform);
return;
}
#endif
input.transform.localScale = GetScale(input.transform.localScale);
input.MovePosition(GetPosition(input.position));
input.velocity = HandleVelocity(input.velocity);
input.MoveRotation(GetRotation(input.rotation));
Vector3 angularVelocity = input.angularVelocity;
if (applyRotationX)
{
angularVelocity.x = 0f;
}
if (applyRotationY)
{
angularVelocity.y = 0f;
}
if (applyRotationZ || applyRotation2D)
{
angularVelocity.z = 0f;
}
input.angularVelocity = angularVelocity;
}
public void ApplyRigidbody2D(Rigidbody2D input)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
ApplyTransform(input.transform);
input.transform.rotation = Quaternion.AngleAxis(GetRotation(Quaternion.Euler(0f, 0f, input.rotation)).eulerAngles.z, Vector3.forward);
return;
}
#endif
input.transform.localScale = GetScale(input.transform.localScale);
input.position = GetPosition(input.position);
input.velocity = HandleVelocity(input.velocity);
input.rotation = GetRotation(Quaternion.Euler(0f, 0f, input.rotation)).eulerAngles.z;
if (applyRotationX)
{
input.angularVelocity = 0f;
}
}
Vector3 HandleVelocity(Vector3 velocity)
{
Vector3 idealVelocity = Vector3.zero;
Vector3 direction = Vector3.right;
switch (velocityHandleMode)
{
case VelocityHandleMode.Preserve: idealVelocity = velocity; break;
case VelocityHandleMode.Align:
direction = _splineResult.forward;
if (Vector3.Dot(velocity, direction) < 0f) direction *= -1f;
idealVelocity = direction * velocity.magnitude; break;
case VelocityHandleMode.AlignRealistic:
direction = _splineResult.forward;
if (Vector3.Dot(velocity, direction) < 0f) direction *= -1f;
idealVelocity = direction * velocity.magnitude * Vector3.Dot(velocity.normalized, direction); break;
}
if (applyPositionX) velocity.x = idealVelocity.x;
if (applyPositionY) velocity.y = idealVelocity.y;
if (applyPositionZ) velocity.z = idealVelocity.z;
return velocity;
}
private Vector3 GetPosition(Vector3 inputPosition)
{
position = _splineResult.position;
Vector2 finalOffset = _offset;
if (finalOffset != Vector2.zero)
{
position += _splineResult.right * finalOffset.x * _splineResult.size + _splineResult.up * finalOffset.y * _splineResult.size;
}
if (retainLocalPosition)
{
Matrix4x4 matrix = Matrix4x4.TRS(position, _splineResult.rotation, Vector3.one);
Vector3 splineLocalPosition = matrix.inverse.MultiplyPoint3x4(targetUser.transform.position);
splineLocalPosition.x = applyPositionX ? 0f : splineLocalPosition.x;
splineLocalPosition.y = applyPositionY ? 0f : splineLocalPosition.y;
splineLocalPosition.z = applyPositionZ ? 0f : splineLocalPosition.z;
inputPosition = matrix.MultiplyPoint3x4(splineLocalPosition);
} else
{
if (applyPositionX) inputPosition.x = position.x;
if (applyPositionY) inputPosition.y = position.y;
if (applyPositionZ) inputPosition.z = position.z;
}
return inputPosition;
}
private Quaternion GetRotation(Quaternion inputRotation)
{
rotation = Quaternion.LookRotation(_splineResult.forward * (direction == Spline.Direction.Forward ? 1f : -1f), _splineResult.up);
if (_2dMode)
{
if (applyRotation2D)
{
rotation *= Quaternion.Euler(90, -90, 0);
inputRotation = Quaternion.AngleAxis(rotation.eulerAngles.z + _rotationOffset.z, Vector3.forward);
}
return inputRotation;
}
else
{
if (_rotationOffset != Vector3.zero)
{
rotation = rotation * Quaternion.Euler(_rotationOffset);
}
}
if (retainLocalRotation)
{
Quaternion localRotation = Quaternion.Inverse(rotation) * inputRotation;
Vector3 targetEuler = localRotation.eulerAngles;
targetEuler.x = applyRotationX ? 0f : targetEuler.x;
targetEuler.y = applyRotationY ? 0f : targetEuler.y;
targetEuler.z = applyRotationZ ? 0f : targetEuler.z;
inputRotation = rotation * Quaternion.Euler(targetEuler);
} else
{
if (!applyRotationX || !applyRotationY || !applyRotationZ)
{
Vector3 targetEuler = rotation.eulerAngles;
Vector3 sourceEuler = inputRotation.eulerAngles;
if (!applyRotationX) targetEuler.x = sourceEuler.x;
if (!applyRotationY) targetEuler.y = sourceEuler.y;
if (!applyRotationZ) targetEuler.z = sourceEuler.z;
inputRotation.eulerAngles = targetEuler;
}
else
{
inputRotation = rotation;
}
}
return inputRotation;
}
private Vector3 GetScale(Vector3 inputScale)
{
if (applyScaleX) inputScale.x = _baseScale.x * _splineResult.size;
if (applyScaleY) inputScale.y = _baseScale.y * _splineResult.size;
if (applyScaleZ) inputScale.z = _baseScale.z * _splineResult.size;
return inputScale;
}
public void OnBeforeSerialize()
{
}
public void OnAfterDeserialize()
{
_hasRotationOffset = _rotationOffset != Vector3.zero;
_hasOffset = _offset != Vector2.zero;
}
}
}