diff --git a/Assets/Scenes/ChaseRun.unity b/Assets/Scenes/ChaseRun.unity
index 656fed8..df72dc8 100644
--- a/Assets/Scenes/ChaseRun.unity
+++ b/Assets/Scenes/ChaseRun.unity
@@ -2500,9 +2500,22 @@ MonoBehaviour:
m_EditorClassIdentifier:
moveSpeed: 1
laneDistance: 0.4
- jumpPower: 0.6
- jumpDuration: 1.2
laneSwitchSpeed: 10
+ maxHoldTime: 0.25
+ initialJumpVelocity: 6.5
+ holdUpwardAcceleration: 35
+ lowJumpGravityMultiplier: 2
+ fallGravityMultiplier: 2.5
+ coyoteTime: 0.12
+ jumpBufferTime: 0.12
+ maxVerticalSpeed: 15
+ allowAirLaneSwitch: 1
+ groundProbe: {fileID: 0}
+ groundMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ groundCheckRadius: 0.2
+ groundCheckExtraDown: 0.06
useSpeedBlendTree: 1
speedParamName: Speed
runSpeedParamValue: 2
@@ -2513,11 +2526,13 @@ MonoBehaviour:
secondHitWindow: 10
stateWaitTimeout: 3
waitingForGameOver: 0
- fallingShortHash: 0
validateStatesOnStart: 1
runTag: Run
fallTag: Fall
fallingTag: Falling
+ runShortHash: 0
+ fallShortHash: 0
+ fallingShortHash: 0
--- !u!65 &1704108065
BoxCollider:
m_ObjectHideFlags: 0
@@ -6238,7 +6253,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
- m_IsActive: 1
+ m_IsActive: 0
--- !u!23 &3681778087044869278
MeshRenderer:
m_ObjectHideFlags: 0
@@ -8840,6 +8855,18 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
+ - target: {fileID: 6341515697253773609, guid: 515cc30092d66fe4dba290f9d6415a60, type: 3}
+ propertyPath: initialJumpVelocity
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 6341515697253773609, guid: 515cc30092d66fe4dba290f9d6415a60, type: 3}
+ propertyPath: fallGravityMultiplier
+ value: 1.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 6341515697253773609, guid: 515cc30092d66fe4dba290f9d6415a60, type: 3}
+ propertyPath: holdUpwardAcceleration
+ value: 20
+ objectReference: {fileID: 0}
- target: {fileID: 7027419816435059383, guid: 515cc30092d66fe4dba290f9d6415a60, type: 3}
propertyPath: m_Material
value:
@@ -8848,6 +8875,10 @@ PrefabInstance:
propertyPath: m_Name
value: ChasePlayer
objectReference: {fileID: 0}
+ - target: {fileID: 7336801398090946996, guid: 515cc30092d66fe4dba290f9d6415a60, type: 3}
+ propertyPath: m_IsActive
+ value: 1
+ objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
diff --git a/Assets/Scripts/ChaseOn/ChasePlayerController.cs b/Assets/Scripts/ChaseOn/ChasePlayerController.cs
index 32d2168..9406802 100644
--- a/Assets/Scripts/ChaseOn/ChasePlayerController.cs
+++ b/Assets/Scripts/ChaseOn/ChasePlayerController.cs
@@ -1,76 +1,132 @@
using System.Collections;
-using DG.Tweening;
using UnityEngine;
+///
+/// Endless runner controller:
+/// - Forward motion (−Z), 3 lanes with smooth switching (ground & air)
+/// - Tap = small jump, Hold (within window) = higher jump
+/// - Coyote time + jump buffer for forgiving inputs
+/// - Robust ground detection (collider-based sphere cast with optional probe)
+/// - Animator driving preserved; obstacle/fall flow preserved
+///
+[RequireComponent(typeof(Rigidbody))]
public class ChasePlayerController : MonoBehaviour
{
+ // ===== Movement =====
[Header("Movement")]
public float moveSpeed = 5f;
- public float laneDistance = 2.5f; // 0=Left,1=Mid,2=Right
- public float jumpPower = 0.6f;
- public float jumpDuration = 1.2f;
- public float laneSwitchSpeed = 10f; // used as units per second
+ [SerializeField] private float laneDistance = 2.5f; // 0=Left,1=Mid,2=Right
+ [SerializeField] private float laneSwitchSpeed = 10f; // units/sec
+ // ===== Jump (Tap / Hold) =====
+ [Header("Jump (Tap/Hold)")]
+ [SerializeField] private float maxHoldTime = 0.25f; // hold window
+ [SerializeField] private float initialJumpVelocity = 6.5f;
+ [SerializeField] private float holdUpwardAcceleration = 35f;
+ [SerializeField] private float lowJumpGravityMultiplier = 2.0f;
+ [SerializeField] private float fallGravityMultiplier = 2.5f;
+ [SerializeField] private float coyoteTime = 0.12f; // after leaving ground
+ [SerializeField] private float jumpBufferTime = 0.12f; // before landing
+ [SerializeField] private float maxVerticalSpeed = 15f;
+
+ [Header("Air Control")]
+ [SerializeField] private bool allowAirLaneSwitch = true;
+
+ // ===== Ground Check =====
+ [Header("Ground Check")]
+ [Tooltip("Optional feet probe; if null, uses collider bounds.")]
+ [SerializeField] private Transform groundProbe;
+ [SerializeField] private LayerMask groundMask = ~0;
+ [SerializeField] private float groundCheckRadius = 0.22f;
+ [SerializeField] private float groundCheckExtraDown = 0.06f;
+
+ // ===== Animator Driving =====
[Header("Animator Driving")]
- public bool useSpeedBlendTree = true;
- public string speedParamName = "Speed";
- public float runSpeedParamValue = 2f;
- public string runStateName = "Locomotion";
- public int baseLayer = 0;
+ [SerializeField] private bool useSpeedBlendTree = true;
+ [SerializeField] private string speedParamName = "Speed";
+ [SerializeField] private float runSpeedParamValue = 2f;
+ [SerializeField] private string runStateName = "Locomotion";
+ [SerializeField] private int baseLayer = 0;
- [Header("Fall / GameOver Logic")]
+ // ===== Fall / GameOver =====
+ [Header("Fall / GameOver")]
public string fallStateName = "Fall";
public string fallingStateName = "Falling";
- public float secondHitWindow = 10f;
- public float stateWaitTimeout = 3f;
+ [SerializeField] private float secondHitWindow = 10f;
+ [SerializeField] private float stateWaitTimeout = 3f;
+
public static System.Action OnMoveSpeedChanged;
- int currentLane = 1;
- Rigidbody rb;
- Animator animator;
- bool isGrounded = true;
- bool isJumping = false;
+ // ----- runtime state -----
+ private int currentLane = 1; // 0,1,2
+ private float targetLaneX = 0f;
- Vector2 startTouchPosition;
- bool swipeDetected = false;
- float minSwipeDistance = 50f;
+ private Rigidbody rb;
+ private Animator animator;
+ private Collider col; // any non-trigger collider
- float lastObstacleHitTime = -999f;
- public bool waitingForGameOver = false;
+ private bool isGrounded = true;
+ private bool isJumping = false;
+ private float lastGroundedTime = -999f;
+ private float jumpPressTime = -999f;
+ private float jumpHoldTimer = 0f;
+ private bool jumpHeld = false;
- int runShortHash, fallShortHash;
- public int fallingShortHash;
- [SerializeField] bool validateStatesOnStart = true;
- [SerializeField] string runTag = "Run";
- [SerializeField] string fallTag = "Fall";
- [SerializeField] string fallingTag = "Falling";
+ private Vector2 startTouchPosition;
+ private bool swipeDetected = false;
+ private const float MIN_SWIPE = 50f;
- float originalMoveSpeed;
- bool unableToMove = false;
+ private float lastObstacleHitTime = -999f;
+ [HideInInspector] public bool waitingForGameOver = false;
- ChaseScoreManager scoreManager;
+ [SerializeField] private bool validateStatesOnStart = true;
+ [SerializeField] private string runTag = "Run";
+ [SerializeField] private string fallTag = "Fall";
+ [SerializeField] private string fallingTag = "Falling";
- void Start()
+ public int runShortHash, fallShortHash, fallingShortHash;
+ private bool hasSpeedFloat, hasIsGroundedBool, hasJumpTrigger, hasLandTrigger;
+
+ private float originalMoveSpeed;
+ private bool unableToMove = false;
+
+ private ChaseScoreManager scoreManager;
+
+ // ========= Unity =========
+ private void Start()
{
+ // Components
rb = GetComponent();
animator = GetComponent();
+ col = GetComponent();
scoreManager = FindObjectOfType();
- runShortHash = Animator.StringToHash(runStateName);
- fallShortHash = Animator.StringToHash(fallStateName);
+ // Rigidbody setup (smooth & robust)
+ rb.interpolation = RigidbodyInterpolation.Interpolate;
+ rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
+ rb.constraints = RigidbodyConstraints.FreezeRotation;
+
+ // Animator hashes
+ runShortHash = Animator.StringToHash(runStateName);
+ fallShortHash = Animator.StringToHash(fallStateName);
fallingShortHash = Animator.StringToHash(fallingStateName);
+ // Validate states (optional)
if (validateStatesOnStart)
{
- if (!animator.HasState(baseLayer, runShortHash))
- Debug.LogError($"Run state '{runStateName}' not found");
- if (!animator.HasState(baseLayer, fallShortHash))
- Debug.LogError($"Fall state '{fallStateName}' not found");
- if (!animator.HasState(baseLayer, fallingShortHash))
- Debug.LogError($"Falling state '{fallingStateName}' not found");
+ if (!animator.HasState(baseLayer, runShortHash)) Debug.LogError($"Run state '{runStateName}' not found");
+ if (!animator.HasState(baseLayer, fallShortHash)) Debug.LogError($"Fall state '{fallStateName}' not found");
+ if (!animator.HasState(baseLayer, fallingShortHash)) Debug.LogError($"Falling state '{fallingStateName}' not found");
}
+ // Cache animator parameters once
+ hasSpeedFloat = HasParam(speedParamName, AnimatorControllerParameterType.Float);
+ hasIsGroundedBool = HasParam("IsGrounded", AnimatorControllerParameterType.Bool);
+ hasJumpTrigger = HasParam("Jump", AnimatorControllerParameterType.Trigger);
+ hasLandTrigger = HasParam("Land", AnimatorControllerParameterType.Trigger);
+
originalMoveSpeed = moveSpeed;
+ targetLaneX = LaneToX(currentLane);
ForceRunStart();
}
@@ -80,194 +136,293 @@ public class ChasePlayerController : MonoBehaviour
OnMoveSpeedChanged?.Invoke(newSpeed);
}
- void Update()
+ private void Update()
{
+ UpdateGrounded();
DriveRunAnimation();
if (!unableToMove)
{
- HandleInput();
- HandleSwipe();
+ ReadKeyboardInput();
+ ReadTouchInput();
+ HandleJumpHold();
}
+
+ ApplyBetterJumpGravity();
+ ClampVerticalSpeed();
}
- void FixedUpdate()
+ private void FixedUpdate()
{
- MoveForward();
+ MoveForwardAndSide();
}
- void HandleInput()
+ // ========= Input =========
+ private void ReadKeyboardInput()
{
- if (isJumping) return;
+ // Lane switching (in-air allowed if enabled)
+ if ((isGrounded || allowAirLaneSwitch) && Input.GetKeyDown(KeyCode.LeftArrow) && currentLane > 0)
+ SetLane(currentLane - 1);
- if (Input.GetKeyDown(KeyCode.LeftArrow) && currentLane > 0)
+ if ((isGrounded || allowAirLaneSwitch) && Input.GetKeyDown(KeyCode.RightArrow) && currentLane < 2)
+ SetLane(currentLane + 1);
+
+ // Jump
+ if (Input.GetKeyDown(KeyCode.Space))
{
- currentLane--;
- TweenToLaneX((currentLane - 1) * laneDistance);
+ jumpPressTime = Time.time;
+ TryStartJump();
+ jumpHeld = true;
+ jumpHoldTimer = 0f;
}
-
- if (Input.GetKeyDown(KeyCode.RightArrow) && currentLane < 2)
+ if (Input.GetKeyUp(KeyCode.Space))
{
- currentLane++;
- TweenToLaneX((currentLane - 1) * laneDistance);
+ jumpHeld = false;
}
-
- if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
- Jump();
}
- void HandleSwipe()
+ private void ReadTouchInput()
{
if (Input.touchCount != 1) return;
+ var t = Input.GetTouch(0);
- var touch = Input.GetTouch(0);
- switch (touch.phase)
+ switch (t.phase)
{
case TouchPhase.Began:
- startTouchPosition = touch.position;
+ startTouchPosition = t.position;
swipeDetected = true;
+ jumpHeld = true;
+ jumpHoldTimer = 0f;
+ jumpPressTime = Time.time;
break;
case TouchPhase.Ended:
- if (!swipeDetected) return;
- Vector2 swipe = touch.position - startTouchPosition;
+ if (!swipeDetected) { jumpHeld = false; break; }
+ Vector2 swipe = t.position - startTouchPosition;
- if (swipe.magnitude >= minSwipeDistance && !isJumping)
+ if (swipe.magnitude >= MIN_SWIPE)
{
if (Mathf.Abs(swipe.x) > Mathf.Abs(swipe.y))
{
- if (swipe.x > 0 && currentLane < 2)
- {
- currentLane++;
- TweenToLaneX((currentLane - 1) * laneDistance);
- }
- else if (swipe.x < 0 && currentLane > 0)
- {
- currentLane--;
- TweenToLaneX((currentLane - 1) * laneDistance);
- }
- }
- else if (swipe.y > 0 && isGrounded)
- {
- Jump();
+ if ((isGrounded || allowAirLaneSwitch) && swipe.x > 0 && currentLane < 2) SetLane(currentLane + 1);
+ else if ((isGrounded || allowAirLaneSwitch) && swipe.x < 0 && currentLane > 0) SetLane(currentLane - 1);
}
+ else if (swipe.y > 0) TryStartJump();
+ }
+ else
+ {
+ // Tap
+ TryStartJump();
}
swipeDetected = false;
+ jumpHeld = false;
break;
}
}
- void TweenToLaneX(float targetX)
- {
- float distance = Mathf.Abs(rb.position.x - targetX);
- float duration = distance / laneSwitchSpeed;
+ // ========= Movement =========
+ private float LaneToX(int laneIndex) => (laneIndex - 1) * laneDistance;
- rb.DOMoveX(targetX, duration).SetEase(Ease.OutQuad);
+ private void SetLane(int laneIndex)
+ {
+ currentLane = Mathf.Clamp(laneIndex, 0, 2);
+ targetLaneX = LaneToX(currentLane);
}
- void MoveForward()
+ private void MoveForwardAndSide()
{
- rb.MovePosition(rb.position + Vector3.back * moveSpeed * Time.fixedDeltaTime);
+ // Forward (−Z)
+ Vector3 forwardStep = Vector3.back * moveSpeed * Time.fixedDeltaTime;
+
+ // Side toward target lane X
+ float newX = Mathf.MoveTowards(rb.position.x, targetLaneX, laneSwitchSpeed * Time.fixedDeltaTime);
+ Vector3 targetPos = new Vector3(newX, rb.position.y, rb.position.z) + forwardStep;
+
+ rb.MovePosition(targetPos);
}
- void Jump()
+ // ========= Jump System =========
+ private void TryStartJump()
{
- if (!isGrounded) return;
+ bool canCoyote = (Time.time - lastGroundedTime) <= coyoteTime;
- isGrounded = false;
- isJumping = true;
- rb.velocity = Vector3.zero;
- rb.useGravity = false;
+ if ((isGrounded || canCoyote) && !waitingForGameOver)
+ {
+ var v = rb.velocity;
+ v.y = initialJumpVelocity;
+ rb.velocity = v;
- float forwardDisplacement = moveSpeed * jumpDuration;
- Vector3 jumpTarget = rb.position + Vector3.back * forwardDisplacement;
+ isJumping = true;
+ isGrounded = false;
+ jumpPressTime = -999f; // consume buffer
- rb.DOJump(jumpTarget, jumpPower, 1, jumpDuration)
- .SetEase(Ease.Linear)
- .OnStart(() =>
- {
- SafeSetTrigger("Jump");
- SafeSetBool("IsGrounded", false);
- })
- .OnComplete(() =>
- {
- rb.useGravity = true;
- isGrounded = true;
- isJumping = false;
- SafeSetTrigger("Land");
- SafeSetBool("IsGrounded", true);
- ForceRunStart();
- });
+ if (hasJumpTrigger) animator.SetTrigger("Jump");
+ if (hasIsGroundedBool) animator.SetBool("IsGrounded", false);
+ }
}
- void OnCollisionEnter(Collision collision)
+ private void HandleJumpHold()
+ {
+ if (!isJumping || !jumpHeld) return;
+
+ if (jumpHoldTimer < maxHoldTime && rb.velocity.y > 0f)
+ {
+ rb.AddForce(Vector3.up * holdUpwardAcceleration, ForceMode.Acceleration);
+ jumpHoldTimer += Time.deltaTime;
+ }
+ }
+
+ private void ApplyBetterJumpGravity()
+ {
+ if (rb == null) return;
+
+ if (rb.velocity.y < 0f)
+ {
+ rb.AddForce(Physics.gravity * (fallGravityMultiplier - 1f), ForceMode.Acceleration);
+ }
+ else if (!jumpHeld && rb.velocity.y > 0f)
+ {
+ rb.AddForce(Physics.gravity * (lowJumpGravityMultiplier - 1f), ForceMode.Acceleration);
+ }
+ }
+
+ private void ClampVerticalSpeed()
+ {
+ var v = rb.velocity;
+ if (v.y > maxVerticalSpeed) v.y = maxVerticalSpeed;
+ if (v.y < -maxVerticalSpeed) v.y = -maxVerticalSpeed;
+ rb.velocity = v;
+ }
+
+ // ========= Grounding =========
+ private void UpdateGrounded()
+ {
+ bool groundedNow = GroundProbe(out _);
+
+ if (groundedNow)
+ {
+ if (!isGrounded)
+ {
+ if (hasLandTrigger) animator.SetTrigger("Land");
+ if (hasIsGroundedBool) animator.SetBool("IsGrounded", true);
+ isJumping = false;
+ ForceRunStart();
+ }
+
+ isGrounded = true;
+ lastGroundedTime = Time.time;
+
+ // Buffered jump pressed just before landing
+ if ((Time.time - jumpPressTime) <= jumpBufferTime)
+ {
+ jumpPressTime = -999f;
+ TryStartJump();
+ }
+ }
+ else
+ {
+ isGrounded = false;
+ if (hasIsGroundedBool) animator.SetBool("IsGrounded", false);
+ }
+ }
+
+ private bool GroundProbe(out Vector3 hitPoint)
+ {
+ hitPoint = transform.position;
+
+ if (col != null)
+ {
+ Bounds b = col.bounds;
+ Vector3 feet = new Vector3(b.center.x, b.min.y + 0.02f, b.center.z);
+ Vector3 origin = groundProbe ? groundProbe.position : feet;
+
+ // SphereCast small distance down
+ if (Physics.SphereCast(origin, groundCheckRadius, Vector3.down, out RaycastHit hit,
+ groundCheckExtraDown + 0.02f, groundMask, QueryTriggerInteraction.Ignore))
+ {
+ hitPoint = hit.point;
+ return true;
+ }
+
+ // Fallback overlap
+ if (Physics.CheckSphere(origin + Vector3.down * groundCheckExtraDown, groundCheckRadius, groundMask, QueryTriggerInteraction.Ignore))
+ {
+ hitPoint = origin + Vector3.down * groundCheckExtraDown;
+ return true;
+ }
+ return false;
+ }
+
+ // No collider → simple overlap at probe or near feet
+ Vector3 o = groundProbe ? groundProbe.position : (transform.position + Vector3.down * 0.95f);
+ bool ok = Physics.CheckSphere(o, groundCheckRadius, groundMask, QueryTriggerInteraction.Ignore);
+ if (ok) hitPoint = o;
+ return ok;
+ }
+
+ private void OnCollisionStay(Collision collision)
+ {
+ // Extra safety: contact with ground layer & low vertical speed => grounded
+ if (((1 << collision.gameObject.layer) & groundMask) != 0 && Mathf.Abs(rb.velocity.y) < 0.1f)
+ {
+ isGrounded = true;
+ lastGroundedTime = Time.time;
+ }
+ }
+
+ private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
- SafeSetBool("IsGrounded", true);
+ lastGroundedTime = Time.time;
+ isJumping = false;
+ if (hasIsGroundedBool) animator.SetBool("IsGrounded", true);
ForceRunStart();
}
}
- void ForceRunStart(bool ignoreGuards = false)
+ // ========= Animator =========
+ private void ForceRunStart(bool ignoreGuards = false)
{
if (!ignoreGuards && (IsInOrGoingTo(fallShortHash) || IsInOrGoingTo(fallingShortHash) || waitingForGameOver))
return;
- if (useSpeedBlendTree && HasParameter(speedParamName, AnimatorControllerParameterType.Float))
- {
+ if (useSpeedBlendTree && hasSpeedFloat)
animator.SetFloat(speedParamName, runSpeedParamValue);
- }
else if (!string.IsNullOrEmpty(runStateName))
- {
animator.CrossFadeInFixedTime(runStateName, 0.1f, baseLayer, 0f);
- }
}
- void DriveRunAnimation()
+ private void DriveRunAnimation()
{
if (IsInOrGoingTo(fallShortHash) || IsInOrGoingTo(fallingShortHash) || isJumping) return;
- if (useSpeedBlendTree && HasParameter(speedParamName, AnimatorControllerParameterType.Float))
+ if (useSpeedBlendTree && hasSpeedFloat)
{
animator.SetFloat(speedParamName, runSpeedParamValue, 0.1f, Time.deltaTime);
}
else
{
- var st = animator.GetCurrentAnimatorStateInfo(baseLayer);
+ var st = animator.GetCurrentAnimatorStateInfo(baseLayer);
var nxt = animator.GetNextAnimatorStateInfo(baseLayer);
- bool inRunNow = st.shortNameHash == runShortHash || st.IsTag(runTag);
+ bool inRunNow = st.shortNameHash == runShortHash || st.IsTag(runTag);
bool goingToRun = animator.IsInTransition(baseLayer) && (nxt.shortNameHash == runShortHash || nxt.IsTag(runTag));
if (!isJumping && !inRunNow && !goingToRun)
- {
animator.CrossFadeInFixedTime(runStateName, 0.1f, baseLayer, 0f);
- }
}
}
- bool HasParameter(string name, AnimatorControllerParameterType type)
+ private bool HasParam(string name, AnimatorControllerParameterType type)
{
foreach (var p in animator.parameters)
if (p.type == type && p.name == name) return true;
return false;
}
- void SafeSetTrigger(string trig)
- {
- if (HasParameter(trig, AnimatorControllerParameterType.Trigger))
- animator.SetTrigger(trig);
- }
-
- void SafeSetBool(string param, bool v)
- {
- if (HasParameter(param, AnimatorControllerParameterType.Bool))
- animator.SetBool(param, v);
- }
-
- bool IsInOrGoingTo(int shortHash)
+ private bool IsInOrGoingTo(int shortHash)
{
var st = animator.GetCurrentAnimatorStateInfo(baseLayer);
if (st.shortNameHash == shortHash) return true;
@@ -279,49 +434,41 @@ public class ChasePlayerController : MonoBehaviour
return false;
}
- // ----------------- Obstacle/Fall flow -----------------
-
+ // ========= Obstacle / Fall flow (kept) =========
public void OnObstacleHit()
{
if (waitingForGameOver) return;
- // Second hit within window → Falling then GameOver
if (Time.time - lastObstacleHitTime <= secondHitWindow)
{
waitingForGameOver = true;
- //SetMoveSpeed(0);
moveSpeed = 0;
StartCoroutine(PlayStateAndGameOver(fallingStateName, fallingShortHash));
}
else
{
- // First hit → Fall only (no GameOver), then resume run when Fall finishes
lastObstacleHitTime = Time.time;
PlayStateOnce(fallStateName);
- originalMoveSpeed = moveSpeed; // remember whatever it was right now
- //SetMoveSpeed(0f); // optional: pause forward motion during stumble
+ originalMoveSpeed = moveSpeed;
moveSpeed = 0;
-
StartCoroutine(ResumeRunAfter(fallStateName, fallShortHash));
}
}
- void PlayStateOnce(string stateName, float xfade = 0.08f)
+ private void PlayStateOnce(string stateName, float xfade = 0.08f)
{
- if (string.IsNullOrEmpty(stateName) || animator == null) return;
- animator.CrossFadeInFixedTime(stateName, xfade, baseLayer, 0f);
+ if (!string.IsNullOrEmpty(stateName))
+ animator.CrossFadeInFixedTime(stateName, xfade, baseLayer, 0f);
}
- IEnumerator ResumeRunAfter(string stateName, int shortHash, float xfade = 0.1f)
+ private IEnumerator ResumeRunAfter(string stateName, int shortHash, float xfade = 0.1f)
{
float t0 = Time.time;
while (!IsInOrGoingTo(shortHash) && !TimedOut(t0)) yield return null;
while (animator.IsInTransition(baseLayer)) yield return null;
- // Wait for completion OR force resume after timeout
t0 = Time.time;
- while (!StateFinished(shortHash) && !TimedOut(t0))
- yield return null;
+ while (!StateFinished(shortHash) && !TimedOut(t0)) yield return null;
if (!waitingForGameOver)
{
@@ -330,6 +477,7 @@ public class ChasePlayerController : MonoBehaviour
animator.CrossFadeInFixedTime(runStateName, 0.1f, baseLayer, 0f);
}
}
+
public IEnumerator PlayStateAndGameOver(string stateName, int shortHash, float xfade = 0.08f)
{
unableToMove = true;
@@ -341,26 +489,23 @@ public class ChasePlayerController : MonoBehaviour
animator.CrossFadeInFixedTime(stateName, xfade, baseLayer, 0f);
- // Wait to enter target state
float t0 = Time.time;
while (!IsInOrGoingTo(shortHash) && !TimedOut(t0)) yield return null;
while (animator.IsInTransition(baseLayer)) yield return null;
- // Wait for it to finish (non-looping recommended)
t0 = Time.time;
while (!StateFinished(shortHash) && !TimedOut(t0)) yield return null;
if (scoreManager) scoreManager.GameOver();
}
- bool StateFinished(int shortHash)
+ private bool StateFinished(int shortHash)
{
var st = animator.GetCurrentAnimatorStateInfo(baseLayer);
return st.shortNameHash == shortHash && !animator.IsInTransition(baseLayer) && st.normalizedTime >= 1f;
}
- bool TimedOut(float startTime)
- {
- return stateWaitTimeout > 0f && (Time.time - startTime) > stateWaitTimeout;
- }
+ private bool TimedOut(float startTime) =>
+ stateWaitTimeout > 0f && (Time.time - startTime) > stateWaitTimeout;
+
}
diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset
index 0d01522..68463c0 100644
--- a/ProjectSettings/DynamicsManager.asset
+++ b/ProjectSettings/DynamicsManager.asset
@@ -18,7 +18,7 @@ PhysicsManager:
m_ClothInterCollisionDistance: 0
m_ClothInterCollisionStiffness: 0
m_ContactsGeneration: 1
- m_LayerCollisionMatrix: fffffffffffffffffffffffffffaffffffffffffffffffffffffffff7ffffffff7fffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ m_LayerCollisionMatrix: fffffffffffffffffffffffffffbffffffffffffffffffffffffffff7ffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_SimulationMode: 0
m_AutoSyncTransforms: 0
m_ReuseCollisionCallbacks: 1