BlupiController

Blupi's body: movement, collision, jumping, swimming, vehicles, powers and the animation state that picks his clip.

Location

Headersrc/GalaxyEggbert/Game/BlupiController.hpp
Sourcessrc/GalaxyEggbert/Game/BlupiController.cpp
NamespaceGalaxyEggbert::Game
Engine dependencyNone. It sees only a Worlds::World, SolidBoxes and plain floats and booleans.

Older pages called this class GEBlupiController and described an invisible collision point. Since then Blupi is drawn as a 3D model converted from the original Ray Dream scenes; the controller decides which clip that model plays. (The class comment at the top of the header still describes the early placeholder; the code is current.)

Purpose

BlupiController reproduces the original game's movement rules in 3D. Each call of Step() turns one tick of steering input into a new position and status: tank-style turning (135 °/s) and walking (2.5 cells/s once under way, after the original's four-tick ease-in), the original's jump speeds and gravity, ledges and walls, crouching and looking up, swimming at the surface and under water, hanging on bars, being squashed or ballooned, riding lifts and crates, six vehicle modes, secret powers, and the one-shot actions (switch, dynamite, pickups, death). It also keeps an AnimState from which the host chooses Blupi's model clip, and it reports one-shot cues (head bump, bar grab, turn, idle fidget) as events for the host to play as sounds.

Speeds are written in the original's units: 64 pixels per block and 20 ticks per second, so 8 px/tick becomes 8 × 20 / 64 = 2.5 blocks per second.

Collaborators

Uses

Used by

InteractionSystem does not use it: the two meet only in the host.

Key members

The header is about 1 800 lines, most of it constants with the original's values and their sources. A selection of the public API of BlupiController.hpp (verified 2026-11-10):

MemberSignatureWhat it does
Stepvoid Step(const Worlds::World& world, float turnInput, float moveInput, bool jumpPressed, bool crouchHeld, bool lookUpHeld, float dt, bool tempPassable = false, bool inSurfWater = false, bool inDeepWater = false, bool pushingCrate = false, bool holdingCrate = false)One tick of movement and collision. Turn and move inputs are −1/0/+1; terrain facts (vanished Temp tiles, water) are computed by the caller and passed in.
SetPositionvoid SetPosition(float x, float y, float z) noexceptMoves Blupi; he stays airborne (teleports and other callers).
SettleOnGroundvoid SettleOnGround(const Worlds::World& world, bool tempPassable = false)After a spawn or respawn, establishes standing before the first input tick (the original's PlayPrepare), so walking starts at once; a start in open air still falls.
GetX/GetY/GetZ, GetYaw, SetYaw, GetVelocityY, IsOnGroundgetters, void SetYaw(float) noexceptPosition (centred X/Z, feet Y), heading (0 faces −Z), vertical speed, ground contact.
GetAnimStateAnimState GetAnimState() const noexceptWhich of the original's actions Blupi is in (see below).
GetAnimIcon, GetDisplayAnimIconint ...() const noexceptThe original sprite icon for the current frame (sprite fallback, first-person indicator).
EventsThisFrameconst std::vector<Event>& EventsThisFrame() const noexceptSound cues of this tick (HeadBumped, BarGrabbed, TurnStarted, IdleFidget, CrateGripped, ...).
GetVehicleMode, IsInVehicle, TriggerMount, TriggerDismount, CanLeaveVehiclebool TriggerMount(VehicleMode mode, bool inNage, bool inSurf) noexceptVehicles: None, Helicopter, Jeep, Tank, Skateboard, Overcraft, each with the original's speeds.
IsSurf, IsNage, GetWaterGaugeLevel, JustDrownedbool ...() const noexceptFloating at the surface, swimming under water, the air gauge (100, red below 25).
TriggerCrush, TriggerBalloon, PopBalloonbool ...() noexceptSquashed by a crusher; carried by a wasp's balloon.
TriggerShield, TriggerPower, TriggerCloud, TriggerHide, TriggerInvertbool ...() noexceptSecret powers and the inverted controls, each with the original's gate; true when granted.
TriggerTeleport, TriggerBye, TriggerSpringBounce, TriggerOneShotAnimbool TriggerTeleport(std::uint16_t icon) noexcept, ...Teleporter transit, the exit wave, spring bounce, one-shot actions such as FireTank.
TriggerDeathLock, ConsumeDeathLockResolvedbool TriggerDeathLock(DeathCause cause, bool shouldRespawn) noexceptFreezes Blupi for a death (Clear1-4, Glu, Drown); the host respawns when it resolves.
SetCrateCells, SetSolidBoxes, FollowCratevoid SetCrateCells(std::vector<std::array<float, 3>> cells), ...Crates and solid BigDecor count as solid for him; the caller updates them before each Step().
SetRidingLift, SetLiftTops, SetLiftUnder, SetTerrainAnimationPhasevoid ...(...) noexceptPer-tick facts from the lifts and the terrain clock.
IsClearAt, CanStandAtstatic bool ...(const Worlds::World&, float x, float y, float z, ...)Collision queries shared with the crate code.
CheatVehicle, DisableGhost, SetCheatSuperBlupivoid CheatVehicle(VehicleMode mode, const Worlds::World* world = nullptr) noexcept, ...Entry points for the typed cheats (vehicles, ghost, megablupi).
constantskMoveSpeed = 2.5f, kTurnSpeed = 0.75π, kJumpSpeed = 12.0f, kGravity = 25.0f, kStepLimit = 4/64, kHeadHeight = 49/64, kBodyHalfWidth = 18/64Blocks per second, radians per second, block units.

AnimState

An enum class AnimState : std::uint8_t with one value per live action of the original's table_blupi: Stop, March, Jump, Air, Down, Up; the squashed and balloon states; each vehicle's stop/march pair; StopNage/MarchNage and StopSurf/MarchSurf for swimming; StopSuspend, MarchSuspend, JumpSuspend on bars; actions such as Push, Switch, TakeDynamite, PutDynamite, FireTank, HelicoGlu; the mockery and reaction poses (Mockery, JumpAie, Ouf1a ... Ouf5, Vertigo, Recede, Advance); Win, Turn, Bye, Teleporting, DeathLocked, PickupBusy, and the short transitions StopMarch and StopJump. The Blupi model in avatars3d/blupi/ has a clip for each state.

How it is used

The host prepares the tick's facts, then steps him once per tick with the scaled simulation time:

const float stepStartFeetY = blupi_.GetY();
...
blupi_.SetTerrainAnimationPhase(worldRuntime_.GetAnimPhase());
blupi_.Step(worldRuntime_.GetWorld(), steering, moveInput, jumpPressed,
            crouchHeld, lookUpHeld, simDt, tempPassable, inSurfWater, inDeepWater,
            wasPushingCrate_, holdingCrate_);

Afterwards it reads EventsThisFrame() for sounds, compares before/after state (landing, water entry, teleport end) and runs the actions. Mission starts go through PlaceBlupi, which sets the crate cells and calls SettleOnGround.

Movement facts worth knowing

Rules and invariants

Tests

Related pages