Skip to content

Instantly share code, notes, and snippets.

@beardordie
Last active August 28, 2021 15:27
Show Gist options
  • Save beardordie/38444475d51b16b4e5f885cc245af060 to your computer and use it in GitHub Desktop.
Save beardordie/38444475d51b16b4e5f885cc245af060 to your computer and use it in GitHub Desktop.
Unity - simple 2D auto movement component with nice Gizmo, separated from Unity Playground, added two movement types, follows Open/Closed principle
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class AutoMover2D : MonoBehaviour
{
public enum AutoMovementType
{
AddForceEveryFrame,
AddImpulseForce,
Translate
}
public AutoMovementType movementType = AutoMovementType.AddForceEveryFrame;
// These are the forces that will push the object every frame
// don't forget they can be negative too!
public Vector2 forceDirection = new Vector2(1f, 0f);
public float forceMultiplier = 2f;
[Tooltip("Clamp the velocity, only enforced for AddForceEveryFrame")] public float maxVelocity = 20f;
//is the push relative or absolute to the world?
public bool relativeToRotation = true;
//mesh to use as the Gizmo arrow, should be a mesh with an arrow pointed straight upwards
public Mesh gizmoMoveArrowMesh; // use this: https://github.com/Unity-Technologies/UnityPlayground/blob/master/Assets/_INTERNAL_/Resources/Meshes/MoveArrow.fbx
protected new Rigidbody2D rigidbody2D;
protected virtual void Awake()
{
rigidbody2D = GetComponent<Rigidbody2D>();
}
protected virtual void Start()
{
if (movementType == AutoMovementType.AddImpulseForce)
{
AddImpulseForce();
}
}
protected virtual void Update()
{
if (movementType == AutoMovementType.Translate)
{
TranslateTick();
}
}
protected virtual void FixedUpdate()
{
if (movementType == AutoMovementType.AddForceEveryFrame)
{
AddForceTick();
}
}
public virtual void TranslateTick()
{
if (relativeToRotation)
{
transform.Translate(forceDirection * forceMultiplier, Space.Self);
}
else
{
transform.Translate(forceDirection * forceMultiplier, Space.World);
}
}
public virtual void AddForceTick()
{
if (!ExceedingMaxVelocity())
{
if (relativeToRotation)
{
rigidbody2D.AddRelativeForce(forceDirection * forceMultiplier);
}
else
{
rigidbody2D.AddForce(forceDirection * forceMultiplier);
}
}
ClampVelocity();
}
public virtual void AddImpulseForce()
{
if (relativeToRotation)
{
rigidbody2D.AddRelativeForce(forceDirection * forceMultiplier, ForceMode2D.Impulse);
}
else
{
rigidbody2D.AddForce(forceDirection * forceMultiplier, ForceMode2D.Impulse);
}
ClampVelocity();
}
protected virtual bool ExceedingMaxVelocity()
{
if (rigidbody2D.velocity.x >= maxVelocity || rigidbody2D.velocity.y >= maxVelocity) return true;
return false;
}
protected virtual void ClampVelocity()
{
rigidbody2D.velocity = new Vector2(Mathf.Clamp(rigidbody2D.velocity.x, -maxVelocity, maxVelocity),
Mathf.Clamp(rigidbody2D.velocity.y, -maxVelocity, maxVelocity));
}
//Draw an arrow to show the direction in which the object will move
protected virtual void OnDrawGizmosSelected()
{
if (enabled)
{
float extraAngle = (relativeToRotation) ? transform.rotation.eulerAngles.z : 0f;
DrawMoveArrowGizmo(transform.position, forceDirection, extraAngle);
}
}
protected virtual void DrawMoveArrowGizmo(Vector3 position, Vector2 direction, float extraAngle = 0f, float scale = 0f)
{
DrawGizmo(gizmoMoveArrowMesh, position, direction, extraAngle, scale);
}
//Draws a gizmo in a certain direction, with support for an extraAngle (to make it relative to the GameObject's rotation) and a specific scale
protected virtual void DrawGizmo(Mesh meshToDraw, Vector3 position, Vector2 direction, float extraAngle, float scale)
{
Gizmos.color = Color.green;
float arrowAngle = Angle(direction);
if (scale == 0f)
{
//calculate it from the direction
scale = direction.magnitude;
}
Gizmos.DrawMesh(meshToDraw, position, Quaternion.AngleAxis(arrowAngle + extraAngle, Vector3.forward), Vector3.one * scale);
}
protected virtual float Angle(Vector2 inputVector)
{
if (inputVector.x < 0) return (Mathf.Atan2(inputVector.x, inputVector.y) * Mathf.Rad2Deg * -1) - 360;
else return -Mathf.Atan2(inputVector.x, inputVector.y) * Mathf.Rad2Deg;
}
}
using UnityEngine;
public class ManualMover2D : AutoMover2D
{
private bool hasStarted = false;
protected override void Start()
{
}
protected override void Update()
{
if(hasStarted)
base.Update();
}
protected override void FixedUpdate()
{
if(hasStarted)
base.FixedUpdate();
}
// Call this from outside the class, which makes this a manual Mover2D, not an AutoMover2D
[ContextMenu("Begin Movement")]
public void BeginMovement()
{
if(movementType == AutoMovementType.AddForceEveryFrame || movementType == AutoMovementType.Translate)
{
hasStarted = true;
}
else if(movementType == AutoMovementType.AddImpulseForce)
{
AddImpulseForce();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment