using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PlayerLoop;
using Random = System.Random;
namespace MoreMountains.Tools
{
///
/// A class used to handle the movement and behaviour of floating texts, usually used to display damage text.
/// This is designed to be spawned by a MMFloatingTextSpawner, not used on its own.
/// It also requires a specific hierarchy. You'll find examples of it in the MMTools/Tools/MMFloatingText/Prefabs folder
///
public class MMFloatingText : MonoBehaviour
{
[Header("Bindings")]
/// the part of the prefab that we'll move
[Tooltip("the part of the prefab that we'll move")]
public Transform MovingPart;
/// the part of the prefab that we'll rotate to face the target camera
[Tooltip("the part of the prefab that we'll rotate to face the target camera")]
public Transform Billboard;
/// the TextMesh used to display the value
[Tooltip("the TextMesh used to display the value")]
public TextMesh TargetTextMesh;
[Header("Debug")]
/// the direction of this floating text, used for debug only
[Tooltip("the direction of this floating text, used for debug only")]
[MMReadOnly]
public Vector3 Direction = Vector3.up;
protected bool _useUnscaledTime = false;
public virtual float GetTime() { return (_useUnscaledTime) ? Time.unscaledTime : Time.time; }
public virtual float GetDeltaTime() { return _useUnscaledTime ? Time.unscaledDeltaTime : Time.unscaledTime; }
protected float _startedAt;
protected float _lifetime;
protected Vector3 _newPosition;
protected Color _initialTextColor;
protected bool _animateMovement;
protected bool _animateX;
protected AnimationCurve _animateXCurve;
protected float _remapXZero;
protected float _remapXOne;
protected bool _animateY;
protected AnimationCurve _animateYCurve;
protected float _remapYZero;
protected float _remapYOne;
protected bool _animateZ;
protected AnimationCurve _animateZCurve;
protected float _remapZZero;
protected float _remapZOne;
protected MMFloatingTextSpawner.AlignmentModes _alignmentMode;
protected Vector3 _fixedAlignment;
protected Vector3 _movementDirection;
protected Vector3 _movingPartPositionLastFrame;
protected bool _alwaysFaceCamera;
protected Camera _targetCamera;
protected Quaternion _targetCameraRotation;
protected bool _animateOpacity;
protected AnimationCurve _animateOpacityCurve;
protected float _remapOpacityZero;
protected float _remapOpacityOne;
protected bool _animateScale;
protected AnimationCurve _animateScaleCurve;
protected float _remapScaleZero;
protected float _remapScaleOne;
protected bool _animateColor;
protected Gradient _animateColorGradient;
protected Vector3 _newScale;
protected Color _newColor;
protected float _elapsedTime;
protected float _remappedTime;
///
/// On enable, we initialize our floating text
///
protected void OnEnable()
{
Initialization();
}
///
/// Changes whether or not this floating text should use unscaled time
///
///
public virtual void SetUseUnscaledTime(bool status, bool resetStartedAt)
{
_useUnscaledTime = status;
if (resetStartedAt)
{
_startedAt = GetTime();
}
}
///
/// Stores start time and initial color
///
protected virtual void Initialization()
{
_startedAt = GetTime();
if (TargetTextMesh != null)
{
_initialTextColor = TargetTextMesh.color;
}
}
///
/// On Update we move our text
///
protected virtual void Update()
{
UpdateFloatingText();
}
///
/// Handles the text's life cycle, movement, scale, color, opacity, alignment and billboard
///
protected virtual void UpdateFloatingText()
{
_elapsedTime = GetTime() - _startedAt;
_remappedTime = MMMaths.Remap(_elapsedTime, 0f, _lifetime, 0f, 1f);
// lifetime
if (_elapsedTime > _lifetime)
{
TurnOff();
}
HandleMovement();
HandleColor();
HandleOpacity();
HandleScale();
HandleAlignment();
HandleBillboard();
}
///
/// Moves the text along the specified curves
///
protected virtual void HandleMovement()
{
// position movement
if (_animateMovement)
{
this.transform.up = Direction;
_newPosition.x = _animateX ? MMMaths.Remap(_animateXCurve.Evaluate(_remappedTime), 0f, 1, _remapXZero, _remapXOne) : 0f;
_newPosition.y = _animateY ? MMMaths.Remap(_animateYCurve.Evaluate(_remappedTime), 0f, 1, _remapYZero, _remapYOne) : 0f;
_newPosition.z = _animateZ ? MMMaths.Remap(_animateZCurve.Evaluate(_remappedTime), 0f, 1, _remapZZero, _remapZOne) : 0f;
// we move the moving part
MovingPart.transform.localPosition = _newPosition;
// we store the last position
if (Vector3.Distance(_movingPartPositionLastFrame, MovingPart.position) > 0.5f)
{
_movingPartPositionLastFrame = MovingPart.position;
}
}
}
///
/// Animates the text's color over the specified gradient
///
protected virtual void HandleColor()
{
if (_animateColor)
{
_newColor = _animateColorGradient.Evaluate(_remappedTime);
SetColor(_newColor);
}
}
///
/// Animates the text's opacity over the specified curve
///
protected virtual void HandleOpacity()
{
if (_animateOpacity)
{
float newOpacity = MMMaths.Remap(_animateOpacityCurve.Evaluate(_remappedTime), 0f, 1f, _remapOpacityZero, _remapOpacityOne);
SetOpacity(newOpacity);
}
}
///
/// Animates the text's scale over the specified curve
///
protected virtual void HandleScale()
{
if (_animateScale)
{
_newScale = Vector3.one * MMMaths.Remap(_animateScaleCurve.Evaluate(_remappedTime), 0f, 1f, _remapScaleZero, _remapScaleOne);
MovingPart.transform.localScale = _newScale;
}
}
///
/// Handles text rotation to match either a fixed alignment, the initial direction or the movement's direction
///
protected virtual void HandleAlignment()
{
if (_alignmentMode == MMFloatingTextSpawner.AlignmentModes.Fixed)
{
MovingPart.transform.up = _fixedAlignment;
}
else if (_alignmentMode == MMFloatingTextSpawner.AlignmentModes.MatchInitialDirection)
{
MovingPart.transform.up = this.transform.up;
}
else if (_alignmentMode == MMFloatingTextSpawner.AlignmentModes.MatchMovementDirection)
{
_movementDirection = MovingPart.position - _movingPartPositionLastFrame;
MovingPart.transform.up = _movementDirection.normalized;
}
}
///
/// Forces the text to face the camera
///
protected virtual void HandleBillboard()
{
if (_alwaysFaceCamera)
{
_targetCameraRotation = _targetCamera.transform.rotation;
Billboard.transform.LookAt(MovingPart.transform.position + _targetCameraRotation * Vector3.forward, _targetCameraRotation * MovingPart.up);
}
}
///
/// Called by the spawner, sets all required variables
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
public virtual void SetProperties(string value, float lifetime, Vector3 direction, bool animateMovement,
MMFloatingTextSpawner.AlignmentModes alignmentMode, Vector3 fixedAlignment,
bool alwaysFaceCamera, Camera targetCamera,
bool animateX, AnimationCurve animateXCurve, float remapXZero, float remapXOne,
bool animateY, AnimationCurve animateYCurve, float remapYZero, float remapYOne,
bool animateZ, AnimationCurve animateZCurve, float remapZZero, float remapZOne,
bool animateOpacity, AnimationCurve animateOpacityCurve, float remapOpacityZero, float remapOpacityOne,
bool animateScale, AnimationCurve animateScaleCurve, float remapScaleZero, float remapScaleOne,
bool animateColor, Gradient animateColorGradient)
{
SetText(value);
_lifetime = lifetime;
Direction = direction;
_animateMovement = animateMovement;
_animateX = animateX;
_animateXCurve = animateXCurve;
_remapXZero = remapXZero;
_remapXOne = remapXOne;
_animateY = animateY;
_animateYCurve = animateYCurve;
_remapYZero = remapYZero;
_remapYOne = remapYOne;
_animateZ = animateZ;
_animateZCurve = animateZCurve;
_remapZZero = remapZZero;
_remapZOne = remapZOne;
_alignmentMode = alignmentMode;
_fixedAlignment = fixedAlignment;
_alwaysFaceCamera = alwaysFaceCamera;
_targetCamera = targetCamera;
_animateOpacity = animateOpacity;
_animateOpacityCurve = animateOpacityCurve;
_remapOpacityZero = remapOpacityZero;
_remapOpacityOne = remapOpacityOne;
_animateScale = animateScale;
_animateScaleCurve = animateScaleCurve;
_remapScaleZero = remapScaleZero;
_remapScaleOne = remapScaleOne;
_animateColor = animateColor;
_animateColorGradient = animateColorGradient;
UpdateFloatingText();
}
///
/// Resets this text's position
///
public virtual void ResetPosition()
{
if (_animateMovement)
{
MovingPart.transform.localPosition = Vector3.zero;
}
_movingPartPositionLastFrame = MovingPart.position - Direction;
}
///
/// Sets the target mesh's text value
///
///
public virtual void SetText(string newValue)
{
TargetTextMesh.text = newValue;
}
///
/// Sets the color of the target text
///
///
public virtual void SetColor(Color newColor)
{
TargetTextMesh.color = newColor;
}
///
/// Sets the opacity of the target text
///
///
public virtual void SetOpacity(float newOpacity)
{
_newColor = TargetTextMesh.color;
_newColor.a = newOpacity;
TargetTextMesh.color = _newColor;
}
///
/// Turns of the text for recycling
///
protected virtual void TurnOff()
{
this.gameObject.SetActive(false);
}
}
}