From 72c337c83c7f14d658a94650b9db3c675ca0b74f Mon Sep 17 00:00:00 2001 From: Dakota Irsik Date: Tue, 26 May 2026 16:46:30 +0800 Subject: [PATCH] Fix thrown Pikmin dropping instead of arcing on launch A Pikmin is released from roughly hand height, just above the surface the leader stands on, so on its first physics step it can collide with that ground. OnCollisionHandle's Thrown case demoted any non-Pikmin/non-Player contact to Idle, and FixedUpdate then overwrote the (correctly calculated and applied) launch velocity, so the throw dropped straight down instead of arcing to the reticle. Ignore ground/scenery contacts during the brief post-launch grace window, reusing the existing collider-regrowth period (extracted to the named constant THROW_COLLIDER_GROWTH_TIME). The Pikmin still lands and goes Idle once clear of the launch point, and object hits (PikminInteract) are handled separately and unaffected. Behaviour-only and backward compatible (no version-specific APIs). Co-Authored-By: Claude Opus 4.7 (1M context) --- Assets/Scripts/_Objects/Pikmin/PikminAI.cs | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Assets/Scripts/_Objects/Pikmin/PikminAI.cs b/Assets/Scripts/_Objects/Pikmin/PikminAI.cs index 5d315cb..aeaf419 100644 --- a/Assets/Scripts/_Objects/Pikmin/PikminAI.cs +++ b/Assets/Scripts/_Objects/Pikmin/PikminAI.cs @@ -212,6 +212,12 @@ public class PikminAI : MonoBehaviour, IHealth, IComparable, IInteraction [SerializeField] float _HeldAudioTimer; + // How long after launch the thrown Pikmin's collider grows back from ~0 to its full size + // (see HandleThrown). The same window doubles as a grace period during which ground/scenery + // contacts are ignored, so a Pikmin thrown from near the ground isn't cancelled by a contact + // on its very first physics step before it has had a chance to travel. + const float THROW_COLLIDER_GROWTH_TIME = 0.2f; + [SerializeField] float _ColliderTimer; @@ -892,9 +898,7 @@ void HandleBeingHeld() void HandleThrown() { - const float GROWTH_TIMER = 0.2f; - - if (_ColliderTimer >= GROWTH_TIMER) + if (_ColliderTimer >= THROW_COLLIDER_GROWTH_TIME) { _Collider.radius = _ColliderOriginRadius; _Collider.height = _ColliderOriginHeight; @@ -902,8 +906,8 @@ void HandleThrown() } _ColliderTimer += Time.deltaTime; - _Collider.radius = Mathf.Lerp(0.001f, _ColliderOriginRadius, _ColliderTimer / GROWTH_TIMER); - _Collider.height = Mathf.Lerp(0.001f, _ColliderOriginHeight, _ColliderTimer / GROWTH_TIMER); + _Collider.radius = Mathf.Lerp(0.001f, _ColliderOriginRadius, _ColliderTimer / THROW_COLLIDER_GROWTH_TIME); + _Collider.height = Mathf.Lerp(0.001f, _ColliderOriginHeight, _ColliderTimer / THROW_COLLIDER_GROWTH_TIME); } void HandleOnFire() @@ -1093,6 +1097,19 @@ void OnCollisionHandle(Collision collision) } case PikminStates.Thrown: { + // Ignore ground/scenery contacts during the brief post-launch grace window. + // A Pikmin is thrown from roughly hand height, just above the surface the player + // is standing on, so without this guard a contact on the very first physics step + // demotes it to Idle before it travels; FixedUpdate then overwrites its launch + // velocity and the throw "drops" straight down instead of arcing. The window + // matches the collider regrowth in HandleThrown, and the Pikmin still lands and + // goes Idle as normal once it has cleared the launch point. Object hits + // (PikminInteract) are handled by the case above and are intentionally unaffected. + if (_ColliderTimer < THROW_COLLIDER_GROWTH_TIME) + { + break; + } + if (!col.CompareTag("Pikmin") && !col.CompareTag("Player")) { ChangeState(PikminStates.Idle);