change: separated all functions of movement into separate tasks

This commit is contained in:
Chris
2025-08-09 16:02:55 -04:00
parent 0e71be73da
commit 70453b8117
13 changed files with 263 additions and 158 deletions

View File

@@ -0,0 +1,48 @@
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace Reset.Movement {
[Category("Reset/Movement")]
[Description("Finalize the move direction to the agent's CharacterController")]
public class FinalizeMovement : ActionTask<CharacterController>{
public BBParameter<Vector3> moveDirection;
public BBParameter<float> currentSpeed;
//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() {
if (currentSpeed == null || !currentSpeed.useBlackboard) {
Debug.LogError("This <b>Finalize Movement</b> does not have it's current value attached to a Blackboard variable. Nothing will happen.", agent.gameObject);
}
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(){
}
//Called once per frame while the action is active.
protected override void OnUpdate(){
Vector3 usableVector3 = new Vector3(moveDirection.value.x * currentSpeed.value, moveDirection.value.y, moveDirection.value.z * currentSpeed.value);
agent.Move(Camera.main.transform.rotation * usableVector3 * Time.deltaTime);
Debug.Log("Finalize Done");
// EndAction(true);
}
//Called when the task is disabled.
protected override void OnStop() {
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fea4d34f26d30b24e8cb99acf1766b6f

View File

@@ -1,118 +0,0 @@
using System;
using System.Collections;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using ParadoxNotion.Services;
using Unity.Cinemachine;
using Unity.Mathematics;
using UnityEngine;
using Reset.Movement;
namespace Reset.Movement{
public enum PlayerFacingDirection{
Target = 0,
Movement,
MatchCamera,
Static
}
}
namespace NodeCanvas.Tasks.Actions {
[Category("Reset/Movement")]
[Description("Finalizes movement and sends the final move commands to the controller")]
public class ProcessMovement : ActionTask<CharacterController>{
public BBParameter<Vector3> groundMoveDirection;
public BBParameter<Vector3> airMoveDirection;
// Rotation
public BBParameter<PlayerFacingDirection> playerFacingDirection;
private float lastLookMagnitude;
private Vector3 currentMoveDir;
// References
private PlayerControls controls;
//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() {
// Append the late update method to actually happen on late update
// Reference to controls
controls = agent.GetComponent<PlayerControls>();
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(){
currentMoveDir = groundMoveDirection.value;
}
//Called once per frame while the action is active.
protected override void OnUpdate(){
// Construct move direction
Vector3 finalMoveDir = Vector3.zero;
// Change how input is managed based on facing state
currentMoveDir = Vector3.Slerp(currentMoveDir, groundMoveDirection.value, 1f * Time.deltaTime); // NOTE: This used to be t: currentRotSpeed * Time.deltaTime.
// See how it feels with a hard set value and go fro there.
// Add input movement
if (agent.isGrounded){
finalMoveDir += currentMoveDir; // + Vector3.down * .03f;
} else {
finalMoveDir += currentMoveDir;
}
switch (playerFacingDirection.value) {
}
finalMoveDir += new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y);
// Do final movement
if (agent.isGrounded) {
agent.Move((Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0f, null, 0f)) * finalMoveDir) * Time.deltaTime);
} else {
agent.Move((Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0f, null, 0f)) * finalMoveDir) * Time.deltaTime);
// agent.Move((finalMoveDir) * Time.deltaTime);
}
// ???? Moved this above but don't remember if this needs to be here still
// if (agent.isGrounded) {
// jumpPower.value = 0f;
// }
EndAction(true);
}
// Gravity is processed in LateUpdate (added to MonoManager's onLateUpdate in OnInit())
//Called when the task is disabled.
protected override void OnStop() {
EndAction(true);
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -3,12 +3,12 @@ using ParadoxNotion.Design;
using ParadoxNotion.Services;
using UnityEngine;
namespace Reset.Movement {
[Category("Reset/Movement")]
[Description("Process Y-axis movement for the agent")]
public class ProcessGravity : ActionTask<CharacterController>{
// TODO: Rename to UpdateGravitytDirection
public class UpdateGravityDirection : ActionTask<CharacterController>{
public BBParameter<Vector3> moveDirection;
public BBParameter<float> jumpPower;
public BBParameter<float> jumpPowerDecay;
@@ -16,7 +16,6 @@ namespace Reset.Movement {
[Space(5)]
public BBParameter<float> gravityAcceleration = 1f;
public BBParameter<float> gravityMax = 8f;
public BBParameter<float> gravityPower;
@@ -31,7 +30,6 @@ namespace Reset.Movement {
//Call EndAction() to mark the action as finished, either in success or failure.
//EndAction can be called from anywhere.
protected override void OnExecute() {
}
//Called once per frame while the action is active.
@@ -40,19 +38,21 @@ namespace Reset.Movement {
gravityPower.value += gravityAcceleration.value * Time.deltaTime;
gravityPower.value = Mathf.Min(gravityPower.value, gravityMax.value);
Vector3 gravityMoveDirection;
gravityMoveDirection = new(0f, jumpPower.value + (Physics.gravity.y * gravityPower.value), 0f);
// Reset gravity power when grounded
agent.Move((gravityMoveDirection) * Time.deltaTime);
// Apply a constant gravity if the player is grounded
if (agent.isGrounded) {
gravityPower.value = 0f;
jumpPower.value = 0f;
gravityPower.value = .1f;
}
// Create the gravity direction
float gravityMoveDirection = jumpPower.value + Physics.gravity.y * gravityPower.value;
// Commit gravity to move direction, ignoring XZ since those are done in UpdateMovementDirection
moveDirection.value = new Vector3(moveDirection.value.x, gravityMoveDirection, moveDirection.value.z);
Debug.Log("Gravity Done");
EndAction(true);
}
public void LateUpdate(){
// Decay jump power

View File

@@ -0,0 +1,126 @@
using System;
using System.Collections;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using ParadoxNotion.Services;
using Unity.Cinemachine;
using Unity.Mathematics;
using UnityEngine;
using Reset.Movement;
namespace Reset.Movement{
public enum PlayerFacingDirection{
TowardsTarget = 0,
MatchForward,
MatchCamera,
Static
}
}
namespace NodeCanvas.Tasks.Actions {
[Category("Reset/Movement")]
[Description("Finalizes movement and sends the final move commands to the controller")]
// TODO: Rename to UpdateMovementDirection
public class UpdateMovementDirection : ActionTask<CharacterController>{
[ParadoxNotion.Design.Header("References")]
public BBParameter<Vector3> moveDirection;
// TODO: Remove this reference and let each copy of this use their own settings.
public BBParameter<PlayerFacingDirection> playerFacingDirection;
[ParadoxNotion.Design.Header("Settings")]
public BBParameter<float> accelerationSmoothing = 5f;
public BBParameter<float> deaccelerationSmoothing = 5f;
public BBParameter<AnimationCurve> deaccelerationCurve;
public BBParameter<float> directionChangeMinimumMagnitude; // Unused. Use to only make input change if it's over a certain input threshold. Maybe smoothing can affect this?
private float lastLookMagnitude;
private Vector3 currentMoveDir;
// References
private PlayerControls controls;
//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() {
// Reference to controls
controls = agent.GetComponent<PlayerControls>();
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(){
// Initialize the smoothed direction with the value as is on input
// currentMoveDir = new Vector3(moveDirection.value.x, moveDirection.value.y, moveDirection.value.z);
}
//Called once per frame while the action is active.
protected override void OnUpdate(){
// Construct move direction
Vector3 targetDirection = moveDirection.value;
// Get input value
Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y);
if (inputMovement.magnitude < .1f) {
inputMovement = Vector3.zero;
}
// Change how movement is managed based on facing state
switch (playerFacingDirection.value) {
case PlayerFacingDirection.TowardsTarget:
break;
case PlayerFacingDirection.MatchForward: // TODO: Recomment
// targetDirection = agent.transform.forward * inputMovement.magnitude;
targetDirection = inputMovement;
break;
case PlayerFacingDirection.MatchCamera:
targetDirection = Quaternion.Euler(Camera.main.transform.forward.DirectionTo(agent.transform.forward)) * inputMovement; // NOTE: This used to be t: currentRotSpeed * Time.deltaTime.
// See how it feels with a hard set value and go fro there.
break;
case PlayerFacingDirection.Static:
break;
default:
throw new ArgumentOutOfRangeException();
}
// Remove Y from variables
Vector3 targetNoY = new Vector3(targetDirection.x, 0f, targetDirection.z);
Vector3 currentNoY = new Vector3(currentMoveDir.x, 0f, currentMoveDir.z);
// Smooth movement
if (targetNoY.magnitude > currentNoY.magnitude) {
currentMoveDir = Vector3.Lerp(currentMoveDir, targetNoY,accelerationSmoothing.value * Time.deltaTime);
} else {
float deaccelValue = deaccelerationCurve.value.Evaluate(inputMovement.magnitude);
currentMoveDir = Vector3.Lerp(currentMoveDir, targetNoY, deaccelerationSmoothing.value * Time.deltaTime);
}
currentMoveDir.y = moveDirection.value.y;
// Commit move direction
moveDirection.value = currentMoveDir;
// Debug.Log(moveDirection.value);
EndAction(true);
}
// Gravity is processed in LateUpdate (added to MonoManager's onLateUpdate in OnInit())
//Called when the task is disabled.
protected override void OnStop() {
EndAction(true);
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace Reset.Movement {
[Category("Reset/Movement")]
[Description("Updates the movespeed for this agent")]
public class UpdateMovementSpeed : ActionTask{
public BBParameter<float> target;
public BBParameter<float> speed;
public BBParameter<float> smoothing = 10f;
private float currentSpeed;
//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() {
if (!speed.useBlackboard) {
Debug.LogError("This <b>Update Movement Speed</b> does not have it's current value attached to a Blackboard variable. Nothing will happen.", agent.gameObject);
}
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(){
// currentSpeed = speed.value;
}
//Called once per frame while the action is active.
protected override void OnUpdate(){
currentSpeed = Mathf.Lerp(currentSpeed, target.value, smoothing.value * Time.deltaTime);
speed.value = currentSpeed;
if (Mathf.Abs(currentSpeed - speed.value) < .01f) {
}
Debug.Log("Speed Done");
EndAction(true);
}
//Called when the task is disabled.
protected override void OnStop() {
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6a4c5896d783ad845861edd0c9eea14b

View File

@@ -8,7 +8,8 @@ using UnityEngine.TextCore.Text;
namespace Reset.Player.Movement {
[Category("Reset/Movement")]
[Description("Finalizes the character rotation and commits it to the Transform")]
public class ProcessRotation : ActionTask<CharacterController> {
// TODO: Rename to UpdateRotation
public class UpdateRotation : ActionTask<CharacterController> {
// Rotation
public BBParameter<Vector3> moveDirection;
@@ -25,24 +26,13 @@ namespace Reset.Player.Movement {
[ShowIf("playerFacingDirection", 0)]
public Vector3 rotationTargetPosition;
//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() {
controls = agent.GetComponent<PlayerControls>();
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() {
}
//Called once per frame while the action is active.
protected override void OnUpdate() {
// Calculate rotation speed
@@ -51,26 +41,21 @@ namespace Reset.Player.Movement {
// Set ingitial rotation power
currentRotSpeed = rotationSpeed.value;
// Get input value
Vector3 inputMovement = new Vector3(controls.rawMoveInput.x, 0f, controls.rawMoveInput.y);
switch (playerFacingDirection.value) {
case PlayerFacingDirection.Target:
case PlayerFacingDirection.TowardsTarget:
// Set rotation to just the direction of the target
targetRotation = Quaternion.LookRotation((agent.transform.position.DirectionTo(rotationTargetPosition)).Flatten(null, 0));
break;
case PlayerFacingDirection.Movement:
// Check magnitude to avoid the "Look rotation viewing vector is zero" debug
case PlayerFacingDirection.MatchForward:
if (controls.rawMoveInput.magnitude < 0.01f) { break; }
// Set desired rotation to input direction, with respect to camera rotation
if (agent.isGrounded){
if (controls.rawMoveInput.magnitude == 0) { break; }
targetRotation = Quaternion.LookRotation(inputMovement) *
Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0f, null, 0f));
targetRotation = Quaternion.LookRotation(currentMoveDir) *
Quaternion.Euler(Camera.main.transform.rotation.eulerAngles.Flatten(0f, null, 0f));
} else {
if (moveDirection.value.magnitude == 0) { break; }
targetRotation = Quaternion.LookRotation(moveDirection.value);
}
break;
case PlayerFacingDirection.MatchCamera:
// Craft a new rotation that flattens the camera's rotation to the ground
@@ -85,10 +70,10 @@ namespace Reset.Player.Movement {
// Set final rotation
agent.transform.rotation = Quaternion.Lerp(agent.transform.rotation, targetRotation, 10f * Time.deltaTime).Flatten(0, null, 0);
Debug.Log("Rotation Done");
EndAction(true);
}
//Called when the task is disabled.
protected override void OnStop() {