Fix thrown Pikmin dropping instead of arcing on launch#12
Conversation
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) <noreply@anthropic.com>
|
Thank you Claude, but how do you ensure the Pikmin doesn't fall through the wall or go through anything during this process? |
|
Hi @intns — I'm Claude, the AI Dakota paired with on this PR. He asked me to come answer your question directly, and to surface some of the thinking we went through that never made it into the thread, so you have the full picture rather than just the diff and your question. First, the direct answer to "how do you ensure the Pikmin doesn't fall through the wall or go through anything": the fix never disables collisions. It only suppresses one AI state transition for ~0.2s. The physics engine keeps colliding the entire time. Concretely: On the exact scenario your question points at — this is something Dakota flagged to me before he replied: his own worry was the player standing right up against a wall and spam-throwing Pikmin into it during that 0.2s window — could one get shoved through? We dug into it, and it holds up, but not because of the window. The Pikmin prefabs ( On what was actually causing the drop: Dakota's first instinct was that the Pikmin might be colliding with the surrounding squad, and mine was the ground mesh. We were able to settle it rather than guess. The existing check already excludes Pikmin/Player contacts from the demotion — if (!col.CompareTag("Pikmin") && !col.CompareTag("Player"))
{
ChangeState(PikminStates.Idle);
}— so squadmates were never the trigger, and a temporary diagnostic log caught the contact that actually was:
One thing I want to be straight about: I initially suggested to Dakota this might stem from a physics change between Unity 6000.0 and 6000.4, but when he asked me to back that up I couldn't actually substantiate it. So the PR doesn't rest on that claim — it rests on the observed behavior above, and it's backward compatible: on a build where the launch-step floor contact doesn't happen, the guard is simply a no-op because the Pikmin is airborne for that window. The near-zero collider that regrows over 0.2s in Happy to rework it if you'd rather address the launch-from-ground-height case a different way (e.g. a short raycast/ |
|
@intns (Dakota here) Full disclosure. While I'm a 15+ year .net dev I'm very very new to game development; you would know the validity of claude's assertions better than me. I was just having fun playing Pikmin4 with my daughter and remembered your repo from a while back and after cloning realized I only had 6000.4 installed and saw this problem that I don't remember exising before. Great work on the project btw! My daughter smiled so big and laughed when I made Olimar and one of the pikmin 5x transform scale and threw him. |
Summary
Throwing a Pikmin frequently makes it drop straight out of the leader's hand instead of arcing to the reticle. The launch velocity is calculated and applied correctly, but the Pikmin is knocked out of the
Thrownstate on its first physics step, after whichPikminAI.FixedUpdate()overwrites the launch velocity.A Pikmin is released from roughly hand height — just above the ground the leader is standing on — so on the first
FixedUpdateit registers a collision with that ground.OnCollisionHandle'sThrowncase demotes any contact that isn't taggedPikmin/PlayertoIdle, which cancels the throw before it travels.Fix
Ignore ground/scenery contacts during the brief post-launch grace window — the same period over which the throw collider already regrows in
HandleThrown(extracted to a named constantTHROW_COLLIDER_GROWTH_TIME). The Pikmin still lands and goesIdlenormally once it has cleared the launch point, and object hits (PikminInteract, e.g. enemies/pellets) are handled by the separatecaseabove and are intentionally unaffected.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. + if (_ColliderTimer < THROW_COLLIDER_GROWTH_TIME) + { + break; + } + if (!col.CompareTag("Pikmin") && !col.CompareTag("Player")) { ChangeState(PikminStates.Idle); } break; }How we reproduced
This surfaced after upgrading the Editor to Unity 6000.4.6f1 (though we didn't have the suggested Unity version installed to verify if this issure occured on the suggested Unity version or not). We could not tie it to a specific documented Unity physics change, so the fix is justified purely on behaviour and is backward compatible (no version-specific APIs).
Diagnostic logging we used (temporary — NOT part of this PR)
In case you want to reproduce the diagnosis, these are the (condensed) temporary logs we added:
PlayerPikminController.OnPrimaryAction— press/release snapshot + post-throw trackingPikminAI.OnCollisionHandle— what a Thrown Pikmin actually contactsRepresentative log output (single throw, no Pikmin crowding the leader)
The velocity is correct and applied; the
Thrown -> Idletransition triggered by theMapcontact is what kills the throw (FixedUpdatethen overwrites the velocity). After the fix the Pikmin staysThrownthrough launch and arcs normally.Compatibility
Behaviour-only change using existing fields and standard control flow. On a build where the launch-step ground contact doesn't occur, the new guard is a no-op (the Pikmin is airborne during that window), so existing throw behaviour is unchanged.