169 lines
5.9 KiB
C#
169 lines
5.9 KiB
C#
|
using UnityEngine;
|
||
|
using NeoFPS.CharacterMotion;
|
||
|
using NeoFPS.CharacterMotion.MotionData;
|
||
|
using NeoFPS.CharacterMotion.Parameters;
|
||
|
using NeoFPS.CharacterMotion.States;
|
||
|
using NeoSaveGames.Serialization;
|
||
|
|
||
|
namespace NeoFPS.CharacterMotion.States
|
||
|
{
|
||
|
[MotionGraphElement("Misc/GrappleSwingState", "GrappleSwingState")]
|
||
|
[HelpURL("https://docs.neofps.com/manual/motiongraphref-mgs-grappleswingstate.html")]
|
||
|
public class GrappleSwingState : MotionGraphState
|
||
|
{
|
||
|
[SerializeField, Tooltip("The point in space that the grapple is tethered to.")]
|
||
|
private VectorParameter m_GrapplePoint = null;
|
||
|
|
||
|
[SerializeField, Tooltip("When entering the state, a target distance will be calculated based on multiplying the current distance to the grapple point by this multiplier.")]
|
||
|
private float m_TargetDistanceMultiplier = 0.75f;
|
||
|
|
||
|
[SerializeField, Tooltip("Below this distance from the grapple point, the character will actually be pushed away.")]
|
||
|
private float m_MinDistance = 2f;
|
||
|
|
||
|
[SerializeField, Tooltip("The acceleration towards the grapple point per meter distance above the target distance.")]
|
||
|
private float m_AccelerationPerMeter = 15f;
|
||
|
|
||
|
[SerializeField, Tooltip("The maximum acceleration towards the grapple point.")]
|
||
|
private float m_MaxAccel = 40f;
|
||
|
|
||
|
private Vector3 m_OutVelocity = Vector3.zero;
|
||
|
private float m_TargetLength = 0f;
|
||
|
|
||
|
public override bool completed
|
||
|
{
|
||
|
get { return m_GrapplePoint == null || m_GrapplePoint.value == Vector3.zero; }
|
||
|
}
|
||
|
|
||
|
public override Vector3 moveVector
|
||
|
{
|
||
|
get { return m_OutVelocity * Time.deltaTime; }
|
||
|
}
|
||
|
|
||
|
public override bool applyGravity
|
||
|
{
|
||
|
get { return true; }
|
||
|
}
|
||
|
|
||
|
public override bool applyGroundingForce
|
||
|
{
|
||
|
get { return false; }
|
||
|
}
|
||
|
|
||
|
public override void OnValidate()
|
||
|
{
|
||
|
base.OnValidate();
|
||
|
}
|
||
|
|
||
|
public override bool CheckCanEnter()
|
||
|
{
|
||
|
return m_GrapplePoint != null && m_GrapplePoint.value != Vector3.zero;
|
||
|
}
|
||
|
|
||
|
public override void OnEnter()
|
||
|
{
|
||
|
base.OnEnter();
|
||
|
|
||
|
m_TargetLength = Vector3.Magnitude(m_GrapplePoint.value - GetCenterPoint()) * m_TargetDistanceMultiplier;
|
||
|
if (m_TargetLength < m_MinDistance)
|
||
|
m_TargetLength = m_MinDistance;
|
||
|
}
|
||
|
|
||
|
public override void OnExit()
|
||
|
{
|
||
|
base.OnExit();
|
||
|
m_OutVelocity = Vector3.zero;
|
||
|
}
|
||
|
|
||
|
Vector3 GetCenterPoint()
|
||
|
{
|
||
|
return controller.localTransform.position + controller.localTransform.up * characterController.height;
|
||
|
}
|
||
|
|
||
|
public override void Update()
|
||
|
{
|
||
|
base.Update();
|
||
|
|
||
|
m_OutVelocity = characterController.velocity;
|
||
|
|
||
|
|
||
|
if (m_GrapplePoint.value != Vector3.zero)
|
||
|
{
|
||
|
var deltaPos = m_GrapplePoint.value - GetCenterPoint();
|
||
|
float distance = Vector3.Magnitude(deltaPos);
|
||
|
if (distance > m_TargetLength)
|
||
|
{
|
||
|
deltaPos.Normalize();
|
||
|
float pull = m_AccelerationPerMeter * (distance - m_TargetLength);
|
||
|
if (pull > m_MaxAccel)
|
||
|
pull = m_MaxAccel;
|
||
|
pull *= Time.deltaTime;
|
||
|
|
||
|
if (Vector3.Dot(m_OutVelocity, deltaPos) < 0f)
|
||
|
{
|
||
|
Vector3 target = Vector3.ProjectOnPlane(m_OutVelocity, deltaPos);
|
||
|
m_OutVelocity = Vector3.Lerp(m_OutVelocity, target, 0.25f);
|
||
|
}
|
||
|
|
||
|
m_OutVelocity += deltaPos * pull;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (distance < m_MinDistance)
|
||
|
{
|
||
|
deltaPos.Normalize();
|
||
|
float push = m_AccelerationPerMeter * (m_MinDistance - distance);
|
||
|
if (push > m_MaxAccel)
|
||
|
push = m_MaxAccel;
|
||
|
push *= -Time.deltaTime;
|
||
|
|
||
|
if (Vector3.Dot(m_OutVelocity, deltaPos) > 0f)
|
||
|
{
|
||
|
Vector3 target = Vector3.ProjectOnPlane(m_OutVelocity, deltaPos);
|
||
|
m_OutVelocity = Vector3.Lerp(m_OutVelocity, target, 0.25f);
|
||
|
}
|
||
|
|
||
|
m_OutVelocity += deltaPos * push;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (Vector3.Dot(m_OutVelocity, deltaPos) < 0f)
|
||
|
{
|
||
|
Vector3 target = Vector3.ProjectOnPlane(m_OutVelocity, deltaPos);
|
||
|
m_OutVelocity = Vector3.Lerp(m_OutVelocity, target, 0.25f);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void ChangeFrameOfReference(Vector3 deltaPos, Quaternion deltaRot)
|
||
|
{
|
||
|
base.ChangeFrameOfReference(deltaPos, deltaRot);
|
||
|
m_GrapplePoint.value = Vector3.zero;
|
||
|
}
|
||
|
|
||
|
public override void CheckReferences(IMotionGraphMap map)
|
||
|
{
|
||
|
m_GrapplePoint = map.Swap(m_GrapplePoint);
|
||
|
base.CheckReferences(map);
|
||
|
}
|
||
|
|
||
|
private static readonly NeoSerializationKey k_TargetLengthKey = new NeoSerializationKey("targetLength");
|
||
|
|
||
|
/*
|
||
|
public override void WriteProperties(INeoSerializer writer)
|
||
|
{
|
||
|
base.WriteProperties(writer);
|
||
|
// Optional - write any data saved by the NeoSave system here
|
||
|
writer.WriteValue(k_OutVelocityKey, m_OutVelocity);
|
||
|
}
|
||
|
|
||
|
public override void ReadProperties(INeoDeserializer reader)
|
||
|
{
|
||
|
base.ReadProperties(reader);
|
||
|
// Optional - read any data saved by the NeoSave system here
|
||
|
reader.TryReadValue(k_OutVelocityKey, out m_OutVelocity, m_OutVelocity);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
}
|