Collision System
GEBlupiController: grid collision, 1-block step-up traversal, gravity.
Constants
kMoveSpeed = 5.5f; // units/s
kJumpSpeed = 12.0f; // units/s
kGravity = 25.0f; // units/s²
kFallLimit = -10.0f; // terminal fall velocity
kStepLimit = 1.0f; // max step-up height
Block Solidity
bool IsSolidAt(world, gx, gy, gz):
if out of [0, blocksPerAxis-1] on any axis: return false // (or handled by caller clamping)
return !world.getBlock(gx, gy, gz).isAir()
Grid coordinates are computed via std::lround(pos + kWorldCenter), then clamped to [0, blocksPerAxis - 1].
GroundHeightAt(gx, gz)
int GroundHeightAt(world, gx, gz):
for y from top down to 0:
if IsSolidAt(world, gx, y, gz): return y + 1
return 0
TryMoveAxis (per-axis horizontal step)
bool TryMoveAxis(world, axisDelta):
targetGround = GroundHeightAt(world, targetGx, targetGz)
if targetGround - currentFeetY <= kStepLimit:
apply the move
if grounded: lift Y onto targetGround // 1-block step-up traversal
return true
return false // blocked — step too high
Step(world, dx, dz, jumpPressed, dt)
Step(world, dx, dz, jumpPressed, dt):
TryMoveAxis(world, dx along X)
TryMoveAxis(world, dz along Z)
if onGround_ and jumpPressed:
velocityY_ = kJumpSpeed
velocityY_ -= kGravity * dt
velocityY_ = max(velocityY_, kFallLimit)
pos.y += velocityY_ * dt
groundY = GroundHeightAt(world, gx, gz)
if pos.y <= groundY:
pos.y = groundY
velocityY_ = 0
onGround_ = true
else:
onGround_ = false
What's Not Implemented
- No swimming, hazard, spring, or fan tile interaction —
BlockTypeshas predicate helpers for these but they aren't wired intoGEBlupiController. - No object/enemy collision — there are no objects to collide with yet.
- No AABB body — collision is a single point-column check per axis, not a swept box.
Verification
tools/VerifyBlupiMovement.cpp links only GEBlupiController.cpp (no CNA
dependency) and scripts movement scenarios headlessly to verify collision behavior without a
live window.