Skip to content

Instantly share code, notes, and snippets.

@FleshMobProductions
Last active March 3, 2022 07:46
Show Gist options
  • Save FleshMobProductions/5f9225ed8c66c53b68f76ea7af0ceab2 to your computer and use it in GitHub Desktop.
Save FleshMobProductions/5f9225ed8c66c53b68f76ea7af0ceab2 to your computer and use it in GitHub Desktop.
using UnityEngine;
namespace FMPUtils
{
/// <summary>
/// In order to apply the delta movement to an object, just check if the object is grounded on this obstacle,
/// and if it is, store a reference to this behaviour and call one of the following methods in the Update() for
/// applying the delta movement of this object: ApplyDeltaTranslationTo, ApplyDeltaRotationTo or
/// ApplyDeltaTranslationRotationTo. If the object is disabled, delta changes are 0 and positions / rotations
/// won't get updated.
/// One recommneded workflow might be to assign another script that handles movement of the transform to this
/// gameObject. In the script execution order settings (or by using the DefaultExecutionOrder attribute above
/// the class definition), assign a lower value (like -20), for it to have priority.
/// Then assign a script execution order value to MovingObstacle that is higher than the movement script,
/// but lower than 0, so it has priority towards regular scripts.
/// Then the right order is maintained: 1. movement of the object is updated, 2. delta movement values in
/// this script are updated, 3. delta movement changes are applied to other objects if the call the "ApplyTo" methods
/// </summary>
public class MovingObstacle : MonoBehaviour
{
private Quaternion rotationPrevFrame;
private Quaternion rotationCurrentFrame;
private Vector3 positionPrevFrame;
private Vector3 positionCurrentFrame;
private void Start()
{
StoreCurrentValuesInTranslationVars();
}
// Make the positions to be the same, so that we don't receive delta position or rotation values from the
// disabled objects while they are disabled
private void OnEnable()
{
StoreCurrentValuesInTranslationVars();
}
private void OnDisable()
{
StoreCurrentValuesInTranslationVars();
}
private void StoreCurrentValuesInTranslationVars()
{
rotationCurrentFrame = transform.rotation;
rotationPrevFrame = rotationCurrentFrame;
positionCurrentFrame = transform.position;
positionPrevFrame = positionCurrentFrame;
}
public Quaternion GetDeltaRotation()
{
if (rotationCurrentFrame != rotationPrevFrame)
{
return Quaternion.Inverse(rotationPrevFrame) * rotationCurrentFrame;
}
return Quaternion.identity;
}
public Vector3 GetDeltaTranslation()
{
return positionCurrentFrame - positionPrevFrame;
}
private void Update()
{
rotationPrevFrame = rotationCurrentFrame;
positionPrevFrame = positionCurrentFrame;
rotationCurrentFrame = transform.rotation;
positionCurrentFrame = transform.position;
}
public void ApplyDeltaTranslationTo(Transform target)
{
target.Translate(GetDeltaTranslation(), Space.World);
}
public void ApplyDeltaRotationTo(Transform target)
{
target.rotation *= GetDeltaRotation();
}
public void ApplyDeltaTranslationRotationTo(Transform target)
{
Vector3 prevPos = target.position;
Quaternion prevRot = target.rotation;
target.SetPositionAndRotation(prevPos + GetDeltaTranslation(), prevRot * GetDeltaRotation());
}
/// <summary>
/// Will return the target.position in obstacle local space. The method should
/// be called when entering the platform. Use the returned local position for
/// future placement on the obstacle
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
public Vector3 GetObstacleLocalPositionOnEntering(Transform target)
{
return transform.InverseTransformPoint(target.position);
}
/// <summary>
/// Takes the local position the target had on entering the platform and the global position change of the target since the platform was entered,
/// and returns the new global position for the target
/// </summary>
/// <param name="target">the object to apply the position changes to</param>
/// <param name="obstacleLocalPosOnEntering">the local position that was returned by calling GetObstacleLocalPositionOnEntering when entering the obstacle</param>
/// <param name="globalMovementSinceEntering">The global delta movement of the target since the target entered the obstacle</param>
/// <returns></returns>
public Vector3 GetGlobalPositionOnObstacleFor(Transform target, Vector3 obstacleLocalPosOnEntering, Vector3 globalMovementSinceEntering)
{
return transform.TransformPoint(obstacleLocalPosOnEntering) + globalMovementSinceEntering;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment