Skip to content

Getting Started with Engine

This guide demonstrates how to use the Engine's ECS architecture to create game objects and systems.

Creating Entities

The Astralix engine uses an entity-component system where entities are created via EntityManager and components are added through ComponentManager or directly on entity objects.

Basic entity creation:

cpp
using namespace astralix;

// Get managers (singleton access)
auto entityManager = EntityManager::get();
auto componentManager = ComponentManager::get();

// Create an entity (derived from IEntity)
// Note: add_entity requires a concrete entity type, not just an ID
auto* player = entityManager->add_entity<GameObject>("Player");

// Add components directly on entity
auto* transform = player->add_component<TransformComponent>(
    glm::vec3(0, 0, 0),  // position
    glm::quat(1, 0, 0, 0),  // rotation
    glm::vec3(1, 1, 1)  // scale
);

// Or add components via ComponentManager
componentManager->add_component<RigidBodyComponent>(player->get_entity_id());

Querying Entities

Find entities using manager methods:

cpp
// Get all entities with a specific component
auto* entity = entityManager->get_entity_with_component<TransformComponent>();

// Check if any entity has a component
bool hasTransform = entityManager->has_entity_with_component<TransformComponent>();

// Get entity by name
auto* player = entityManager->get_entity_by_name("Player");

// Iterate over all entities
entityManager->for_each([](IEntity* entity) {
    // Process each entity
    if (entity->has_component<TransformComponent>()) {
        auto* transform = entity->get_component<TransformComponent>();
        // Use transform...
    }
});

// Get all components of a type
auto transforms = componentManager->get_components<TransformComponent>();
for (auto* transform : transforms) {
    // Process each transform component
}

Creating Systems

Implement custom game logic with systems. All systems must inherit from System<T> and implement lifecycle methods:

cpp
#include "systems/system.hpp"
#include "events/key-codes.hpp"
#include "managers/window-manager.hpp"

namespace astralix {

class PlayerControllerSystem : public System<PlayerControllerSystem> {
public:
    void start() override {
        // Initialize system
    }

    void fixed_update(double fixed_dt) override {
        // Physics-rate updates
    }

    void pre_update(double dt) override {
        // Pre-update logic
    }

    void update(double dt) override {
        auto entityManager = EntityManager::get();

        // Iterate over entities with custom logic
        entityManager->for_each([dt](IEntity* entity) {
            if (!entity->has_component<PlayerComponent>()) return;

            auto* transform = entity->get_component<TransformComponent>();
            auto* player = entity->get_component<PlayerComponent>();

            if (!transform || !player) return;

            // Handle input using window manager helpers
            if (input::IS_KEY_DOWN(input::KeyCode::W)) {
                transform->position.z += player->speed * dt;
            }
        });
    }
};

}

// Systems are registered in Engine::start() based on project config
// Custom systems would need to be added to the engine initialization

Custom Components

Components must inherit from Component<T> base class and be registered properly:

cpp
#include "components/component.hpp"

namespace astralix {

class PlayerComponent : public Component<PlayerComponent> {
public:
    PlayerComponent(const EntityID& entity_id, const ComponentID& id)
        : Component(entity_id, id) {}

    float speed = 5.0f;
    float jump_force = 10.0f;
    int health = 100;
    int max_health = 100;
};

class EnemyComponent : public Component<EnemyComponent> {
public:
    EnemyComponent(const EntityID& entity_id, const ComponentID& id)
        : Component(entity_id, id) {}

    float move_speed = 2.0f;
    float detection_radius = 10.0f;
    int damage = 10;
};

}

Note: Custom components need constructors that accept EntityID and ComponentID parameters as required by the component system.

Building Complex Entities

Create helper functions to compose entities with multiple components:

cpp
IEntity* CreatePlayer(glm::vec3 position) {
    auto entityManager = EntityManager::get();

    auto* entity = entityManager->add_entity<GameObject>("Player");

    // Add components
    entity->add_component<TransformComponent>(
        position,
        glm::quat(1, 0, 0, 0),
        glm::vec3(1, 1, 1)
    );

    entity->add_component<RigidBodyComponent>(
        entity->get_entity_id(),
        ComponentID()  // Component ID generated by manager
    );

    entity->add_component<PlayerComponent>(
        entity->get_entity_id(),
        ComponentID()
    );

    entity->add_component<CameraComponent>(
        entity->get_entity_id(),
        ComponentID()
    );

    return entity;
}

IEntity* CreateEnemy(glm::vec3 position) {
    auto entityManager = EntityManager::get();

    auto* entity = entityManager->add_entity<GameObject>("Enemy");

    entity->add_component<TransformComponent>(
        position,
        glm::quat(1, 0, 0, 0),
        glm::vec3(1, 1, 1)
    );

    entity->add_component<RigidBodyComponent>(
        entity->get_entity_id(),
        ComponentID()
    );

    entity->add_component<EnemyComponent>(
        entity->get_entity_id(),
        ComponentID()
    );

    return entity;
}

Scene Creation

Organize entities into scenes by inheriting from the Scene class:

cpp
#include "entities/scene.hpp"
#include "managers/scene-manager.hpp"

namespace astralix {

class GameScene : public Scene {
public:
    GameScene() : Scene("GameScene") {}

    void start() override {
        // Create player
        auto* player = CreatePlayer(glm::vec3(0, 0, 0));

        // Create enemies
        for (int i = 0; i < 10; i++) {
            glm::vec3 pos = glm::vec3(rand() % 100, 0, rand() % 100);
            CreateEnemy(pos);
        }
    }

    void update() override {
        // Scene-specific update logic runs each frame
    }

private:
    // Helper methods
    IEntity* CreatePlayer(glm::vec3 position) {
        // Use Scene::add_entity<T> helper
        return this->add_entity<GameObject>("Player");
    }

    IEntity* CreateEnemy(glm::vec3 position) {
        return this->add_entity<GameObject>("Enemy");
    }
};

}

// Register the scene with SceneManager
auto sceneManager = SceneManager::get();
sceneManager->add_scene<GameScene>();

// Get active scene
Scene* activeScene = sceneManager->get_active_scene();

Next Steps

  • Learn about Physics for rigid body simulation
  • Explore Renderer for graphics
  • Review Editor for visual editing tools