fixed movement and dash constraints

This commit is contained in:
Nilton Constantino 2026-06-05 09:30:56 +01:00
parent 6cfb53adc6
commit f9fe2728ca
No known key found for this signature in database
22 changed files with 167 additions and 40 deletions

View File

@ -2996,6 +2996,7 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 1179841130} - component: {fileID: 1179841130}
- component: {fileID: 1179841131}
- component: {fileID: 1179841129} - component: {fileID: 1179841129}
m_Layer: 0 m_Layer: 0
m_Name: Brain m_Name: Brain
@ -3018,6 +3019,7 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Gameplay.Entities.Sentinel.SentinelBrain m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Gameplay.Entities.Sentinel.SentinelBrain
subscriptionId: 53c694ecee4d49be8b1852bf3047ed0e subscriptionId: 53c694ecee4d49be8b1852bf3047ed0e
rootEntity: {fileID: 1478155985} rootEntity: {fileID: 1478155985}
controls: {fileID: 1179841131}
--- !u!4 &1179841130 --- !u!4 &1179841130
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -3034,6 +3036,20 @@ Transform:
- {fileID: 1809909214} - {fileID: 1809909214}
m_Father: {fileID: 2054429927} m_Father: {fileID: 2054429927}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1179841131
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1179841128}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c03b6f34733d48c18d0373cc1ca3d338, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Intrepid.Gameplay.Entities.Sentinel.SentinelControls
dashBreakingThreshold: 2
dashCounter: 0
--- !u!1 &1187971235 --- !u!1 &1187971235
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -3209,8 +3225,8 @@ MonoBehaviour:
Damping: {x: 1, y: 0, z: 1} Damping: {x: 1, y: 0, z: 1}
Lookahead: Lookahead:
Enabled: 1 Enabled: 1
Time: 0.5 Time: 0.3
Smoothing: 15 Smoothing: 10
IgnoreY: 1 IgnoreY: 1
--- !u!114 &1223120093 --- !u!114 &1223120093
MonoBehaviour: MonoBehaviour:
@ -5794,6 +5810,7 @@ MonoBehaviour:
dashLanding: {fileID: 9206814923105168154, guid: 208cb7d0ce6444ed7b55f4c4b4e632aa, type: 3} dashLanding: {fileID: 9206814923105168154, guid: 208cb7d0ce6444ed7b55f4c4b4e632aa, type: 3}
speed: 15 speed: 15
targetTime: 0.2 targetTime: 0.2
dashMaxAngleFromForward: 60
--- !u!1 &2128748248 --- !u!1 &2128748248
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 608292f83d96477ebe6397a317ea947f
timeCreated: 1779259704

View File

@ -2,19 +2,25 @@ using Intrepid.Core.Entities;
using Intrepid.Gameplay.Entities.Sentinel.StateMachine; using Intrepid.Gameplay.Entities.Sentinel.StateMachine;
using Intrepid.Integration.Input; using Intrepid.Integration.Input;
using Intrepid.Structures; using Intrepid.Structures;
using Intrepid.Utilities;
using UnityEngine;
namespace Intrepid.Gameplay.Entities.Sentinel namespace Intrepid.Gameplay.Entities.Sentinel
{ {
public class SentinelBrain : EntityBrain public class SentinelBrain : EntityBrain
{ {
[GroupInjections, SerializeField] private SentinelControls controls;
protected SentinelStateMachine StateMachine { get; private set; } protected SentinelStateMachine StateMachine { get; private set; }
public SentinelEntity Entity => RootEntity as SentinelEntity; public SentinelEntity Entity => RootEntity as SentinelEntity;
public SentinelInputs Inputs => InputService.Instance.BuildSentinelInputs(); public SentinelInputs Inputs { get; private set; }
public SentinelStateType CurrentState => StateMachine.CurrentImplementation.GetStateKey(); public SentinelStateType CurrentState => StateMachine.CurrentImplementation.GetStateKey();
public SentinelControls Controls => controls;
protected override void InitializeVariables() protected override void InitializeVariables()
{ {
Inputs = InputService.Instance.BuildSentinelInputs();
StateMachine = GetComponentInChildren<SentinelStateMachine>(); StateMachine = GetComponentInChildren<SentinelStateMachine>();
foreach (var sentinelState in GetComponentsInChildren<SentinelState>()) foreach (var sentinelState in GetComponentsInChildren<SentinelState>())
{ {

View File

@ -1,8 +1,19 @@
namespace Intrepid.Gameplay.Entities.Sentinel namespace Intrepid.Gameplay.Entities.Sentinel
{ {
public sealed class SentinelConstants public static class SentinelConstants
{ {
public sealed class Parameters public static class Thresholds
{
public static class Movement
{
public const float DeadZone = 0.1f;
public const float DeadZoneSqrt = DeadZone * DeadZone;
public const float WalkZone = 0.65f;
public const float WalkZoneSqrt = WalkZone * WalkZone;
}
}
public static class Parameters
{ {
public const string KnockdownForce = "KnockdownForce"; public const string KnockdownForce = "KnockdownForce";
} }

View File

@ -0,0 +1,28 @@
using Intrepid.Utilities;
using UnityEngine;
namespace Intrepid.Gameplay.Entities.Sentinel
{
public class SentinelControls : MonoBehaviour
{
[GroupConfigurations, SerializeField, Range(0, 3)] private int dashBreakingThreshold = 2;
[GroupDebug, SerializeField] private int dashCounter;
public int DashCounter => dashCounter;
public void DashCounterInc()
{
dashCounter++;
}
public void ResetDash()
{
dashCounter = 0;
}
public bool DashShouldBreak()
{
return DashCounter >= dashBreakingThreshold;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c03b6f34733d48c18d0373cc1ca3d338
timeCreated: 1780645811

View File

@ -1,4 +1,3 @@
using System;
using Intrepid.Core.Entities; using Intrepid.Core.Entities;
using Intrepid.GameManagers; using Intrepid.GameManagers;
using Intrepid.Gameplay.Messages.Events; using Intrepid.Gameplay.Messages.Events;
@ -27,7 +26,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel
public EntityModelAnimation ModelAnimation => modelAnimation; public EntityModelAnimation ModelAnimation => modelAnimation;
public Vector2 DesiredVelocity { get; set; } public Vector2 DesiredVelocity { get; set; }
public Vector3 LinearVelocity { get; private set; } public Vector3 LinearVelocity { get; private set; }
public Vector2 Forward => new(_desiredForward.x, _desiredForward.z); public Vector2 Forward => new Vector2(_desiredForward.x, _desiredForward.z).normalized;
public override void DeployEntity(Vector2 position) public override void DeployEntity(Vector2 position)
{ {
@ -39,7 +38,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel
public void ChangeOrientation(Vector2 direction) public void ChangeOrientation(Vector2 direction)
{ {
if (direction.sqrMagnitude <= 0.01f) if (direction.sqrMagnitude <= GonConstants.CommonZeroSqrt)
{ {
return; return;
} }

View File

@ -8,8 +8,8 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
public class SentinelStateDash : SentinelState public class SentinelStateDash : SentinelState
{ {
[GroupConfigurations, SerializeField] private AnimationClip dash; [GroupConfigurations, SerializeField] private AnimationClip dash;
[GroupConfigurations, SerializeField, Range(0, 100)] private float speed = 30; [GroupConfigurations, SerializeField, Range(0, 100)] private float speed = 35;
[GroupConfigurations, SerializeField, Range(0, 10)] private float targetTime = .15f; [GroupConfigurations, SerializeField, Range(0, 10)] private float targetTime = .125f;
private Timer Timer { get; } = new(); private Timer Timer { get; } = new();
@ -29,7 +29,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
protected override void RunOnEnter(ParameterStore parameterStore) protected override void RunOnEnter(ParameterStore parameterStore)
{ {
Brain.Entity.ChangeOrientation(Brain.Inputs.Movement()); Brain.Controls.DashCounterInc();
Brain.Entity.ModelAnimation.CrossFade(dash, 0.01f); Brain.Entity.ModelAnimation.CrossFade(dash, 0.01f);
Timer.Start(); Timer.Start();
} }

View File

@ -7,8 +7,8 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
public class SentinelStateDashBreaking : SentinelState public class SentinelStateDashBreaking : SentinelState
{ {
[GroupConfigurations, SerializeField] private AnimationClip dashBreaking; [GroupConfigurations, SerializeField] private AnimationClip dashBreaking;
[GroupConfigurations, SerializeField, Range(5, 30)] private float speed = 10; [GroupConfigurations, SerializeField, Range(5, 30)] private float speed = 5;
[GroupConfigurations, SerializeField, Range(0, 2)] private float extraTime = 0.5f; [GroupConfigurations, SerializeField, Range(0, 2)] private float extraTime = 0.4f;
[GroupConfigurations, SerializeField] private AnimationCurve speedCurve; [GroupConfigurations, SerializeField] private AnimationCurve speedCurve;
private Timer Timer { get; } = new(); private Timer Timer { get; } = new();

View File

@ -8,7 +8,8 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
{ {
[GroupConfigurations, SerializeField] private AnimationClip dashLanding; [GroupConfigurations, SerializeField] private AnimationClip dashLanding;
[GroupConfigurations, SerializeField, Range(0, 30)] private float speed = 15; [GroupConfigurations, SerializeField, Range(0, 30)] private float speed = 15;
[GroupConfigurations, SerializeField, Range(0, 10)] private float targetTime = .25f; [GroupConfigurations, SerializeField, Range(0, 10)] private float targetTime = .2f;
[GroupConfigurations, SerializeField, Range(15, 90)] private float dashMaxAngleFromForward = 60f;
private Timer Timer { get; } = new(); private Timer Timer { get; } = new();
@ -30,6 +31,11 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
protected override void RunOnExit() protected override void RunOnExit()
{ {
Timer.Stop(); Timer.Stop();
var movement = Brain.Inputs.Movement();
var forward = Brain.Entity.Forward;
var direction = GonFunctions
.ConstrainDirectionToForwardCone(movement, forward, dashMaxAngleFromForward);
Brain.Entity.ChangeOrientation(direction);
} }
public override void RunOnUpdate() public override void RunOnUpdate()
@ -37,7 +43,9 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
if (CheckDash()) return; if (CheckDash()) return;
if (Timer.IsNotRunning) if (Timer.IsNotRunning)
{ {
Brain.ChangeState(SentinelStateType.DashBreaking); Brain.ChangeState(Brain.Controls.DashShouldBreak()
? SentinelStateType.DashBreaking
: SentinelStateType.Idle);
return; return;
} }
Timer.Update(Time.deltaTime); Timer.Update(Time.deltaTime);
@ -58,5 +66,10 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
} }
return false; return false;
} }
} }
} }

View File

@ -7,6 +7,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
public class SentinelStateIdle : SentinelState public class SentinelStateIdle : SentinelState
{ {
[GroupConfigurations, SerializeField] private AnimationClip idle; [GroupConfigurations, SerializeField] private AnimationClip idle;
private Vector2 Movement { get; set; } private Vector2 Movement { get; set; }
public override SentinelStateType GetStateKey() public override SentinelStateType GetStateKey()
@ -20,6 +21,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
protected override void RunOnEnter(ParameterStore parameterStore) protected override void RunOnEnter(ParameterStore parameterStore)
{ {
Brain.Controls.ResetDash();
Brain.Entity.ModelAnimation.CrossFade(idle, 0.2f); Brain.Entity.ModelAnimation.CrossFade(idle, 0.2f);
Brain.Entity.DesiredVelocity = Vector2.zero; Brain.Entity.DesiredVelocity = Vector2.zero;
} }
@ -45,10 +47,10 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
{ {
switch (Movement.sqrMagnitude) switch (Movement.sqrMagnitude)
{ {
case > 0.1f and < 0.65f: case > SentinelConstants.Thresholds.Movement.DeadZoneSqrt and < SentinelConstants.Thresholds.Movement.WalkZoneSqrt:
Brain.ChangeState(SentinelStateType.Walk); Brain.ChangeState(SentinelStateType.Walk);
return true; return true;
case >= 0.65f: case >= SentinelConstants.Thresholds.Movement.WalkZoneSqrt:
Brain.ChangeState(SentinelStateType.Run); Brain.ChangeState(SentinelStateType.Run);
return true; return true;
default: default:

View File

@ -9,8 +9,8 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
[GroupConfigurations, SerializeField] private AnimationClip knockdown; [GroupConfigurations, SerializeField] private AnimationClip knockdown;
[GroupConfigurations, SerializeField] private AnimationClip knockout; [GroupConfigurations, SerializeField] private AnimationClip knockout;
[GroupConfigurations, SerializeField] private float KnockoutTimeMultiplier = 0.1f; [GroupConfigurations, SerializeField] private float KnockoutTimeMultiplier = 0.1f;
[GroupConfigurations, SerializeField, Range(0, 3)] private float knockdownTime = 2.0f; [GroupConfigurations, SerializeField, Range(0, 3)] private float knockdownTime = .1f;
[GroupConfigurations, SerializeField, Range(0, 3)] private float recoverTime = 1.5f; [GroupConfigurations, SerializeField, Range(0, 3)] private float recoverTime = .5f;
private Vector2 KnockdownForce { get; set; } private Vector2 KnockdownForce { get; set; }
private float KnockoutTime { get; set; } private float KnockoutTime { get; set; }

View File

@ -27,6 +27,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
protected override void RunOnExit() protected override void RunOnExit()
{ {
Brain.Entity.ChangeOrientation(Movement);
} }
public override void RunOnUpdate() public override void RunOnUpdate()
@ -52,10 +53,10 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
{ {
switch (Movement.sqrMagnitude) switch (Movement.sqrMagnitude)
{ {
case <= 0.1f: case <= SentinelConstants.Thresholds.Movement.DeadZoneSqrt:
Brain.ChangeState(SentinelStateType.Idle); Brain.ChangeState(SentinelStateType.Idle);
return true; return true;
case < 0.65f: case < SentinelConstants.Thresholds.Movement.WalkZoneSqrt:
Brain.ChangeState(SentinelStateType.Walk); Brain.ChangeState(SentinelStateType.Walk);
return true; return true;
default: default:

View File

@ -27,6 +27,7 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
protected override void RunOnExit() protected override void RunOnExit()
{ {
Brain.Entity.ChangeOrientation(Movement);
} }
public override void RunOnUpdate() public override void RunOnUpdate()
@ -52,10 +53,10 @@ namespace Intrepid.Gameplay.Entities.Sentinel.StateMachine.States
{ {
switch (Movement.sqrMagnitude) switch (Movement.sqrMagnitude)
{ {
case <= 0.1f: case <= SentinelConstants.Thresholds.Movement.DeadZoneSqrt:
Brain.ChangeState(SentinelStateType.Idle); Brain.ChangeState(SentinelStateType.Idle);
return true; return true;
case >= 0.65f: case >= SentinelConstants.Thresholds.Movement.WalkZoneSqrt:
Brain.ChangeState(SentinelStateType.Run); Brain.ChangeState(SentinelStateType.Run);
return true; return true;
default: default:

View File

@ -94,7 +94,7 @@ public partial class @InputActions: IInputActionCollection2, IDisposable
""actions"": [ ""actions"": [
{ {
""name"": ""Movement"", ""name"": ""Movement"",
""type"": ""Value"", ""type"": ""PassThrough"",
""id"": ""9e2d6670-978a-4e07-847e-8763e3a9a503"", ""id"": ""9e2d6670-978a-4e07-847e-8763e3a9a503"",
""expectedControlType"": ""Vector2"", ""expectedControlType"": ""Vector2"",
""processors"": """", ""processors"": """",
@ -126,7 +126,7 @@ public partial class @InputActions: IInputActionCollection2, IDisposable
{ {
""name"": ""2D Vector"", ""name"": ""2D Vector"",
""id"": ""247b8d8e-671f-4160-be10-4d99b4cf0661"", ""id"": ""247b8d8e-671f-4160-be10-4d99b4cf0661"",
""path"": ""2DVector"", ""path"": ""2DVector(mode=1)"",
""interactions"": """", ""interactions"": """",
""processors"": """", ""processors"": """",
""groups"": """", ""groups"": """",
@ -140,7 +140,7 @@ public partial class @InputActions: IInputActionCollection2, IDisposable
""path"": ""<Keyboard>/w"", ""path"": ""<Keyboard>/w"",
""interactions"": """", ""interactions"": """",
""processors"": """", ""processors"": """",
""groups"": """", ""groups"": "";Keyboard & Mouse"",
""action"": ""Movement"", ""action"": ""Movement"",
""isComposite"": false, ""isComposite"": false,
""isPartOfComposite"": true ""isPartOfComposite"": true
@ -151,7 +151,7 @@ public partial class @InputActions: IInputActionCollection2, IDisposable
""path"": ""<Keyboard>/s"", ""path"": ""<Keyboard>/s"",
""interactions"": """", ""interactions"": """",
""processors"": """", ""processors"": """",
""groups"": """", ""groups"": "";Keyboard & Mouse"",
""action"": ""Movement"", ""action"": ""Movement"",
""isComposite"": false, ""isComposite"": false,
""isPartOfComposite"": true ""isPartOfComposite"": true
@ -162,7 +162,7 @@ public partial class @InputActions: IInputActionCollection2, IDisposable
""path"": ""<Keyboard>/a"", ""path"": ""<Keyboard>/a"",
""interactions"": """", ""interactions"": """",
""processors"": """", ""processors"": """",
""groups"": """", ""groups"": "";Keyboard & Mouse"",
""action"": ""Movement"", ""action"": ""Movement"",
""isComposite"": false, ""isComposite"": false,
""isPartOfComposite"": true ""isPartOfComposite"": true
@ -173,7 +173,7 @@ public partial class @InputActions: IInputActionCollection2, IDisposable
""path"": ""<Keyboard>/d"", ""path"": ""<Keyboard>/d"",
""interactions"": """", ""interactions"": """",
""processors"": """", ""processors"": """",
""groups"": """", ""groups"": "";Keyboard & Mouse"",
""action"": ""Movement"", ""action"": ""Movement"",
""isComposite"": false, ""isComposite"": false,
""isPartOfComposite"": true ""isPartOfComposite"": true

View File

@ -8,7 +8,7 @@
"actions": [ "actions": [
{ {
"name": "Movement", "name": "Movement",
"type": "Value", "type": "PassThrough",
"id": "9e2d6670-978a-4e07-847e-8763e3a9a503", "id": "9e2d6670-978a-4e07-847e-8763e3a9a503",
"expectedControlType": "Vector2", "expectedControlType": "Vector2",
"processors": "", "processors": "",
@ -40,7 +40,7 @@
{ {
"name": "2D Vector", "name": "2D Vector",
"id": "247b8d8e-671f-4160-be10-4d99b4cf0661", "id": "247b8d8e-671f-4160-be10-4d99b4cf0661",
"path": "2DVector", "path": "2DVector(mode=1)",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": "",
@ -54,7 +54,7 @@
"path": "<Keyboard>/w", "path": "<Keyboard>/w",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": ";Keyboard & Mouse",
"action": "Movement", "action": "Movement",
"isComposite": false, "isComposite": false,
"isPartOfComposite": true "isPartOfComposite": true
@ -65,7 +65,7 @@
"path": "<Keyboard>/s", "path": "<Keyboard>/s",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": ";Keyboard & Mouse",
"action": "Movement", "action": "Movement",
"isComposite": false, "isComposite": false,
"isPartOfComposite": true "isPartOfComposite": true
@ -76,7 +76,7 @@
"path": "<Keyboard>/a", "path": "<Keyboard>/a",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": ";Keyboard & Mouse",
"action": "Movement", "action": "Movement",
"isComposite": false, "isComposite": false,
"isPartOfComposite": true "isPartOfComposite": true
@ -87,7 +87,7 @@
"path": "<Keyboard>/d", "path": "<Keyboard>/d",
"interactions": "", "interactions": "",
"processors": "", "processors": "",
"groups": "", "groups": ";Keyboard & Mouse",
"action": "Movement", "action": "Movement",
"isComposite": false, "isComposite": false,
"isPartOfComposite": true "isPartOfComposite": true

View File

@ -59,7 +59,7 @@ namespace Intrepid.Integration.Input
return new SentinelInputs return new SentinelInputs
{ {
Movement = () => Locking.IsNotLocked Movement = () => Locking.IsNotLocked
? InputActions.sentinel.Movement.ReadValue<Vector2>().normalized ? InputActions.sentinel.Movement.ReadValue<Vector2>()
: Vector2.zero, : Vector2.zero,
Dash = () => Locking.IsNotLocked && InputActions.sentinel.Dash.WasPressedThisFrame(), Dash = () => Locking.IsNotLocked && InputActions.sentinel.Dash.WasPressedThisFrame(),
}; };

View File

@ -1,7 +1,10 @@
namespace Intrepid.Core namespace Intrepid.Utilities
{ {
public static class GonConstants public static class GonConstants
{ {
public static float CommonZero => 0.001f;
public static float CommonZeroSqrt => CommonZero * CommonZero;
public static class ExecutionOrder public static class ExecutionOrder
{ {
public const int ASAP = -10000; public const int ASAP = -10000;

View File

@ -0,0 +1,20 @@
using UnityEngine;
namespace Intrepid.Utilities
{
public static class GonExtensions
{
public static Vector2 Rotate(this Vector2 v, float degrees)
{
var radians = degrees * Mathf.Deg2Rad;
var sin = Mathf.Sin(radians);
var cos = Mathf.Cos(radians);
return new Vector2(
v.x * cos - v.y * sin,
v.x * sin + v.y * cos
);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cdba58dc758948c8a2a233692247eb65
timeCreated: 1780647310

View File

@ -0,0 +1,20 @@
using UnityEngine;
namespace Intrepid.Utilities
{
public static class GonFunctions
{
public static Vector2 ConstrainDirectionToForwardCone(
Vector2 direction,
Vector2 forward,
float maxAngleDegrees)
{
var clampedAngle = Mathf.Clamp(
Vector2.SignedAngle(forward, direction),
-maxAngleDegrees,
maxAngleDegrees
);
return forward.Rotate(clampedAngle).normalized;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 046061aab07741c7b4066d5c7a91ce37
timeCreated: 1780647513