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:
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:
// 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:
#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 initializationCustom Components
Components must inherit from Component<T> base class and be registered properly:
#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:
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:
#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();