291 lines
12 KiB
C#
291 lines
12 KiB
C#
using System;
|
|
using Drawing;
|
|
using log4net.Appender;
|
|
using NodeCanvas.Framework;
|
|
using ParadoxNotion.Design;
|
|
using ParadoxNotion.Services;
|
|
using Reset.Core.Tools;
|
|
using Reset.Units;
|
|
using Sirenix.Serialization;
|
|
using Unity.Cinemachine;
|
|
using UnityEngine;
|
|
|
|
|
|
namespace NodeCanvas.Tasks.Actions {
|
|
|
|
[Category("Reset/Movement")]
|
|
[Description("Pulls the agent towards a position with a spring-like effect")]
|
|
public class DoGrapplePull : ActionTask<UnitMovementHandler>{
|
|
public BBParameter<Vector3> grapplePoint;
|
|
public BBParameter<Vector3> offset;
|
|
|
|
public BBParameter<float> pullAccelerationSpeed;
|
|
public BBParameter<float> pullDeaccelerationSpeed;
|
|
|
|
[Tooltip("X is minimum speed, Y is maximum speed")]
|
|
public BBParameter<Vector2> pullTimeRange;
|
|
[Tooltip("X is the distance where the curve will first be evaluated, Y is the distance where the curve will last be evaluated")]
|
|
public BBParameter<Vector2> pullSpeedRange;
|
|
|
|
public BBParameter<float> slowdownDistance;
|
|
|
|
public BBParameter<AnimationCurve> pullSpeedCurve;
|
|
public BBParameter<AnimationCurve> endDeaccelerationCurve;
|
|
|
|
private float startTime;
|
|
|
|
private Vector3 velocityOnStart;
|
|
private Vector3 directionOnStart;
|
|
|
|
private Vector3 originalDirection;
|
|
|
|
public float breakAtDistance;
|
|
public float breakAtDotProduct;
|
|
|
|
private float currentSpeed;
|
|
private Vector3 smoothedInput;
|
|
private Vector3 smoothedInputRefVelocity;
|
|
|
|
private Vector3 gizmoSwingDirection;
|
|
private Vector3 gizmoPointDirection;
|
|
private Vector3 gizmoFinalDirection;
|
|
private Vector3 gizmosSmoothedInput;
|
|
private float gizmoVertValue;
|
|
|
|
private Transform camera;
|
|
|
|
private float referenceSpeed;
|
|
|
|
private Vector3 finalDirection;
|
|
private float yChangeMultipler;
|
|
|
|
//Use for initialization. This is called only once in the lifetime of the task.
|
|
//Return null if init was successfull. Return an error string otherwise
|
|
protected override string OnInit(){
|
|
DebugOverlayDrawer.AddOnOverlay("Grapple", "Composite Swing Direction", Vector3.zero);
|
|
DebugOverlayDrawer.AddOnOverlay("Grapple", "Target Swing Direction", Vector3.zero);
|
|
DebugOverlayDrawer.AddOnOverlay("Grapple", "Smoothed Input", Vector3.zero);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
//This is called once each time the task is enabled.
|
|
//Call EndAction() to mark the action as finished, either in success or failure.
|
|
//EndAction can be called from anywhere.
|
|
protected override void OnExecute(){
|
|
camera = Camera.main.transform;
|
|
MonoManager.current.onLateUpdate += DrawGrappleGizmo;
|
|
// Set the initial direction
|
|
directionOnStart = agent.transform.position.DirectionTo(grapplePoint.value);
|
|
|
|
// Get the current move direction
|
|
velocityOnStart = agent.outputMoveDirection;
|
|
|
|
// Lerp the initial direction more towards the point of the grapple and less towards current momentum if not moving fast
|
|
finalDirection = Vector3.Lerp(velocityOnStart, directionOnStart, velocityOnStart.magnitude / 10f);
|
|
|
|
startTime = Time.time;
|
|
currentSpeed = pullSpeedCurve.value[0].value * pullSpeedRange.value.y;
|
|
|
|
smoothedInput = agent.GetComponent<CharacterController>().velocity.normalized.Flatten(null, 0f, 0f);
|
|
}
|
|
|
|
//Called once per frame while the action is active.
|
|
protected override void OnUpdate(){
|
|
// Get direction to the point
|
|
Vector3 directionToPoint = agent.transform.position.DirectionTo(grapplePoint.value);
|
|
|
|
// Calculate input
|
|
Vector2 rawInput = agent.GetComponent<PlayerControls>().rawMoveInput;
|
|
Vector3 input = new(rawInput.x, rawInput.y, 0f);
|
|
|
|
smoothedInput = Vector3.SmoothDamp(smoothedInput, input, ref smoothedInputRefVelocity, 2);
|
|
DebugOverlayDrawer.ChangeValue("Grapple", "Smoothed Input", smoothedInput.ToString());
|
|
|
|
// Change input handling based on position
|
|
if (directionToPoint.y < 0) {
|
|
|
|
} else {
|
|
}
|
|
|
|
// Create the distance variables
|
|
float currentDist = Vector3.Distance(agent.transform.position, grapplePoint.value);
|
|
|
|
// Calculate the swing direction.
|
|
// Vector3 swingDirection = Quaternion.LookRotation(smoothedInput) * directionToPoint * smoothedInput.magnitude; // Old
|
|
Vector3 sidewaysSwingAngle = Quaternion.AngleAxis(90f, Vector3.up) * directionToPoint;
|
|
Vector3 upwardsSwingAngle = Quaternion.AngleAxis(-90f, Vector3.right) * directionToPoint;
|
|
// Vector3 downwardsSwingAngle = Quaternion.AngleAxis(90f, Vector3.right) * directionToPoint; // why not just use upwards but negative based on input on Y
|
|
|
|
// Create the composite swing direction and the target swing direction
|
|
// The composite is the output while the target is the one used in calculating
|
|
Vector3 compositeSwingDirection;
|
|
Vector3 targetSwingDirection;
|
|
|
|
// if (directionToPoint.y > 0) {
|
|
DebugOverlayDrawer.ChangeValue("Grapple", "Target Swing Direction", Mathf.Abs((smoothedInput.y + 1f) / 2).ToString());
|
|
Vector3 swingAngleAbovePoint = -upwardsSwingAngle;
|
|
|
|
if (Mathf.Abs(smoothedInput.y) > .01f){
|
|
swingAngleAbovePoint = Vector3.Slerp(-upwardsSwingAngle, upwardsSwingAngle, Mathf.Abs((smoothedInput.y + 1f) / 2));
|
|
}
|
|
Vector3 axisFromInput = Vector3.zero;
|
|
|
|
if (smoothedInput.x > 0) {
|
|
axisFromInput = Vector3.Slerp(swingAngleAbovePoint, sidewaysSwingAngle, smoothedInput.x);
|
|
}
|
|
|
|
if (smoothedInput.x < 0) {
|
|
axisFromInput = Vector3.Slerp(swingAngleAbovePoint, -sidewaysSwingAngle, Mathf.Abs(smoothedInput.x));
|
|
}
|
|
|
|
compositeSwingDirection = Vector3.Slerp(swingAngleAbovePoint, axisFromInput, smoothedInput.x);
|
|
// } else {
|
|
// compositeSwingDirection = Vector3.Slerp(upwardsSwingAngle, sidewaysSwingAngle, smoothedInput.magnitude);
|
|
// }
|
|
|
|
// Some math for getting the Y
|
|
yChangeMultipler = Mathf.Lerp(yChangeMultipler, 0f, elapsedTime * .5f); // Starts at 1 so that the player has more ability to change height on start of swing, then smooths to zero
|
|
|
|
DebugOverlayDrawer.ChangeValue("Grapple", "Composite Swing Direction", compositeSwingDirection.ToString());
|
|
Debug.Log(Vector3.Dot(directionToPoint, Vector3.down));
|
|
|
|
// Speed
|
|
float evaluatedSpeed = pullSpeedCurve.value.Evaluate(Mathf.Clamp((Time.time - startTime) / 6f, 0f, Mathf.Infinity));
|
|
float speedAgainstCurve = Mathf.Lerp(pullSpeedRange.value.x, pullSpeedRange.value.y, evaluatedSpeed);
|
|
|
|
// Find how far from 0-1 the player is from the max and minimum distance
|
|
// Get the base distance then account for the minimum distance to the point so that being the minimum away will Lerp to 1
|
|
// float currentDistMinimumAccounted = (currentDist - pullSpeedDistances.value.x);
|
|
|
|
if (currentDist < slowdownDistance.value) {
|
|
float change = endDeaccelerationCurve.value.Evaluate((slowdownDistance.value - currentDist) / slowdownDistance.value);
|
|
speedAgainstCurve = speedAgainstCurve * change;
|
|
|
|
// Debug.Log($"prev: {speedAgainstCurve}, norm: {(slowdownDistance.value - currentDist) / slowdownDistance.value}, change: {change}, output: {speedAgainstCurve * change} ");
|
|
}
|
|
|
|
// Evaluate the normalized value
|
|
// float normaled = Mathf.Lerp(0, 1f, 1f - elapsedTime / (pullSpeedDistances.value.y - pullSpeedDistances.value.x));
|
|
|
|
// Use the curve evaluation to set the speed
|
|
// float outputSpeed = Mathf.Lerp(pullTimeRange.value.x, pullTimeRange.value.y, evaluatedSpeed);
|
|
|
|
// Soften the speed changes
|
|
currentSpeed = Mathf.Lerp(currentSpeed, speedAgainstCurve, 10f * Time.deltaTime);
|
|
|
|
// Gizmos
|
|
gizmoVertValue = finalDirection.y;
|
|
gizmosSmoothedInput = smoothedInput;
|
|
gizmoPointDirection = directionToPoint;
|
|
gizmoSwingDirection = swingAngleAbovePoint;
|
|
gizmoFinalDirection = finalDirection;
|
|
|
|
//Test
|
|
finalDirection = gizmoSwingDirection;
|
|
|
|
|
|
agent.SetNewDirection(finalDirection.Flatten(null, 0));
|
|
agent.SetNewGravity(finalDirection.y);
|
|
agent.SmoothToSpeed(0f, 1f * Time.deltaTime, out referenceSpeed);
|
|
|
|
// agent.SmoothToDirection(finalDirection.Flatten(null, 0).normalized * evaluatedSpeed, 1f * Time.deltaTime, out referenceDirection);
|
|
// agent.SmoothToGravitation(finalDirection.y, 1f, out referenceGravity);
|
|
|
|
if (Vector3.Dot(directionOnStart, directionToPoint.normalized) < breakAtDotProduct) {
|
|
// EndAction(true);
|
|
} else if (currentDist < breakAtDistance) {
|
|
EndAction(true);
|
|
}
|
|
}
|
|
|
|
public void DrawGrappleGizmo(){
|
|
// Destination gizmos
|
|
using (Draw.WithColor(Color.blue)){
|
|
Vector3 offsetTowardsCamera = grapplePoint.value.DirectionTo(camera.transform.position);
|
|
|
|
// Grapple Point
|
|
Draw.SolidCircle(grapplePoint.value + offsetTowardsCamera, grapplePoint.value.DirectionTo(camera.transform.position), .4f);
|
|
Draw.Label2D(grapplePoint.value + offsetTowardsCamera * 2f + Vector3.up, "Grapple Point");
|
|
|
|
using (Draw.WithLineWidth(1.5f)) {
|
|
// Final Direction
|
|
Draw.Line(agent.transform.position + Vector3.up, agent.transform.position + Vector3.up + gizmoFinalDirection.normalized * 2f);
|
|
Draw.ArrowheadArc(agent.transform.position + Vector3.up, gizmoFinalDirection.normalized, 2f, 15f);
|
|
|
|
// Colors for faded arrows
|
|
Color swingColor = Color.Lerp(Color.blue, Color.blue.Alpha(.4f), (elapsedTime * .6f));
|
|
Color dirColor = Color.Lerp(Color.blue.Alpha(.4f), Color.blue, (elapsedTime * .6f));
|
|
|
|
// Swing Direction
|
|
using (Draw.WithColor(swingColor)) {
|
|
float swingLength = 2.2f;
|
|
Vector3 swingStart = agent.transform.position + Vector3.up * .4f;
|
|
Vector3 swingDir = swingStart + gizmoSwingDirection.normalized * swingLength;
|
|
Draw.DashedLine(swingStart, swingDir, .2f, .2f);
|
|
Draw.ArrowheadArc(swingStart, gizmoSwingDirection.normalized, swingLength, 15f);
|
|
Draw.Label2D(swingDir + Vector3.up * .4f, "Swing Direction");
|
|
}
|
|
|
|
// Point Direction
|
|
using (Draw.WithColor(dirColor)) {
|
|
float pointLength = 1.2f;
|
|
Vector3 pointStart = agent.transform.position + Vector3.up * .2f;
|
|
Vector3 pointDir = pointStart + gizmoPointDirection.normalized * pointLength;
|
|
Draw.DashedLine(pointStart, pointDir, .2f, .2f);
|
|
Draw.ArrowheadArc(pointStart, gizmoPointDirection.normalized, pointLength, 15f);
|
|
Draw.Label2D(pointDir + Vector3.up * .4f, "Grapple Point Direction");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Input Gizmos
|
|
using (Draw.WithColor(Color.red)) {
|
|
// Input left and right, up and down for size
|
|
Vector3 inputGizmoOffset = (agent.transform.position + camera.rotation * Vector3.back + Vector3.up * .5f);
|
|
Vector3 inputGizmoPosition = inputGizmoOffset + camera.rotation * Vector3.Lerp(Vector3.left, Vector3.right, (gizmosSmoothedInput.x - 1 ) / 2f + 1f);
|
|
Draw.Line(inputGizmoOffset + camera.rotation * Vector3.left, inputGizmoOffset + camera.rotation * Vector3.right);
|
|
Draw.SolidCircle(inputGizmoPosition, inputGizmoPosition.DirectionTo(camera.position), Mathf.Lerp(.2f, .6f, (gizmosSmoothedInput.y - 1 ) / 2f + 1f));
|
|
}
|
|
|
|
// Up and down
|
|
using (Draw.WithColor(Color.yellow)) {
|
|
Vector3 vertGizmoPosition = agent.transform.position + camera.rotation * Vector3.left;
|
|
float vertGizmoWidth = .25f;
|
|
float vertGizmoHeight = 1.75f;
|
|
|
|
Vector3 vertGizmoStart = vertGizmoPosition + Vector3.up * vertGizmoHeight;
|
|
Vector3 vertGizmoEnd = vertGizmoPosition + Vector3.up * .35f;
|
|
|
|
Vector3 circlePos = Vector3.Lerp(vertGizmoEnd, vertGizmoStart, gizmoVertValue);
|
|
|
|
Draw.Line(vertGizmoStart, vertGizmoEnd);
|
|
Draw.SolidCircle(circlePos, circlePos.DirectionTo(camera.position), .4f);
|
|
Draw.Label2D(vertGizmoStart + camera.rotation * Vector3.left * 1.5f, gizmoVertValue.ToString());
|
|
|
|
Vector3 vertArrowUpPosition = vertGizmoStart + camera.rotation * Vector3.left * 1f + Vector3.up * .2f;
|
|
Vector3 vertArrowDownPosition = vertGizmoStart + camera.rotation * Vector3.left * 1f + Vector3.down * .2f;
|
|
|
|
if (gizmoVertValue > 0) {
|
|
Draw.SolidTriangle(vertArrowUpPosition + camera.rotation * Vector3.left/4, vertArrowUpPosition + Vector3.up/2, vertArrowUpPosition + camera.rotation * Vector3.right/4);
|
|
} else {
|
|
Draw.SolidTriangle(vertArrowDownPosition + camera.rotation * Vector3.left/4, vertArrowDownPosition + Vector3.down/2, vertArrowDownPosition + camera.rotation * Vector3.right/4);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//Called when the task is disabled.
|
|
protected override void OnStop() {
|
|
MonoManager.current.onLateUpdate -= DrawGrappleGizmo;
|
|
}
|
|
|
|
//Called when the task is paused.
|
|
protected override void OnPause() {
|
|
|
|
}
|
|
}
|
|
} |