Blupi

Player character — physics, collision, animation, and billboard rendering.

Overview

Blupi is the player-controlled character. It handles:

Sources: src/GalaxyEggbert/Game/Blupi.hpp and .cpp

Physics Constants

static constexpr float kGravity   = -22.0f;  // units/s²
static constexpr float kJumpSpeed =  10.0f;  // units/s (initial Y velocity)
static constexpr float kMoveSpeed =   5.5f;  // units/s horizontal
static constexpr float kTurnSpeed = 180.0f;  // degrees/s rotation
static constexpr float kHalfW     =   0.35f; // half-width for AABB
static constexpr float kHalfH     =   0.70f; // half-height for AABB

Public Interface

class Blupi {
public:
    Blupi(Context* context, Scene* scene, const World* world, int wcx, int wcz);
    ~Blupi();

    void Update(float dt);
    void Respawn();
    void SetSpawnPoint(Vector3 pos);
    void ApplyExternalDelta(Vector3 delta);
    void StartFlash(float duration);

    Node*   GetNode()            const;
    Vector3 GetPosition()        const;
    float   GetFacingYaw()       const;
    bool    WasJumpedThisFrame() const;
    bool    WasLandedThisFrame() const;
    bool    IsOnGround()         const;
    bool    WasFallDeath()       const;
    void    ClearFallDeath();
};

Update() Flow

Blupi::Update(dt):
  1. Read rotation input (LEFT/RIGHT/Q/E) → update facingYaw_
  2. Compute forward/right vectors from facingYaw_
  3. Read movement input (UP/W, DOWN/S) → forward
  4. Read strafe input (A, D) → strafe
  5. vel_.x/z = (fwd * fwd + right * strafe) * kMoveSpeed
  6. vel_.y += kGravity * dt; vel_.y = max(vel_.y, -30)
  7. Jump: if onGround_ and Space pressed → vel_.y = kJumpSpeed
  8. pos.y += vel_.y * dt
  9. ResolveY(pos)   ← vertical AABB
  10. pos.x += vel_.x * dt; pos.z += vel_.z * dt
  11. ResolveXZ(pos) ← horizontal AABB
  12. Fall death: if pos.y < -10 → fallDeath_=true, SpawnAt(spawn_)
  13. node_->SetPosition(pos)
  14. Update animation state and animTick_
  15. Invincibility flash update
  16. UpdateSprite() ← update billboard UV

Collision

ResolveY(pos): checks solid blocks below/above Blupi using IsSolid(wx, wy, wz). When falling and foot hits a solid block top, Blupi is snapped to the block top + kHalfH. When rising and head hits a block, Y velocity is zeroed.

ResolveXZ(pos): checks 4 side edges (±kHalfW in X and Z) at body Y height. Floor blocks at wy=0 are excluded from wall collision via bodyWY = round(pos.y).

Block solidity: IsSolid(wx, wy, wz) returns !world->getBlock(...).isAir(). Out-of-bounds negative coordinates → solid. Out-of-bounds positive → air.

Sprite Animation

Animation frames are looked up via Tables::GetBlupiIcon(action_, animTick_ / 3). Dividing by 3 matches the original 20 fps animation at a 60 fps update rate. UV coordinates are computed from the icon index into blupi.png (600×2040 px, 10 cols, 60×60 tiles).

Invincibility Flash

StartFlash(duration) sets flashTimer_. Every 0.1 s while active, the billboard's enabled_ flag is toggled. On expiry, the sprite is forced visible.

Dependencies