You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
4.8 KiB
C#
125 lines
4.8 KiB
C#
// Animancer // Copyright 2020 Kybernetik //
|
|
|
|
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
|
|
|
|
using Animancer.FSM;
|
|
using UnityEngine;
|
|
|
|
namespace Animancer.Examples.StateMachines.Brains
|
|
{
|
|
/// <summary>
|
|
/// A <see cref="CreatureBrain"/> which controls the creature using mouse input.
|
|
/// </summary>
|
|
[AddComponentMenu(Strings.MenuPrefix + "Examples/Brains - Mouse Brain")]
|
|
[HelpURL(Strings.APIDocumentationURL + ".Examples.StateMachines.Brains/MouseBrain")]
|
|
public sealed class MouseBrain : CreatureBrain
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
[SerializeField] private CreatureState _Locomotion;
|
|
[SerializeField] private float _StopDistance = 0.2f;
|
|
[SerializeField] private float _MinRunDistance = 1;
|
|
|
|
private Vector3? _Destination;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private void OnEnable()
|
|
{
|
|
_Destination = null;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private void Update()
|
|
{
|
|
UpdateInput();
|
|
UpdateMovement();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private void UpdateInput()
|
|
{
|
|
if (Input.GetMouseButton(0))
|
|
{
|
|
var creaturePosition = Creature.Rigidbody.position;
|
|
|
|
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
|
|
|
RaycastHit raycastHit;
|
|
if (Physics.Raycast(ray, out raycastHit))
|
|
{
|
|
_Destination = raycastHit.point;
|
|
Debug.DrawLine(ray.origin, raycastHit.point, Color.green);
|
|
}
|
|
else
|
|
{
|
|
// If the ray does not hit anything, just use the point where it intersects
|
|
// the XZ plane at the height the creature is currently at.
|
|
_Destination = CalculateRayTargetXZ(ray, creaturePosition.y);
|
|
if (_Destination != null)
|
|
Debug.DrawLine(ray.origin, _Destination.Value, Color.red);
|
|
}
|
|
|
|
IsRunning =
|
|
_Destination != null &&
|
|
Vector3.Distance(creaturePosition, _Destination.Value) >= _MinRunDistance;
|
|
}
|
|
else
|
|
{
|
|
IsRunning = false;
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
public static Vector3? CalculateRayTargetXZ(Ray ray, float y = 0)
|
|
{
|
|
y = ray.origin.y - y;
|
|
|
|
// If the ray starts above the target and is pointing up then it will never intersect.
|
|
// Same if it is below and pointing down or if it is perfectly horizontal.
|
|
if (ray.direction.y == 0 || SameSign(y, ray.direction.y))
|
|
return null;
|
|
|
|
return ray.origin - ray.direction * (y / ray.direction.y);
|
|
}
|
|
|
|
public static bool SameSign(float x, float y)
|
|
{
|
|
return
|
|
(x > 0 && y > 0) ||
|
|
(x < 0 && y < 0) ||
|
|
(x == 0 && y == 0);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private void UpdateMovement()
|
|
{
|
|
if (_Destination != null)
|
|
{
|
|
var fromCurrentToDestination = _Destination.Value - Creature.Rigidbody.position;
|
|
|
|
// Vector magnitudes are calculated using Pythagoras' Theorem which involves a square root.
|
|
// Square roots are a much slower operation than simple arithmetic operations.
|
|
// Since we only need to see which is greater, we can compare the squared magnitude and stop distance.
|
|
if (fromCurrentToDestination.sqrMagnitude > _StopDistance * _StopDistance)
|
|
{
|
|
MovementDirection = fromCurrentToDestination;
|
|
_Locomotion.TryEnterState();
|
|
Debug.DrawLine(Creature.Rigidbody.position, _Destination.Value, Color.cyan);
|
|
return;
|
|
}
|
|
}
|
|
|
|
_Destination = null;
|
|
MovementDirection = Vector3.zero;
|
|
Creature.Idle.TryEnterState();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|