FollowMousePosition.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
  3. using Animancer.Units;
  4. using UnityEngine;
  5. namespace Animancer.Samples.Mixers
  6. {
  7. /// <summary>
  8. /// Controls Animancer parameters to make the character move
  9. /// towards the mouse position using Root Motion in a 2D Mixer.
  10. /// </summary>
  11. ///
  12. /// <remarks>
  13. /// <strong>Sample:</strong>
  14. /// <see href="https://kybernetik.com.au/animancer/docs/samples/mixers/directional">
  15. /// Directional Mixers</see>
  16. /// </remarks>
  17. ///
  18. /// https://kybernetik.com.au/animancer/api/Animancer.Samples.Mixers/FollowMousePosition
  19. ///
  20. [AddComponentMenu(Strings.SamplesMenuPrefix + "Mixers - Follow Mouse Position")]
  21. [AnimancerHelpUrl(typeof(FollowMousePosition))]
  22. public class FollowMousePosition : MonoBehaviour
  23. {
  24. /************************************************************************************************************************/
  25. #if UNITY_PHYSICS_3D
  26. /************************************************************************************************************************/
  27. // We could hard code the parameter names like this:
  28. // public static readonly StringReference ParameterX = "Movement X";
  29. // public static readonly StringReference ParameterY = "Movement Y";
  30. // But that would make this script less flexible
  31. // and you wouldn't be able to see what it's using in the Inspector.
  32. [SerializeField] private AnimancerComponent _Animancer;
  33. [SerializeField] private StringAsset _ParameterX;
  34. [SerializeField] private StringAsset _ParameterY;
  35. [SerializeField, Seconds] private float _ParameterSmoothTime = 0.15f;
  36. [SerializeField, Meters] private float _StopProximity = 0.1f;
  37. /************************************************************************************************************************/
  38. private SmoothedVector2Parameter _SmoothedParameters;
  39. /************************************************************************************************************************/
  40. protected virtual void Awake()
  41. {
  42. _SmoothedParameters = new SmoothedVector2Parameter(
  43. _Animancer,
  44. _ParameterX,
  45. _ParameterY,
  46. _ParameterSmoothTime);
  47. }
  48. /************************************************************************************************************************/
  49. protected virtual void Update()
  50. {
  51. // Calculate the movement direction.
  52. Vector3 movementDirection = GetMovementDirection();
  53. // The movement direction is in world space,
  54. // so we need to convert it to the character's local space
  55. // to be appropriate for their current rotation.
  56. Vector3 localDirection = transform.InverseTransformDirection(movementDirection);
  57. // Then set the target value for the parameters to move towards:
  58. // - Parameter X towards Direction X (right/left).
  59. // - Parameter Y towards Direction Z (forwards/backwards).
  60. // - Ignore Direction Y because the Mixer is only 2D.
  61. _SmoothedParameters.TargetValue = new Vector2(localDirection.x, localDirection.z);
  62. }
  63. /************************************************************************************************************************/
  64. private Vector3 GetMovementDirection()
  65. {
  66. // Get a ray from the main camera in the direction of the mouse cursor.
  67. Ray ray = Camera.main.ScreenPointToRay(SampleInput.MousePosition);
  68. // Raycast with it and stop trying to move it it doesn't hit anything.
  69. if (!Physics.Raycast(ray, out RaycastHit raycastHit))// Note the exclamation mark !
  70. return Vector3.zero;
  71. // If the ray hit something, calculate the direction from this object to that point.
  72. Vector3 direction = raycastHit.point - transform.position;
  73. // If we are close to the destination, stop moving.
  74. float squaredDistance = direction.sqrMagnitude;
  75. if (squaredDistance <= _StopProximity * _StopProximity)
  76. {
  77. return Vector3.zero;
  78. }
  79. else
  80. {
  81. // Otherwise normalize the direction so that we don't change speed based on distance.
  82. // Calling direction.Normalize() would do the same thing, but would calculate the magnitude again.
  83. return direction / Mathf.Sqrt(squaredDistance);
  84. }
  85. }
  86. /************************************************************************************************************************/
  87. protected virtual void OnDestroy()
  88. {
  89. // It's not necessary for this sample,
  90. // but if this component could be destroyed before the rest of the character
  91. // then we need to Dispose the smoother to remove it from the target parameters.
  92. _SmoothedParameters.Dispose();
  93. }
  94. /************************************************************************************************************************/
  95. #else
  96. /************************************************************************************************************************/
  97. protected virtual void Awake()
  98. {
  99. SampleReadMe.LogMissingPhysics3DModuleError(this);
  100. }
  101. /************************************************************************************************************************/
  102. #endif
  103. /************************************************************************************************************************/
  104. }
  105. }