The Ultra Engine entity component system allows you to easily add behavior to game objects. This class can be extended to add behavior and properties to an Entity.
Property | Type | Description |
---|---|---|
entity | Entity* | entity this component is attached to. A raw pointer is used to prevent a circular reference |
Collide | Method | called whenever a physics collision occurs |
Connect | Method | creates a new logical connection |
Copy | Method | makes a copy of the component, for copying entities |
FireOutputs | Method | fires a group of logical connections |
Load | Method | called when an actor is loaded or copied |
ReceiveSignal | Method | called when an input is triggered by a logical connection |
Save | Method | called when an actor is saved or copied |
Start | Method | called when a component is added |
Update | Method | called once each time World::Update is called |
You can override these methods or add your own in your component class. To add a new component, just create a new .hpp file in your "Source\Components" folder. You can use separate header and code files if you want, but it is more convenient to put everything in a single file that automatically gets included into your project. Compile your project once and the precompiler will detect your new file and update the component system code. The precompiler will automatically generate the files "ComponentSystem.h" and "ComponentSystem.cpp". These files should never be changed by hand, since they will be overwritten every time the precompiler runs.
The precompiler is limited in its ability to parse C++ declarations, so it's a good idea to stick to straightforward C++ syntax.
To use components in C++, include the component's header file and add the component to an entity with Entity::AddComponent. The game engine will take care of the rest for you:
#include "UltraEngine.h"
#include "Components/Mover.hpp"
using namespace UltraEngine;
int main(int argc, const char* argv[])
{
//Get the displays
auto displays = GetDisplays();
//Create a window
auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR);
//Create a world
auto world = CreateWorld();
//Create a framebuffer
auto framebuffer = CreateFramebuffer(window);
//Create a camera
auto camera = CreateCamera(world);
camera->SetClearColor(0.125);
camera->SetFov(70);
camera->SetPosition(0, 0, -3);
//Create a light
auto light = CreateBoxLight(world);
light->SetRotation(35, 45, 0);
light->SetRange(-10, 10);
//Create a box
auto box = CreateBox(world);
box->SetColor(0,0,1);
//Entity component system
auto component = box->AddComponent<Mover>();
component->rotationspeed.y = 45;
//Main loop
while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
{
world->Update();
world->Render(framebuffer);
}
return 0;
}
The Mover component is about as simple as it gets. It just stores some motion parameters and moves or turns the entity each time Update is called:
#pragma once
#include "UltraEngine.h"
class Mover : public Component
{
public:
Vec3 movementspeed;
Vec3 rotationspeed = Vec3(0, 10, 0);
bool globalcoords = false;
//Update method, called once per loop
virtual void Update()
{
if (globalcoords)
{
this->entity->Translate(movementspeed / 60.0f, true);
}
else
{
this->entity->Move(movementspeed / 60.0f);
}
this->entity->Turn(rotationspeed / 60.0f, globalcoords);
}
//This method will work with simple components
virtual shared_ptr<Component> Copy()
{
return std::make_shared<Mover>(*this);
}
};
To call a component method or get a value, first check if a component of the desired type is attached to the entity, and then call the method:
auto component = entity->GetComponent<HealthManager>();
if (component) component->TakeDamage(10);