A neat action that knocks a game object back based on its hit direction. This one is not physics-based. I'll probably make that one later...
// (c) Copyright HutongGames, LLC 2010-2018. All rights reserved.
// author : ransomink
// Keywords: back, gameobject, knock, knockback
/*--- __ECO__ __PLAYMAKER__ __ACTION__ ---*/
using UnityEngine;
namespace HutongGames.PlayMaker.Actions
{
[ActionCategory(ActionCategory.GameObject)]
[Tooltip("Knock back a GameObject based on its hit direction.")]
public class KnockbackGameObject : FsmStateAction
{
[RequiredField]
[UIHint(UIHint.Variable)]
[Tooltip("GameObject to knockback.")]
public FsmOwnerDefault gameObject;
[RequiredField]
[Tooltip("Target GameObject.")]
public FsmGameObject target;
[RequiredField]
[Tooltip("Amount of force applied to the game object.")]
public FsmFloat force;
[RequiredField]
[Tooltip("Vertical force applied to the game object.")]
public FsmFloat height;
[RequiredField]
[Tooltip("Length in seconds of knockback.")]
public FsmFloat duration;
[Tooltip("Knockback animation curve")]
public FsmAnimationCurve animationCurve;
[Tooltip("Use unscaled time. Not affected by Time.timeScale (slow motion effects).")]
public bool realTime;
/// <summary>
/// The gameObject Transform.
/// </summary>
private Transform _t;
/// <summary>
/// Knockback position.
/// </summary>
private Vector3 _knockbackPos;
/// <summary>
/// Local position of the gameObject.
/// </summary>
private Vector3 _localPos;
/// <summary>
/// Direction to move towards.
/// </summary>
private Vector3 _direction;
/// <summary>
/// Beginning of knockback.
/// </summary>
private float _startTime;
/// <summary>
/// End of knockback.
/// </summary>
private float _endTime;
/// <summary>
/// Knockback the gameobject?
/// </summary>
private bool _knockback;
/// <summary>
/// Get the current time.
/// </summary>
private float CurrentTime
{
get { return realTime ? Time.unscaledTime : Time.time; }
}
public override void Reset()
{
gameObject = null;
target = null;
force = null;
height = null;
duration = 0.5f;
animationCurve = null;
realTime = false;
}
public override void OnEnter()
{
DoKnockback();
}
public override void OnUpdate()
{
if ( _knockback )
{
if ( CurrentTime >= _endTime )
{
_knockback = false;
Finish();
}
else
{
Move();
}
}
}
void DoKnockback()
{
var go = Fsm.GetOwnerDefaultTarget( gameObject );
if ( go == null || target == null )
{
return;
}
_t = go.transform;
_localPos = Vector3.zero;
_direction = Vector3.zero;
_startTime = CurrentTime;
_endTime = _startTime + duration.Value;
var a = _t.position;
var b = target.Value.transform.position;
_direction.Set( ( b.x - a.x ), ( b.y - a.y ), ( b.z - a.z ) );
_direction = _direction.normalized;
_localPos = _t.localPosition;
_direction.y = -height.Value;
_knockbackPos = _t.position - ( _direction * force.Value );
_knockback = true;
}
void Move()
{
_t.localPosition = Vector3.Lerp( _localPos, _knockbackPos, animationCurve.curve.Evaluate( Mathf.InverseLerp( _startTime, _endTime, CurrentTime ) ) );
}
}
}