350 lines
12 KiB
C#
350 lines
12 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|