I'm a gameplay programmer
focused on developing
engaging and unique experiences!

My Resume Learn more

Entity-Component-System (ECS) : A Data-Oriented Gameplay Framework in C++ - Part 4

With the basic functionality of my ECS framework done, I'd like to show how it's set up with some use cases of its core components.

ECS Framework Setup

1. First, download the ECS static library project here:

2. Unzip the file and place the EntityComponentSystem folder under your Engine Solution Folder:

3. Open up your solution and add the EntityComponentSystem to the Engine as an Existing Project:

4. Now add the EntityComponentSystem as a Reference to your game project:

5. In your game's header file, include ECS.h and add an ECS member variable:

#include <Engine/EntityComponentSystem/ECS.h

ECS::ECSEngine* ECSEngine;

6. Create a new ECS instance where your game initializes:

void Initialize()
{
    ECSEngine = new ECS::ECSEngine();
}

7. Add the ECS instance to your update loop:

void Update(const float i_deltaTime)
{
    ECSEngine->Update(i_deltaTime);
}

8. Delete the ECS when the game closes:

void CleanUp()
{
    delete ECSEngine;
}

ECS Framework Usage

Implementing Your Own Entity

#ifndef MYENTITY_H
#define MYENTITY_H

// Includes
//=========

#include <Engine/EntityComponentSystem/Entity.h>

// Class Declaration
//==================

class MyEntity : public ECS::Entity<MyEntity>
{
public:
    MyEntity();
    ~MyEntity();

    virtual void Initialize() override;
    virtual void OnEnable() override;
    virtual void OnDisable() override;
};

#endif	// MYENTITY_H

Creating Your Own Entity

size_t entityID = ECSEngine->GetEntityManager()->CreateEntity<eae6320::MyEntity>();

Deleting Your Own Entity

ECSEngine->GetEntityManager()->DestroyEntity(entityID);

Implementing Your Own Component

#ifndef MYCOMPONENT_H
#define MYCOMPONENT_H

// Includes
//=========

#include <Engine/EntityComponentSystem/Component.h>

// Class Declaration
//==================

class MyComponent: public ECS::Component<MyComponent>
{
public:
    MyComponent();
    ~MyComponent();
};

#endif	// MYCOMPONENT_H

Adding Your Own Component

ECSEngine->GetEntityManager()->GetEntity(entityID)->AddComponent<MyComponent>();

Removing Your Own Component

ECSEngine->GetEntityManager()->GetEntity(entityID)->RemoveComponent<MyComponent>();

Creating Your Own System

#ifndef MYSYSTEM_H
#define MYSYSTEM_H

// Includes
//=========

#include <Engine/EntityComponentSystem/System.h>

// Class Declaration
//==================

class MySystem: public ECS::System<MySystem>
{
public:
    MySystem();
    ~MySystem();

    virtual void PreUpdate(float deltaTime) override;
    virtual void Update(float deltaTime) override;
    virtual void PostUpdate(float deltaTime) override;
};

#endif	// MYSYSTEM_H

Implementing Your Own System

#include "MySystem.h"
#include "MyComponent.h"

MySystem::MySystem()
{

}

MySystem::~MySystem()
{

}

void MySystem::Update(float deltaTime)
{
    for (auto myComponent = m_componentManager->begin<MyComponent>(); myComponent != m_componentManager->end<MyComponent>(); ++myComponent)
    {
        if (*myComponent && (*myComponent)->IsActive())
        {
            (*myComponent)->Update(deltaTime);
        }
    }
}

 

Adding Your Own System

ECSEngine->GetSystemManager()->AddSystem<MySystem>();

Prefab Builder Setup

1. First, download the Prefab project here:

2. Unzip the file and place the PrefabBuilder folder under your Tools Solution Folder:

3. Open up your solution and add the PrefabBuilder to your Tools as an Existing Project:

4. Add this to your AssetBuildFunctions.lua file:

NewAssetTypeInfo( "prefabs",
  {
    RegisterReferencedAssets = function( i_sourceRelativePath )
      local sourceAbsolutePath = FindSourceContentAbsolutePathFromRelativePath( i_sourceRelativePath )
      if DoesFileExist( sourceAbsolutePath ) then
        local prefab = dofile( sourceAbsolutePath )
        RegisterAssetToBeBuilt( prefab.components[1].path, "meshes" )
        RegisterAssetToBeBuilt( prefab.components[2].path, "effects" )
      end
    end,
    ConvertSourceRelativePathToBuiltRelativePath = function( i_sourceRelativePath )
        -- Change the source file extension to the binary version
        local relativeDirectory, file = i_sourceRelativePath:match( "(.-)([^/\\]+)$" )
        local fileName, extensionWithPeriod = file:match( "([^%.]+)(.*)" )
        return relativeDirectory .. fileName .. extensionWithPeriod
    end,
    GetBuilderRelativePath = function()
        return "PrefabBuilder.exe"
    end,
  }
)

Prefab Builder Usage

1. Add a prefabs table to your AssetsToBuild.lua file:

prefabs =
{
    { path = "Prefabs/red_cube.prefab" },
},

2. Add a file like this called red_cube.prefab in your Content/Prefabs folder:

return
{
    isActive = true,
    components =
    {
        {
            class = "Mesh",
            path = "meshes/cube.mesh",
        },
        {
            class = "Effect",
            path = "effects/red.effect",
        },
    },
}

3. Load in the prefab using this function in an Entity:

void eae6320::cRenderComponent::LoadPrefab(const char* const i_prefabPath)
{
    Platform::sDataFromFile dataFromFile;
    Platform::LoadBinaryFile(i_prefabPath, dataFromFile);

    auto currentOffset = reinterpret_cast<uintptr_t>( dataFromFile.data );
    const auto finalOffset = currentOffset + dataFromFile.size;

    bool isActive = *reinterpret_cast<uint8_t*>( currentOffset );

    currentOffset += sizeof( isActive );
    const auto meshPathSize = *reinterpret_cast<uint16_t*>( currentOffset );

    currentOffset += sizeof( meshPathSize );
    char* meshPath = reinterpret_cast<char*>( currentOffset );

    currentOffset += meshPathSize * sizeof( char );
    char* effectPath = reinterpret_cast<char*>( currentOffset );

    Graphics::cMesh::Load( meshPath, m_mesh );
    Graphics::cEffect::Load(m_effect, effectPath );

    SetActive(isActive);
}

Prefab Builder Limitations

Unfortunately, I wasn't able to get custom components implemented due to the time requirement of creating a proper reflection system. So my Prefab Builder only supports Mesh and Effect components.

No Comments Yet.

Leave a comment