Smooth 3C & simplify hallucination trigger
This commit is contained in:
@@ -26,5 +26,22 @@ namespace Unheimlich.Features.Player.Data
|
||||
|
||||
[Header("Head Bob - General")]
|
||||
public float resetSpeed = 5f;
|
||||
|
||||
[Tooltip("Amplitude of the subtle Z-axis roll added to the bob (degrees).")]
|
||||
public float bobRollAmplitude = 0.4f;
|
||||
|
||||
[Header("Camera Tilt")]
|
||||
[Tooltip("Maximum Z roll angle when strafing (degrees).")]
|
||||
public float strafeTiltAngle = 2.5f;
|
||||
|
||||
[Tooltip("Speed at which the strafe tilt lerps in and out.")]
|
||||
public float strafeTiltSpeed = 6f;
|
||||
|
||||
[Header("FOV Kick")]
|
||||
[Tooltip("FOV added on top of the base FOV when sprinting.")]
|
||||
public float fovKickAmount = 6f;
|
||||
|
||||
[Tooltip("Speed at which FOV lerps to kick target and back.")]
|
||||
public float fovKickSpeed = 8f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Unheimlich.Core;
|
||||
using Unheimlich.Features.Player.Data;
|
||||
using Unheimlich.Features.Dialogue;
|
||||
using InputManager = Unheimlich.Core.Input.InputManager;
|
||||
@@ -7,7 +8,7 @@ using InputManager = Unheimlich.Core.Input.InputManager;
|
||||
namespace Unheimlich.Features.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles camera effects: aim assist and shake.
|
||||
/// Handles camera effects: aim assist, shake, and FOV kick on sprint.
|
||||
/// </summary>
|
||||
public class CameraEffects : MonoBehaviour
|
||||
{
|
||||
@@ -22,29 +23,62 @@ namespace Unheimlich.Features.Player
|
||||
private Vector3 _pendingAimAssistTarget;
|
||||
private bool _hasAimAssistTarget;
|
||||
|
||||
// FOV kick
|
||||
private float _baseFov = -1f;
|
||||
private float _currentFovOffset = 0f;
|
||||
|
||||
public bool IsAimLocked { get; private set; }
|
||||
public bool HasActiveLookInput { get; private set; }
|
||||
public bool IsUsingGamepad { get; private set; }
|
||||
|
||||
void Start()
|
||||
private void Start()
|
||||
{
|
||||
if (Settings != null)
|
||||
_shakeInterval = 1f / Settings.shakeFrequency;
|
||||
|
||||
if (PlayerController.Instance?.PlayerCamera != null)
|
||||
_baseFov = PlayerController.Instance.PlayerCamera.fieldOfView;
|
||||
}
|
||||
|
||||
void Update()
|
||||
private void Update()
|
||||
{
|
||||
DetectInputDevice();
|
||||
UpdateFovKick();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (_hasAimAssistTarget)
|
||||
{
|
||||
ApplyAimAssistInternal(_pendingAimAssistTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// ── FOV Kick ─────────────────────────────────────────────────────────────
|
||||
|
||||
private void UpdateFovKick()
|
||||
{
|
||||
if (Settings == null || PlayerController.Instance?.PlayerCamera == null) return;
|
||||
|
||||
// Capture base FOV once (handles cases where FOV is changed externally before Start).
|
||||
if (_baseFov < 0f)
|
||||
_baseFov = PlayerController.Instance.PlayerCamera.fieldOfView;
|
||||
|
||||
float targetOffset = PlayerController.Instance.IsRunning ? Settings.fovKickAmount : 0f;
|
||||
_currentFovOffset = Mathf.Lerp(_currentFovOffset, targetOffset, Time.deltaTime * Settings.fovKickSpeed);
|
||||
|
||||
PlayerController.Instance.PlayerCamera.fieldOfView = _baseFov + _currentFovOffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the base FOV reference. Call this if the camera FOV is changed intentionally at runtime.
|
||||
/// </summary>
|
||||
public void ResetBaseFov()
|
||||
{
|
||||
if (PlayerController.Instance?.PlayerCamera != null)
|
||||
_baseFov = PlayerController.Instance.PlayerCamera.fieldOfView;
|
||||
}
|
||||
|
||||
// ── Input device detection ────────────────────────────────────────────────
|
||||
|
||||
private void DetectInputDevice()
|
||||
{
|
||||
Vector2 lookInput = InputManager.GetLookInput();
|
||||
@@ -56,11 +90,15 @@ namespace Unheimlich.Features.Player
|
||||
IsUsingGamepad = false;
|
||||
}
|
||||
|
||||
// ── Camera Shake ──────────────────────────────────────────────────────────
|
||||
|
||||
public void ShakeCamera(float amplitude, float smoothness = 0f)
|
||||
{
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CameraPivot == null || Settings == null)
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CameraPivot == null || Settings == null)
|
||||
return;
|
||||
|
||||
PlayerEvents.TriggerCameraShake(amplitude);
|
||||
|
||||
_shakeSmoothness = smoothness;
|
||||
_shakeTimer -= Time.deltaTime;
|
||||
|
||||
@@ -78,8 +116,8 @@ namespace Unheimlich.Features.Player
|
||||
if (_shakeSmoothness > 0f)
|
||||
{
|
||||
PlayerController.Instance.CameraPivot.position = Vector3.Lerp(
|
||||
PlayerController.Instance.CameraPivot.position,
|
||||
_shakeTarget,
|
||||
PlayerController.Instance.CameraPivot.position,
|
||||
_shakeTarget,
|
||||
Time.deltaTime * _shakeSmoothness);
|
||||
}
|
||||
else
|
||||
@@ -88,6 +126,8 @@ namespace Unheimlich.Features.Player
|
||||
}
|
||||
}
|
||||
|
||||
// ── Aim Assist ────────────────────────────────────────────────────────────
|
||||
|
||||
public void ApplyAimAssist(Vector3 targetCenter)
|
||||
{
|
||||
_pendingAimAssistTarget = targetCenter;
|
||||
@@ -96,9 +136,9 @@ namespace Unheimlich.Features.Player
|
||||
|
||||
private void ApplyAimAssistInternal(Vector3 targetCenter)
|
||||
{
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CameraTransform == null || Settings == null)
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CameraTransform == null || Settings == null)
|
||||
return;
|
||||
|
||||
|
||||
if (PlayerController.Instance.Movement == null)
|
||||
return;
|
||||
|
||||
@@ -113,17 +153,17 @@ namespace Unheimlich.Features.Player
|
||||
Vector3 targetDirection = directionToTarget;
|
||||
float targetYaw = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
|
||||
float targetPitch = -Mathf.Asin(targetDirection.y) * Mathf.Rad2Deg;
|
||||
|
||||
|
||||
float currentYaw = PlayerController.Instance.Movement.Yaw;
|
||||
float currentPitch = PlayerController.Instance.Movement.Pitch;
|
||||
|
||||
|
||||
float newYaw = Mathf.LerpAngle(currentYaw, targetYaw, Settings.aimAssistStrength * Time.deltaTime);
|
||||
float newPitch = Mathf.Lerp(currentPitch, targetPitch, Settings.aimAssistStrength * Time.deltaTime);
|
||||
|
||||
|
||||
PlayerController.Instance.Movement.Yaw = newYaw;
|
||||
PlayerController.Instance.Movement.Pitch = newPitch;
|
||||
}
|
||||
|
||||
|
||||
_hasAimAssistTarget = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,125 +6,194 @@ namespace Unheimlich.Features.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Simulates camera head bobbing motion during player movement and idle states.
|
||||
/// Smoothly transitions between idle, walk and run bob parameters.
|
||||
/// Adds a subtle Z-axis roll to the bob and a strafe tilt applied in LateUpdate.
|
||||
/// </summary>
|
||||
public class CameraHeadBob : MonoBehaviour
|
||||
{
|
||||
private float _timer = 0f;
|
||||
private Vector3 _startLocalPos;
|
||||
|
||||
private HeadBobMode _overrideMode = HeadBobMode.Normal;
|
||||
private bool _hasOverride = false;
|
||||
private Coroutine _resetCoroutine;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_startLocalPos = transform.localPosition;
|
||||
}
|
||||
private float _timer = 0f;
|
||||
private Vector3 _startLocalPos;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CharController == null)
|
||||
return;
|
||||
// Smoothly interpolated bob parameters to avoid brutal state switches.
|
||||
private float _currentBobSpeed = 0f;
|
||||
private float _currentBobAmplitude = 0f;
|
||||
|
||||
var settings = PlayerController.Instance.CameraEffects?.Settings;
|
||||
if (settings == null) return;
|
||||
// Strafe tilt (Z roll applied in LateUpdate, after OctoPlayer sets camera pitch).
|
||||
private float _currentTilt = 0f;
|
||||
|
||||
HeadBobMode currentMode = _hasOverride ? _overrideMode : HeadBobMode.Normal;
|
||||
|
||||
if (currentMode == HeadBobMode.Disabled)
|
||||
private HeadBobMode _overrideMode = HeadBobMode.Normal;
|
||||
private bool _hasOverride = false;
|
||||
private Coroutine _resetCoroutine;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
ResetPosition(settings.resetSpeed);
|
||||
return;
|
||||
_startLocalPos = transform.localPosition;
|
||||
}
|
||||
|
||||
if (currentMode == HeadBobMode.Idle || (PlayerInspectionHandler.Instance != null && PlayerInspectionHandler.Instance.IsInspecting))
|
||||
{
|
||||
ApplyBob(settings.idleBobSpeed, settings.idleBobAmplitude);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isMoving = PlayerController.Instance.IsMoving;
|
||||
bool isRunning = PlayerController.Instance.IsRunning;
|
||||
bool isGrounded = PlayerController.Instance.CharController.isGrounded;
|
||||
|
||||
if (isGrounded)
|
||||
private void Update()
|
||||
{
|
||||
if (isMoving)
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CharController == null)
|
||||
return;
|
||||
|
||||
var settings = PlayerController.Instance.CameraEffects?.Settings;
|
||||
if (settings == null) return;
|
||||
|
||||
HeadBobMode currentMode = _hasOverride ? _overrideMode : HeadBobMode.Normal;
|
||||
|
||||
if (currentMode == HeadBobMode.Disabled)
|
||||
{
|
||||
if (isRunning)
|
||||
ApplyBob(settings.runBobSpeed, settings.runBobAmplitude);
|
||||
else
|
||||
ApplyBob(settings.walkBobSpeed, settings.walkBobAmplitude);
|
||||
SetBobDirect(settings.idleBobSpeed, 0f);
|
||||
ApplySmoothedBob(settings.bobRollAmplitude);
|
||||
return;
|
||||
}
|
||||
else
|
||||
ApplyBob(settings.idleBobSpeed, settings.idleBobAmplitude);
|
||||
|
||||
bool forceIdle = currentMode == HeadBobMode.Idle
|
||||
|| (PlayerInspectionHandler.Instance != null && PlayerInspectionHandler.Instance.IsInspecting);
|
||||
|
||||
if (forceIdle)
|
||||
{
|
||||
SetBobDirect(settings.idleBobSpeed, settings.idleBobAmplitude);
|
||||
ApplySmoothedBob(settings.bobRollAmplitude);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isGrounded = PlayerController.Instance.CharController.isGrounded;
|
||||
if (!isGrounded)
|
||||
{
|
||||
SetBobDirect(settings.idleBobSpeed, 0f);
|
||||
ApplySmoothedBob(settings.bobRollAmplitude);
|
||||
return;
|
||||
}
|
||||
|
||||
// Drive bob parameters directly from the actual physics velocity.
|
||||
// This is naturally in sync with OctoPlayer's inertia — no extra lerp needed.
|
||||
float horizontalSpeed = new Vector3(
|
||||
PlayerController.Instance.CharController.velocity.x,
|
||||
0f,
|
||||
PlayerController.Instance.CharController.velocity.z).magnitude;
|
||||
|
||||
bool isRunning = PlayerController.Instance.IsRunning;
|
||||
|
||||
// Normalise: 0 = stopped, 1 = full walk/run speed (m/s converted from km/h ÷ 3.6).
|
||||
const float WalkSpeedMs = 10f / 3.6f;
|
||||
const float RunSpeedMs = 20f / 3.6f;
|
||||
|
||||
float maxSpeed = isRunning ? RunSpeedMs : WalkSpeedMs;
|
||||
float t = Mathf.Clamp01(horizontalSpeed / maxSpeed);
|
||||
|
||||
float targetSpeed = Mathf.Lerp(settings.idleBobSpeed, isRunning ? settings.runBobSpeed : settings.walkBobSpeed, t);
|
||||
float targetAmplitude = Mathf.Lerp(settings.idleBobAmplitude, isRunning ? settings.runBobAmplitude : settings.walkBobAmplitude, t);
|
||||
|
||||
SetBobDirect(targetSpeed, targetAmplitude);
|
||||
ApplySmoothedBob(settings.bobRollAmplitude);
|
||||
}
|
||||
else
|
||||
ResetPosition(settings.resetSpeed);
|
||||
}
|
||||
|
||||
public void SetMode(HeadBobMode mode)
|
||||
{
|
||||
_overrideMode = mode;
|
||||
_hasOverride = true;
|
||||
}
|
||||
|
||||
public void ClearOverride()
|
||||
{
|
||||
_hasOverride = false;
|
||||
|
||||
if (_resetCoroutine != null)
|
||||
|
||||
/// <summary>
|
||||
/// Applies strafe tilt in LateUpdate so it composites correctly over OctoPlayer's pitch rotation.
|
||||
/// </summary>
|
||||
private void LateUpdate()
|
||||
{
|
||||
StopCoroutine(_resetCoroutine);
|
||||
if (PlayerController.Instance == null || PlayerController.Instance.CharController == null)
|
||||
return;
|
||||
|
||||
var settings = PlayerController.Instance.CameraEffects?.Settings;
|
||||
if (settings == null) return;
|
||||
|
||||
// Strafe direction in local space using actual character velocity.
|
||||
Vector3 velocity = PlayerController.Instance.CharController.velocity;
|
||||
float strafeAmount = Vector3.Dot(velocity, PlayerController.Instance.transform.right);
|
||||
|
||||
// Normalise by run speed (km/h → m/s: / 3.6) to get a -1..1 factor.
|
||||
float runSpeedMs = PlayerController.Instance.Movement != null ? 20f / 3.6f : 5.5f;
|
||||
float strafeFactor = Mathf.Clamp(strafeAmount / runSpeedMs, -1f, 1f);
|
||||
|
||||
float targetTilt = -strafeFactor * settings.strafeTiltAngle;
|
||||
_currentTilt = Mathf.Lerp(_currentTilt, targetTilt, Time.deltaTime * settings.strafeTiltSpeed);
|
||||
|
||||
// Compose with the existing local rotation (OctoPlayer already wrote pitch into it).
|
||||
Quaternion baseRot = transform.localRotation;
|
||||
transform.localRotation = baseRot * Quaternion.Euler(0f, 0f, _currentTilt);
|
||||
}
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Overrides the head bob mode (Idle, Normal, Disabled).</summary>
|
||||
public void SetMode(HeadBobMode mode)
|
||||
{
|
||||
_overrideMode = mode;
|
||||
_hasOverride = true;
|
||||
}
|
||||
|
||||
/// <summary>Clears any active mode override and returns to Normal.</summary>
|
||||
public void ClearOverride()
|
||||
{
|
||||
_hasOverride = false;
|
||||
|
||||
if (_resetCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_resetCoroutine);
|
||||
_resetCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Lerps the camera local position back to origin over <paramref name="duration"/> seconds.</summary>
|
||||
public void LerpToZero(float duration)
|
||||
{
|
||||
if (_resetCoroutine != null)
|
||||
StopCoroutine(_resetCoroutine);
|
||||
|
||||
_resetCoroutine = StartCoroutine(LerpToZeroCoroutine(duration));
|
||||
}
|
||||
|
||||
// ── Private helpers ───────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Sets bob speed and amplitude directly without lerp — velocity already carries the inertia.</summary>
|
||||
private void SetBobDirect(float speed, float amplitude)
|
||||
{
|
||||
_currentBobSpeed = speed;
|
||||
_currentBobAmplitude = amplitude;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the bob timer and writes the resulting local position offset.
|
||||
/// Includes a subtle Z roll (Lissajous third axis) for organic feel.
|
||||
/// </summary>
|
||||
private void ApplySmoothedBob(float rollAmplitude)
|
||||
{
|
||||
_timer += Time.deltaTime * _currentBobSpeed;
|
||||
|
||||
float x = Mathf.Sin(_timer * 0.5f) * _currentBobAmplitude * 0.6f;
|
||||
float y = Mathf.Cos(_timer) * _currentBobAmplitude;
|
||||
|
||||
// Micro Z roll: half frequency of Y so it drifts independently.
|
||||
float roll = Mathf.Sin(_timer * 0.5f + Mathf.PI * 0.25f) * rollAmplitude * (_currentBobAmplitude / Mathf.Max(0.001f, 0.03f));
|
||||
|
||||
Vector3 newPos = _startLocalPos;
|
||||
newPos.x += x;
|
||||
newPos.y += y;
|
||||
transform.localPosition = newPos;
|
||||
|
||||
// Store roll so LateUpdate can composite it with the strafe tilt.
|
||||
// We write only the bob-driven roll here; LateUpdate adds strafe tilt on top.
|
||||
Quaternion bobRot = Quaternion.Euler(0f, 0f, roll);
|
||||
transform.localRotation = bobRot;
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator LerpToZeroCoroutine(float duration)
|
||||
{
|
||||
Vector3 startPos = transform.localPosition;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
transform.localPosition = Vector3.Lerp(startPos, _startLocalPos, t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
transform.localPosition = _startLocalPos;
|
||||
_resetCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void LerpToZero(float duration)
|
||||
{
|
||||
if (_resetCoroutine != null)
|
||||
StopCoroutine(_resetCoroutine);
|
||||
|
||||
_resetCoroutine = StartCoroutine(LerpToZeroCoroutine(duration));
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator LerpToZeroCoroutine(float duration)
|
||||
{
|
||||
Vector3 startPos = transform.localPosition;
|
||||
float elapsed = 0f;
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
transform.localPosition = Vector3.Lerp(startPos, Vector3.zero, t);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
transform.localPosition = Vector3.zero;
|
||||
_resetCoroutine = null;
|
||||
}
|
||||
|
||||
private void ApplyBob(float speed, float amplitude)
|
||||
{
|
||||
_timer += Time.deltaTime * speed;
|
||||
|
||||
float x = Mathf.Sin(_timer * 0.5f) * amplitude;
|
||||
float y = Mathf.Cos(_timer) * amplitude;
|
||||
|
||||
Vector3 newPos = _startLocalPos;
|
||||
newPos.x += x;
|
||||
newPos.y += y;
|
||||
|
||||
transform.localPosition = newPos;
|
||||
}
|
||||
|
||||
private void ResetPosition(float resetSpeed)
|
||||
{
|
||||
transform.localPosition = Vector3.Lerp(transform.localPosition, _startLocalPos, Time.deltaTime * resetSpeed);
|
||||
|
||||
if (Vector3.Distance(transform.localPosition, _startLocalPos) < 0.001f)
|
||||
_timer = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,34 +36,19 @@ namespace Unheimlich.Features.Player
|
||||
|
||||
public InputManager Inputs => InputManager.Instance;
|
||||
|
||||
public bool IsMoving
|
||||
{
|
||||
get
|
||||
{
|
||||
// Read directly from action instead of cached value
|
||||
var moveAction = InputManager.GetMoveAction();
|
||||
if (moveAction == null) return false;
|
||||
return moveAction.ReadValue<UnityEngine.Vector2>().magnitude > 0.1f;
|
||||
}
|
||||
}
|
||||
public bool IsRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Movement == null || OctoCore.OctoCore.Instance == null) return false;
|
||||
|
||||
var actions = OctoCore.OctoCore.Instance.Inputs?.Actions;
|
||||
if (actions != null)
|
||||
{
|
||||
foreach (var actionInfo in actions)
|
||||
{
|
||||
if (actionInfo.Name == "Sprint" && actionInfo.Reference != null)
|
||||
return actionInfo.Reference.action.IsPressed();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Cached sprint InputAction — resolved once in OnAwake to avoid per-frame foreach.
|
||||
private UnityEngine.InputSystem.InputAction _sprintAction;
|
||||
|
||||
/// <summary>
|
||||
/// True when the character is physically moving (based on CharacterController velocity,
|
||||
/// not raw input — correctly synced with OctoPlayer's inertia).
|
||||
/// </summary>
|
||||
public bool IsMoving => CharController != null && CharController.velocity.magnitude > 0.1f;
|
||||
|
||||
/// <summary>
|
||||
/// True while the sprint input is held and the player is moving.
|
||||
/// </summary>
|
||||
public bool IsRunning => _sprintAction != null && _sprintAction.IsPressed() && IsMoving;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
@@ -76,15 +61,34 @@ namespace Unheimlich.Features.Player
|
||||
DiapasonEquipment = GetComponent<DiapasonEquipmentManager>();
|
||||
InspectionHandler = GetComponent<PlayerInspectionHandler>();
|
||||
DetectiveBoardController = GetComponent<DetectiveBoardController>();
|
||||
|
||||
|
||||
PlayerCamera = GetComponentInChildren<Camera>();
|
||||
ArmsSystem = GetComponentInChildren<OctoIkArmsImproved>();
|
||||
|
||||
|
||||
if (PlayerCamera != null)
|
||||
{
|
||||
CameraTransform = PlayerCamera.transform;
|
||||
CameraPivot = CameraTransform.parent;
|
||||
}
|
||||
|
||||
CacheSprintAction();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the Sprint InputAction once from OctoCore to avoid per-frame foreach iteration.
|
||||
/// </summary>
|
||||
private void CacheSprintAction()
|
||||
{
|
||||
if (OctoCore.OctoCore.Instance?.Inputs?.Actions == null) return;
|
||||
|
||||
foreach (var actionInfo in OctoCore.OctoCore.Instance.Inputs.Actions)
|
||||
{
|
||||
if (actionInfo.Name == "Sprint" && actionInfo.Reference != null)
|
||||
{
|
||||
_sprintAction = actionInfo.Reference.action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Teleport
|
||||
|
||||
Reference in New Issue
Block a user