Hi everyone,
I’m working on a first-person controller and having a strange issue with my jump mechanic, which uses a raycast downwards to check if the player is grounded.
The Problem: Jumping (using the spacebar) works perfectly fine in most areas of my test scene. However, specifically when I stand near the left side of my main vehicle entity (“Aeroboticar”), the jump fails. If I move to the right side of the same vehicle, jumping works reliably.
Setup:
- My
Playerentity has aDynamic Rigidbodyand aCollisioncomponent. - Movement and jumping are handled by a script called
firstPersonMovement.js. - Inside this script, the
updatefunction calls acheckGround()function every frame. checkGround()performs araycastFirstdownwards from near the player’s origin (getPosition().y + raycastStartOffset) for a short distance (groundCheckDistance + 0.1).- If the raycast hits a valid entity, a
this.canJumpflag is set totrue(provided a jump cooldown isn’t active). - Pressing spacebar applies an upward impulse only if
this.canJumpis true. - My
Groundentity has aStatic Rigidbodyand aCollisioncomponent, and its Rigidbody group is set toDefault.
Debugging Done:
- Console logs confirm that when standing on the right side of the Aeroboticar, the
checkGroundraycast correctly logsHit: Ground | Setting canJump = true. - When standing on the left side of the Aeroboticar, the
checkGroundraycast logsHit: None / Filtered | Setting canJump = false, even though the player visually appears to be on the same ground surface. - This happens consistently only on the left side relative to the vehicle.
My Hypothesis: It seems the raycast is somehow missing the ground collider, or perhaps hitting an invisible part of the Aeroboticar’s collider only when the player is on its left side. If it hits the Aeroboticar, the filter should ignore it, resulting in Hit: None. I’ve checked the Aeroboticar’s colliders and can’t see anything obvious that would only block the ray on one side.
Project Link: Here is a direct link to the editor: PlayCanvas | HTML5 Game Engine (You can test by launching, walking up to the Aeroboticar, and trying to jump on both its left and right sides).
Relevant Code (checkGround function from firstPersonMovement.js):
FirstPersonMovement.prototype.checkGround = function() {
var groundCheckStart = this.entity.getPosition().clone();
// OPTIONAL: Adjust start Y if player origin is centered: groundCheckStart.y -= 0.5;
var checkDistance = this.groundCheckDistance + 0.1; // Ray distance including buffer
var groundCheckEnd = groundCheckStart.clone().add(pc.Vec3.DOWN.clone().scale(checkDistance));
var result = this.app.systems.rigidbody.raycastFirst(groundCheckStart, groundCheckEnd);
// Set onGround based *only* on whether the ray hit anything
var onGround = (result !== null);
var previouslyCanJump = this.canJump;
if (onGround && this.jumpTimer <= 0) {
this.canJump = true;
if (!previouslyCanJump) {
console.log(`Ground Check - Hit: ${(result ? result.entity.name : 'ERROR')} | Timer <= 0 | Setting canJump = true`);
}
} else {
this.canJump = false;
if (previouslyCanJump && !onGround) {
console.log(`Ground Check - Hit: None | Setting canJump = false`);
}
}
// Optional detailed log:
// console.log(`Ground Check Ray - Start:(${groundCheckStart.x.toFixed(1)},${groundCheckStart.y.toFixed(1)},${groundCheckStart.z.toFixed(1)}) End:(${groundCheckEnd.x.toFixed(1)},${groundCheckEnd.y.toFixed(1)},${groundCheckEnd.z.toFixed(1)}) | Hit: ${(result ? result.entity.name : 'None')} | Timer: ${this.jumpTimer.toFixed(2)} | Can Jump: ${this.canJump}`);
};
// Jump Logic
if (app.keyboard.wasPressed(pc.KEY_SPACE)) {
// console.log("Spacebar pressed. Current Can Jump flag:", this.canJump);
if (this.canJump) {
var jumpImpulse = pc.Vec3.UP.clone().scale(this.jumpPower);
this.entity.rigidbody.applyImpulse(jumpImpulse);
// console.log("Applying Jump Impulse:", jumpImpulse.toString());
this.canJump = false; // Prevent immediate re-jump
this.jumpTimer = this.jumpCooldown; // Start the cooldown timer
console.log("Jumped! Starting cooldown.");
} else {
if(this.jumpTimer > 0) { console.log("Spacebar pressed but jump cooldown active."); }
else { console.log("Spacebar pressed but not on ground (canJump=false)."); }
}
}
Could anyone take a look or suggest why the raycast might be failing specifically on the left side of the Aeroboticar? Any ideas would be greatly appreciated!
Thanks!