Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Game Objects and Entities

GameObject Class

The GameObject is the fundamental entity in VkEngine. All renderable things (players, enemies, props) are GameObjects. Developers create custom subclasses to add game-specific behavior.

Core Properties

class GameObject {
public:
    Transform transform;        // Position, rotation (quaternion), scale
    std::string name;           // For identification
    std::string tag;            // For categorization and filtering
    
    std::function<void(GameObject*, float)> onCollision;  // Collision callback
};

Transform Details:

  • position: World space location (Vector3)
  • rotation: Quaternion representing orientation
  • scale: Object size scaling (Vector3)

All transforms are updated via updateTransform() when modified.

Lifecycle

Creation

Mesh* mesh = engine->getMesh("cube");
Texture* tex = engine->getTexture("white");
PhysicsMaterial* mat = engine->createPhysicsMaterial(0.5f, 0.3f, 0.2f);

auto obj = engine->createGameObject<MyObject>(
    transform,      // Initial transform
    mesh,           // Render geometry
    tex,            // Surface appearance
    mat,            // Physics material
    isDynamic       // true for physics simulation, false for static
);
// Engine calls obj->Start() automatically

Lifecycle Hooks

virtual void Start(Engine* engine);     // Called after creation
virtual void Update(Engine* engine);    // Called every frame
virtual void Destroy(Engine* engine);   // Called on cleanup

Example custom subclass:

class Enemy : public GameObject {
public:
    void Start(Engine* engine) override {
        // Initialization: load resources, set physics, attach sounds
        walkSound = engine->getSound("walk_sfx");
    }
    
    void Update(Engine* engine) override {
        // Per-frame logic: move, animate, detect player proximity
        transform.position += velocity * engine->getDeltaTime();
    }
    
    void Destroy(Engine* engine) override {
        // Cleanup (though most cleanup is automatic)
    }
    
private:
    Sound* walkSound;
    Vector3 velocity;
};

Physics Integration

Static vs Dynamic

// Static object (part of environment)
engine->createGameObject<Rock>(
    transform, mesh, texture, material,
    false  // Static - doesn't move, doesn't respond to physics
);

// Dynamic object (affected by gravity and collisions)
engine->createGameObject<Ball>(
    transform, mesh, texture, material,
    true   // Dynamic - simulated by PhysX
);

Applying Forces

void Update(Engine* engine) override {
    // Apply directional force
    applyForce(Vector3 direction, float power);
    
    // Apply specific force vector
    applyForce(Vector3 force);
    
    // Query current velocity
    Vector3 vel = getVelocity();
}

Collision Callbacks

obj->onCollision = [this](GameObject* other, float impulse) {
    // Called when this object collides with 'other'
    // impulse = magnitude of collision force
    
    if (other->tag == "enemy") {
        health -= 10;
    }
};

Changing Physics at Runtime

void Update(Engine* engine) override {
    if (shouldFall) {
        setPhysicsType(PhysicsType::Dynamic);  // Now affected by gravity
    }
}

Audio Integration

Playing Sounds

void Update(Engine* engine) override {
    if (isMoving) {
        // Play sound at object's location with spatial audio
        Sound* footstep = engine->getSound("footstep");
        playSound(footstep, 1.0f);  // volume = 1.0
    }
}

Sound Control

void Update(Engine* engine) override {
    if (isPaused) {
        setSoundPause(true);  // Pause all sounds from this object
    }
    
    if (shouldStopAll) {
        stopAllSounds();      // Stop all active sounds
    }
}

Spatial Positioning: Sound position automatically follows object transform. 3D sounds have distance-based attenuation configured at creation time.

Rendering

Updating Appearance

void Update(Engine* engine) override {
    if (takeDamage) {
        Texture* damagedTex = engine->getTexture("rock_damaged");
        updateTexture(damagedTex);  // Change surface appearance
    }
}

Getting ID

uint32_t id = getID();  // Unique ID within engine session

CharacterController

A specialized kinematic physics entity for player movement. Unlike GameObjects, CharacterControllers use PhysX’s kinematic character controller for reliable first-person mechanics.

Creation

ICharacterController* controller = engine->createCharacterController(
    height,                 // 1.8f typical for human
    radius,                 // 0.4f typical for human width
    position,               // Initial spawn point
    material,               // Physics material
    interactWithActors      // true = interact with dynamic objects, false = pass through
);

Movement

// Primary movement interface
void Move(Vector3 direction, float speed, float dt);
// direction = normalized direction vector (forward/back/left/right)
// speed = units per second
// dt = delta time from engine

// Example: WASD input
Vector3 dir = Vector3(0, 0, 0);
if (engine->getKey(KeyCode::W) == PRESS) dir.z += 1;
if (engine->getKey(KeyCode::S) == PRESS) dir.z -= 1;
if (engine->getKey(KeyCode::A) == PRESS) dir.x -= 1;
if (engine->getKey(KeyCode::D) == PRESS) dir.x += 1;

controller->Move(dir, 10.0f, engine->getDeltaTime());

Jumping

void Jump(float force);

// Typical usage
if (engine->getKey(KeyCode::Space) == PRESS && isGrounded) {
    controller->Jump(15.0f);  // force = upward impulse
}

State Queries

Vector3 pos = controller->getPosition();
controller->setPosition(newPos);            // Teleport

float vertVel = controller->getVerticalVelocity();
if (vertVel < 0) isGrounded = false;
if (vertVel == 0) isGrounded = true;

Characteristics

  • Built on PhysX kinematic controller (not dynamic rigid body)
  • Automatic gravity application and vertical velocity accumulation
  • Automatically handles slope walking and step climbing
  • Smooth, reliable first-person camera control
  • Can be configured to interact or ignore dynamic objects

Triggers

Non-rendered physics volumes that detect overlaps with GameObjects. Unlike colliders, triggers don’t affect physics simulation.

Creation

Trigger* exitZone = engine->createBoxTrigger(
    position,       // Center position
    size            // Box dimensions (width, height, depth)
);

Callbacks

exitZone->onTriggerEnter = [this](GameObject* other) {
    if (other->tag == "player") {
        levelComplete = true;
    }
};

exitZone->onTriggerExit = [this](GameObject* other) {
    if (other->tag == "player") {
        levelComplete = false;
    }
};

Cleanup

engine->requestDestroyTrigger(exitZone);

Use Cases

  • Level exit zones
  • Pickup areas
  • Hazard detection
  • Cutscene triggers
  • Spawn zones
  • Environmental effects (water, lava)