<div id='stars2'></div>
<div id='stars3'></div>
<div id='stars4'></div>
From Sophomore game project where we had to make a game engine from scratch.
1. [[GameEngine snippets#GameobjectManager.cpp]]
2. [[GameEngine snippets#CollisionSat.cpp]]
3. [[GameEngine snippets#Application.h]]
## GameobjectManager.cpp
```cpp
//-----------------------------------------------------------------------------
//
// File Name: GameObjectManager.cpp
// Author(s): Steven Kugies
// Team: Apricat Games
// Course: Game200
//
// Copyright © 2020 DigiPen (USA) Corporation.
//
//-----------------------------------------------------------------------------
#include "GameObjectManager.h"
#include "GameObject.h"
#include "../Core/GamePauseLevel.h"
namespace ECS
{
//gives a unique id for every created gameobject
static int newID = 0;
/*!****************************************************************************
\brief
CONSTRUCTOR of GameObjectManager
******************************************************************************/
GameObjectManager::GameObjectManager()
{
firstAvailableObj_ = 1;
PoolSetup(10);
}
/*!****************************************************************************
\brief
DESTRUCTOR of GameObjectManager
******************************************************************************/
GameObjectManager::~GameObjectManager()
{
}
/*!****************************************************************************
\brief
Initializes the Game Object pool
\param poolSize
How many GameObjects we want to have at the start in the pool
******************************************************************************/
void GameObjectManager::PoolSetup(unsigned int poolSize)
{
GameObjects_.resize(poolSize);
for (unsigned int i = 0; i < poolSize; i++)
{
GameObjects_[i].next_ = i + 1;
GameObjects_[i].id_ = newID++;
}
GameObjects_.back().next_ = NULL;
firstAvailableObj_ = 1;
}
/*!****************************************************************************
\brief
Resizes the pool to double it's capacity when it is full
******************************************************************************/
void GameObjectManager::ExpandPool()
{
const unsigned int oldSize = unsigned int(GameObjects_.size());
const unsigned int size = oldSize * 2;
GameObjects_.resize(size);
//initialize the new objects into the free list
for (unsigned int i = oldSize; i < size; i++)
{
GameObjects_[i].id_ = newID++;
}
//Setting up the linking of objects in the freelist
for (unsigned int i = oldSize-1; i < size; i++)
{
GameObjects_[i].next_ = i + 1;
}
//set last object to 0 as nothing exists beyond that point
GameObjects_[size - 1].next_ = 0;
//the next object that can be spawned
firstAvailableObj_ = oldSize;
}
/*!****************************************************************************
\brief
Gets the pool of objects
\return
reference to the pool
******************************************************************************/
std::vector<GameObject>& GameObjectManager::GetPool()
{
return GameObjects_;
}
/*!****************************************************************************
\brief
Spawns a gameobject from the pool. Expands the pool if the pool is empty.
\return
id of the spawned gameobject
******************************************************************************/
ObjectId GameObjectManager::Spawn()
{
//Expand pool if empty
if (firstAvailableObj_ == 0)
ExpandPool();
//Gets first available object for use
GameObject& g = GameObjects_[firstAvailableObj_];
g.active_ = true;
g.destroyed_ = false;
g.saveable_ = true;
g.OMBus_.Clear();
//update first available to the next object in free list
firstAvailableObj_ = g.next_;
return g.id_;
}
/*!****************************************************************************
\brief
Puts GameObject back into pool for later use
\param id
the id of the object to despawn
******************************************************************************/
void GameObjectManager::DeSpawn(ObjectId id)
{
//update the list of available objects
GameObjects_[id].next_ = firstAvailableObj_;
firstAvailableObj_ = id;
GameObjects_[id].setName("");
GameObjects_[id].SetPersistent(false);
//reset basic values
GameObjects_[id].active_ = false;
GameObjects_[id].destroyed_ = false;
ClearComponentBits(id);
}
/*!****************************************************************************
\brief
Marks the gameobject to be despawned at the end of the Update
\param id
the id of the object to despawn
******************************************************************************/
void GameObjectManager::DestroyGameObject(ObjectId id)
{
GameObjects_[id].destroyed_ = true;
}
/*!****************************************************************************
\brief
Sets all objects to be destroyed except for persistent objects
******************************************************************************/
void GameObjectManager::ClearGameObjects()
{
const unsigned int size = (const unsigned int)GameObjects_.size();
for (unsigned int i = 1; i < size; i++)
{
GameObject& obj = GameObjects_[i];
if (obj.active_ && !obj.IsPersistent())
DestroyGameObject(obj.id_);
}
}
void GameObjectManager::ClearPauseObjects()
{
const unsigned int size = (const unsigned int)GameObjects_.size();
for (unsigned int i = 1; i < size; i++)
{
GameObject& obj = GameObjects_[i];
if (obj.active_ && !obj.IsPersistent() && obj.StateId_ == Engine::GameStateManager::LevelID::GamePause)
DestroyGameObject(obj.id_);
}
}
void GameObjectManager::ClearActiveObjects()
{
const unsigned int size = (const unsigned int)GameObjects_.size();
for (unsigned int i = 1; i < size; i++)
{
GameObject& obj = GameObjects_[i];
if (obj.active_ && !obj.IsPersistent() && obj.StateId_ == Engine::Application::instance().GameState_->GetCurrent())
DestroyGameObject(obj.id_);
}
}
/*!****************************************************************************
\brief
Get a pointer to the gameobject
\param id
the id of the object we want
\return
gameobject pointer
******************************************************************************/
GameObject* GameObjectManager::GetGameObject(ObjectId id)
{
return &GameObjects_[id];
}
/*!****************************************************************************
\brief
Iterates through each gameObject. Takes the name of a gameObject and returns
an ObjectId with the same name.
\param name
the name of the game object who's ID we want
\return
ObjectId of the object with the same name as the parameter.
******************************************************************************/
ObjectId GameObjectManager::GetIDFromString(std::string name, bool paused)
{
//For each game object in GameObjects_
for (GameObject& obj : GameObjects_)
{
if (paused || (obj.GetStateId() == (int)Engine::Application::instance().GameState_->GetCurrent()))
{
if (obj.name_ == name)
{
return obj.id_;
}
}
}
//If no match found, return 0
return 0;
}
/*!****************************************************************************
\brief
Sets which Components this gameobject has
\param id
the id of the gameobject
\param type
the type of component
\param state
whether the gameobject has the component or not
******************************************************************************/
void GameObjectManager::SetComponentBit(ObjectId id, int type, bool state)
{
GameObjects_[id].componentBitSet_[type] = state;
}
/*!****************************************************************************
\brief
When an object has all components removed use to clear objects
component bitset
\param id
object to clear
******************************************************************************/
void GameObjectManager::ClearComponentBits(ObjectId id)
{
GameObjects_[id].componentBitSet_ = 0;
}
/*!****************************************************************************
\brief
Gets the current size of the object pool
\return
the pool size
******************************************************************************/
int GameObjectManager::PoolSize()
{
return (int)GameObjects_.size();
}
/*!****************************************************************************
\brief
Gets the current number of active objects in the pool
\return
total number of active objects
******************************************************************************/
int GameObjectManager::TotalActive()
{
int count = 0;
for (GameObject& obj : GameObjects_)
{
if (obj.isActive())
count++;
}
return count;
}
}
```
## CollisionSat.cpp
```cpp
//-----------------------------------------------------------------------------
//
// File Name: CollisionSAT.cpp
// Author(s): Steven Kugies
// Team: Apricat Games
// Course: Game200
//
// Copyright © 2020 DigiPen (USA) Corporation.
//
//-----------------------------------------------------------------------------
#include "CollisionSystem.h"
#include <glm/detail/func_geometric.inl>
/*!****************************************************************************
\brief
Uses Seperate Axis Theorem to do a Collision Check between 2 colliders
\param col1
the first collider
\param col2
the second collider
\param CollisionAxis
the shortest vector to move the colliders to no longer be penetrating
\return
if there was a collision
******************************************************************************/
bool ECS::CollisionSystem::CollisionSAT(Collider& col1, Collider& col2, glm::vec2& CollisionAxis)
{
std::vector<glm::vec2>& verts1 = col1.verts_;
std::vector<glm::vec2>& verts2 = col2.verts_;
const int totalVerts1 = static_cast<int>(verts1.size());
const int totalVerts2 = static_cast<int>(verts2.size());
int axis = 0; /*index of the smallest collision axis*/
bool shape = 0; /*used to check origin of axis for it's direction*/
float smallest = FLT_MAX; /*length of smallest collision axis*/
//First test in regards to the first collider
for (int vert = 0; vert < totalVerts1; vert++)
{
const int nextVert = (vert + 1) % totalVerts1;
const glm::vec2 normal = { -(verts1.at(nextVert).y - verts1.at(vert).y),
verts1.at(nextVert).x - verts1.at(vert).x };
//used in the next two 'for loops'. Represents a vertex projected onto our normal vector
float projection;
//projects each point of collider1 onto normal and saves only the smallest and largest point
float min1 = 999999;
float max1 = -999999;
for (int v = 0; v < totalVerts1; v++)
{
projection = (verts1.at(v).x * normal.x + verts1.at(v).y * normal.y);
if (projection < min1)
min1 = projection;
if (projection > max1)
max1 = projection;
}
//projects each point of collider2 onto normal and saves only the smallest and largest point
float min2 = 999999;
float max2 = -999999;
for (int v = 0; v < totalVerts2; v++)
{
projection = (verts2.at(v).x * normal.x + verts2.at(v).y * normal.y);
if (projection < min2)
min2 = projection;
if (projection > max2)
max2 = projection;
}
//compares the smallest and largest points of the two objects to check if there is any overlap
if (!(max2 >= min1 && max1 >= min2))
return false;
//finding the smallest collision Axis
float temp = max1 - min2;
if (temp < smallest)
{
smallest = temp;
axis = vert;
}
temp = max2 - min1;
if (temp < smallest)
{
smallest = temp;
axis = vert;
}
}
//Second test in regards to the Second collider
for (int vert = 0; vert < totalVerts2; vert++)
{
int nextVert = (vert + 1) % totalVerts2;
glm::vec2 normal = { -(verts2.at(nextVert).y - verts2.at(vert).y),
verts2.at(nextVert).x - verts2.at(vert).x };
//used in the next two for loops. Represents a vertex projected onto our normal vector
float projection;
//projects each point of collider1 onto normal and saves only the smallest and largest point
float min1 = FLT_MAX;
float max1 = -FLT_MIN;
for (int v = 0; v < totalVerts1; v++)
{
projection = (verts1.at(v).x * normal.x + verts1.at(v).y * normal.y);
if (projection < min1)
min1 = projection;
if (projection > max1)
max1 = projection;
}
//projects each point of collider2 onto normal and saves only the smallest and largest point
float min2 = FLT_MAX;
float max2 = -FLT_MIN;
for (int v = 0; v < totalVerts2; v++)
{
projection = (verts2.at(v).x * normal.x + verts2.at(v).y * normal.y);
if (projection < min2)
min2 = projection;
if (projection > max2)
max2 = projection;
}
//compares the smallest and largest points of the two objects to check if there is any overlap
if (!(max2 >= min1 && max1 >= min2))
return false;
//finding the smallest collision Axis
float temp = max1 - min2;
if (temp < smallest)
{
smallest = temp;
axis = vert;
shape = 1;
}
temp = max2 - min1;
if (temp < smallest)
{
smallest = temp;
axis = vert;
shape = 1;
}
}
//Axis depends on which shape it came from
if (shape)
{
const int nextVert = (axis + 1) % totalVerts2;
CollisionAxis = { -(verts2.at(nextVert).y - verts2.at(axis).y),verts2.at(nextVert).x - verts2.at(axis).x };
CollisionAxis *= -1;
}
else
{
const int nextVert = (axis + 1) % totalVerts1;
CollisionAxis = { -(verts1.at(nextVert).y - verts1.at(axis).y),verts1.at(nextVert).x - verts1.at(axis).x };
}
float mag = glm::dot(CollisionAxis, CollisionAxis);
CollisionAxis *= smallest / mag;
return true;
}
```
<div id='stars2'></div>
<div id='stars3'></div>
<div id='stars4'></div>
## Application.h
```cpp
//-----------------------------------------------------------------------------
//
// File Name: Application.cpp
// Author(s): Ben Schwedler, Erin Scribner, Scott Fado-Bristow,
// Steven Kugies, Yi-Chun Chen
// Team: Apricat Games
// Course: Game200
//
// Copyright © 2020 DigiPen (USA) Corporation.
//
//-----------------------------------------------------------------------------
#include <Windows.h>
#include "Application.h"
#include <chrono>
#include "Message.h"
#include "WindowSystem.h"
#include "Level1.h" //main level
#include "GameOverLevel.h" //game over screen
#include "GameWonLevel.h" //winner screen
#include "LevelA.h"
#include "ScottLevel.h"
#include "AlexLevel.h"
#include "SoundLevel.h"
#include "../Utilities/window/DebugWindow.h"
#include "../Utilities/window/EditorWindow.h"
#include "../Utilities/window/SystemsInfoWindow.h"
#include "FMODSystem.h"
#include "StevenLevel.h"
#include "TitleScreen.h"
#include "SplashScreen.h"
#include "OptionsLevel.h"
#include "Credits.h"
#include "LevelExit.h"
#include "GamePauseLevel.h"
#include "ObjectEditor.h"
#include "HowToPlayLevel.h"
#include "CreditsPause.h"
namespace Engine
{
Application Application::instance_;
float GetFixedDeltaTime(std::chrono::steady_clock::time_point& current);
/*!****************************************************************************
\brief
CONSTRUCTOR of Application
******************************************************************************/
Application::Application() : lightSource_()
{
//This is first, due to how the subscribe stuff is working right now
messageBus_ = new Message::MessageBus();
//The managers are up here due to default meshes being assigned
meshManager_ = new Manager::MeshManager();
spriteSourceManager_ = new Manager::SpriteSourceManager();
ECS_ = new ECS::ECSystem;
GameState_ = new GameStateManager;
objectArchetypeManager_ = new Manager::GameObjectArchManager();
isRunning = true;
windowSystem = nullptr;
renderer = nullptr;
Editor = nullptr;
FMODSystemInstance = nullptr;
camera_ = nullptr;
perspCamera_ = nullptr;
//DebugData.SetBig();
//temp
GameState_->GameStateAdd(new Level1);
GameState_->GameStateAdd(new LevelA);
GameState_->GameStateAdd(new ScottLevel(true));
GameState_->GameStateAdd(new AlexLevel);
GameState_->GameStateAdd(new SoundLevel);
GameState_->GameStateAdd(new StevenLevel);
//If there is a true boolean, it is a pause state
GameState_->GameStateAdd(new GameOver(true));
GameState_->GameStateAdd(new GameWon(true));
GameState_->GameStateAdd(new TitleScreen);
GameState_->GameStateAdd(new SplashScreen);
GameState_->GameStateAdd(new OptionsLevel(true));
GameState_->GameStateAdd(new HowToPlayLevel(true));
//If there is a true boolean, it is a pause state
GameState_->GameStateAdd(new Credits(true));
GameState_->GameStateAdd(new LevelExit);
//If there is a true boolean, it is a pause state
GameState_->GameStateAdd(new GamePause(true));
GameState_->GameStateAdd(new ObjectEditor);
GameState_->GameStateAdd(new CreditsPause(true));
}
/*!****************************************************************************
\brief
DESTRUCTOR of Application
******************************************************************************/
Application::~Application()
{
#ifdef _Editor
DebugData.Write();
#endif //
delete Editor;
delete renderer;
delete windowSystem;
delete ECS_;
delete meshManager_;
delete spriteSourceManager_;
delete FMODSystemInstance;
delete messageBus_;
delete camera_;
delete perspCamera_;
for (int i = 0; i < MAX_LIGHT_NUM; ++i)
{
delete lightSource_[i];
}
}
/*!****************************************************************************
\brief
Initializes various parts of the application
\param title
the title of the application
\param width
width of the window
\param height
height of the window
\param fullscreen
if the window should start in fullscreen
******************************************************************************/
void Application::Init(const char* title, int width, int height, bool fullscreen)
{
windowSystem = new WindowSystem(title, width, height, fullscreen);
renderer = new Renderer();
FMODSystemInstance = new FMODNamespace::FMODSystem();
#if 0
camera_ = new Camera(
Camera::PROJ_TYPE::ORTHO,
glm::vec3(0.0f, 0.0f, 1.0f), // Position.
glm::vec3(0.0f, 0.0f, 0.0f), // Target.
glm::vec3(0.0f, 1.0f, 0.0f), // World up.
90.0f, // FOV.
(float)windowSystem->GetWidth() / (float)windowSystem->GetHeight(), // Aspect ratio.
0.1f, // Near plane.
1000.0f // Far plane.
);
#else
camera_ = new Camera(
Camera::PROJ_TYPE::PERSP,
glm::vec3(0.0f, 0.0f, 360.0f), // Position.
glm::vec3(0.0f, 0.0f, 0.0f), // Target.
glm::vec3(0.0f, 1.0f, 0.0f), // World up.
90.0f, // FOV.
(float)windowSystem->GetWidth() / (float)windowSystem->GetHeight(), // Aspect ratio.
0.1f, // Near plane.
1000.0f // Far plane.
);
#endif
// Create light sources.
for (int i = 0; i < MAX_LIGHT_NUM; ++i)
{
lightSource_[i] = new LightSource(i, glm::vec2(0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), 1.0f, 1500.0f, 1.9f);
}
// Hard code the light sources.
lightSource_[1]->SetIntensity(0.7f);
lightSource_[1]->SetPosition(glm::vec2(8496.0f, 2813.0f));
lightSource_[2]->SetIntensity(0.7f);
lightSource_[2]->SetPosition(glm::vec2(29857.0f, 7356.0f));
lightSource_[3]->SetIntensity(0.7f);
lightSource_[3]->SetPosition(glm::vec2(47951.0f, 10427.0f));
#ifdef _Editor
Editor = new ImGuiManager(windowSystem->GetWindow());
Editor->AddWindow(new DebugWindow);
Editor->AddWindow(new EditorWindow);
Editor->AddWindow(new SystemsInfoWindow);
BaseWindow* OEwindow_ = Application::instance().Editor->AddWindow(new ObjectEditorWindow);
OEwindow_->Toggle();
#endif //_NO_EDITOR
//GameState_->GameStateNextGameState(GameStateManager::TestLevel);
glfwSetInputMode(windowSystem->GetWindow(), GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}
/*!****************************************************************************
\brief
The Main Game Loop
based on: https://gafferongames.com/post/fix_your_timestep/
******************************************************************************/
void Application::Run()
{
//how much time has passed since startup
float t = 0.0f;
auto currentTime = std::chrono::steady_clock::now();
//how much time has passed since last update
float accumulator = dt;
while (isRunning && !windowSystem->WindowShouldClose())
{
//get time since last update
const float delta = GetFixedDeltaTime(currentTime);
//checks for input
//----------------
//Checks windows messaging for new keyboard events
windowSystem->PollEvents();
//keyInput_->UpdateKeys();
HandleEvents(delta);
/*Message* msg = new Message(1);
ECS_->BroadcastMessage(msg, 1.0f, 0);
delete(msg);
*/
//add how much time has passed since previous update
accumulator += delta;
//fixed game update
while (accumulator >= dt)
{
// game systems update
// -----------------
if (windowSystem->GetWindowState() != WindowSystem::WINDOW_STATE::MINIMIZED)
{
Engine::Application::instance().FMODSystemInstance->ControlPause(false);
Update(dt);
}
else
{
Engine::Application::instance().FMODSystemInstance->ControlPause(true);
//Update only FMODSystem because we need it to process the pause request.
FMODSystemInstance->Update();
}
accumulator -= dt;
t += dt;
}
// render
// ------
const float alpha = accumulator / dt;
renderer->Clear(glm::vec4(244.0f / 255.0f, 241.0f / 255.0f, 234.0f / 255.0f, 1.0f));
renderer->SetShader(Shader::SHADER_TYPE::LIGHTING);
//renderer->SetShader(Shader::SHADER_TYPE::DEFAULT);
Render(alpha);
windowSystem->SwapBuffers();
}
}
/*!****************************************************************************
\brief
where input is processed
\param dt
how much time since the previous update
******************************************************************************/
void Application::HandleEvents(float dt)
{
//Here will lie stuff for handling Windows Messages
//This needs WinMain()
windowSystem->ProcessInput(); // Testing. -Alex
}
/*!****************************************************************************
\brief
the main Render call
\param dt
percent until the next fixed update. Used to interpolate between
previous and current positions
******************************************************************************/
void Application::Update(float dt)
{
//Game State Manager
GameState_->GameStateUpdate(dt);
//GameObject Manager/ECS
ECS_->Update(dt);
//Update FMOD after the level and the objects have been updated
FMODSystemInstance->Update();
}
/*!****************************************************************************
\brief
where input is processed
\param dt
how much time since the previous
******************************************************************************/
void Application::Render(float dt)
{
ECS_->Draw(dt);
#ifdef _Editor
Editor->Update();
#endif // _EDITOR
}
/*!****************************************************************************
\brief
gets the timestep
\return
the timestep
******************************************************************************/
float Application::GetTimeStep()
{
return dt;
}
/*!****************************************************************************
\brief
change the timestep
\param timestep
value to set timestep to
******************************************************************************/
void Application::SetTimeStep(float timestep)
{
dt = timestep;
}
/*!****************************************************************************
\brief
given a point in time return how much time has passed since then
\param current
the time at the start of the previous frame
******************************************************************************/
float GetFixedDeltaTime(std::chrono::steady_clock::time_point& current)
{
auto newTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration<float>(newTime - current);
float frameTime = duration.count();
current = newTime;
if (frameTime > 0.25f)
frameTime = 0.25f;
return frameTime;
}
}
```
<div id='stars2'></div>
<div id='stars3'></div>
<div id='stars4'></div>
## ECS.cpp
```cpp
//-----------------------------------------------------------------------------
//
// File Name: EntityComponentSystem.cpp
// Author(s): Steven Kugies
// Team: Apricat Games
// Course: Game200
//
// Copyright © 2020 DigiPen (USA) Corporation.
//
// Partially based on this: https://austinmorlan.com/posts/entity_component_system/
//-----------------------------------------------------------------------------
//TODO: add safety checks to spawning objects
//------------------------------------------------------------------------------
// Includes:
//------------------------------------------------------------------------------
#include "EntityComponentSystem.h"
#include "GameObject.h"
#include "BaseComponentSystem.h"
#include "SpriteSystem.h"
#include "CollisionSystem.h"
#include "PhysicsSystem.h"
#include "BehaviorSystems.h"
#include "SpineAnimationSystem.h"
#include "AnimationSystem.h"
#include "ParticleSystem.h"
#include "SoundSystem.h"
#include "TOSystem.h"
#include "RenderSystem.h"
#include "../Core/Trace.h"
namespace ECS
{
//----------------------------------------------------------------------------
// Private Function Declarations:
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// Public Functions:
//----------------------------------------------------------------------------
/*!****************************************************************************
\brief
CONSTRUCTOR of the Entity Component System
******************************************************************************/
ECSystem::ECSystem()
{
Systems_.push_back(new RenderSystem);
//Systems_.push_back(new SpriteSystem);
Systems_.push_back(new BehaviorSystem);
Systems_.push_back(new PhysicsSystem);
Systems_.push_back(new CollisionSystem);
Systems_.push_back(new AnimationSystem);
//Systems_.push_back(new SpineAnimationSystem);
Systems_.push_back(new ParticleSystem);
Systems_.push_back(new SoundSystem);
Systems_.push_back(new TOSystem);
//Systems_.push_back(new RenderSystem);
}
/*!****************************************************************************
\brief
DESTRUCTOR of the Entity Component System
******************************************************************************/
ECSystem::~ECSystem()
{
while (!Systems_.empty())
{
delete Systems_.back();
Systems_.pop_back();
}
}
/*!****************************************************************************
\brief
Updates the various systems
\param dt
time since last update
******************************************************************************/
void ECSystem::Update(float dt)
{
ComponentManager_.Update(dt);
for (BaseComponentSystem* sys : Systems_)
{
if (*sys->Enabled())
sys->Update(dt);
}
CleanupGameObjects();
}
/*!****************************************************************************
\brief
calls the various systems to draw to the screen
\return
percentage of time until the next Update call.
Used to interpolate position between current and previous frame.
******************************************************************************/
void ECSystem::Draw(float dt)
{
for (BaseComponentSystem* sys : Systems_)
{
if (sys->Enabled())
sys->Draw(dt);
}
}
/*!****************************************************************************
\brief
Calls GameObject manager to spawn a new GameObject
\return
id of the new gameobject
******************************************************************************/
ObjectId ECSystem::CreateGameObject()
{
return GameObjectManager_.Spawn();
}
/*!****************************************************************************
\brief
Calls GameObject manager to destroy gameobject at end of Update
\param id
id of object to be destroyed
******************************************************************************/
void ECSystem::DestroyGameObject(ObjectId id)
{
GameObjectManager_.DestroyGameObject(id);
}
void ECSystem::ClearGameObjects()
{
GameObjectManager_.ClearGameObjects();
}
/*!****************************************************************************
\brief
Calls Component Manager to spawn a new component
Then calls GameObject Manager to set it has that type of component.
\param id
id of object to be destroyed
\param type
the type of component to spawn
\return
pointer to the created component
******************************************************************************/
Component* ECSystem::AddComponent(ObjectId id, cType type)
{
if (GameObjectManager_.GetGameObject(id)->Has(type))
{
traceMessage("------");
traceMessage(Engine::Application::instance().ECS_->GameObjectManager_.GetGameObject(id)->GetName());
traceMessage("Object already has type");
traceMessageEnum(type);
traceMessage("------");
return nullptr;
}
Component* C = ComponentManager_.Spawn(id, type);
GameObjectManager_.SetComponentBit(id, int(type), true);
RegisterComponent(id);
return C;
}
/*!****************************************************************************
\brief
Calls ComponentManager to despawn a component from gameobject
\param id
id of the gameobject
\param type
the type of component to despawn
******************************************************************************/
void ECSystem::RemoveComponent(ObjectId id, cType type)
{
ComponentManager_.Despawn(id, type);
Engine::Application::instance().ECS_->GameObjectManager_.SetComponentBit(id, int(type), false);
}
/*!****************************************************************************
\brief
Calls ComponentManager to despawn all component from gameobject
\param id
id of the gameobject
******************************************************************************/
void ECSystem::RemoveComponent(ObjectId id)
{
ComponentManager_.Despawn(id);
Engine::Application::instance().ECS_->GameObjectManager_.ClearComponentBits(id);
}
/*!****************************************************************************
\brief
Gets the objects name from the gameobject manager
\param id
id of the gameobject
******************************************************************************/
const std::string& ECSystem::GetObjectName(ObjectId id)
{
return GameObjectManager_.GetGameObject(id)->GetName();
}
//----------------------------------------------------------------------------
// Private Functions:
//----------------------------------------------------------------------------
/*!****************************************************************************
\brief
despawns all active objects and components
******************************************************************************/
void ECSystem::CleanupGameObjects()
{
const unsigned int size = (unsigned int)GameObjectManager_.GameObjects_.size();
for (unsigned int i = 1; i < size; i++)
{
GameObject& obj = GameObjectManager_.GameObjects_[i];
if (obj.isDestroyed())
{
GameObjectManager_.DeSpawn(obj.GetId());
ComponentManager_.Despawn(obj.GetId());
DeRegisterComponent(obj.GetId());
}
}
}
/*!****************************************************************************
\brief
Checks all systems to see if objects components should be registered with it
\param id
id of the gameobject
******************************************************************************/
void ECSystem::RegisterComponent(ObjectId id)
{
for (BaseComponentSystem* sys : Systems_)
{
sys->OnEntityCreated(id);
}
}
void ECSystem::CleanupPauseObjects()
{
GameObjectManager_.ClearPauseObjects();
}
void ECSystem::CleanupActiveObjects()
{
GameObjectManager_.ClearActiveObjects();
}
/*!****************************************************************************
\brief
Removes the Object from all systems
\param id
id of the gameobject
******************************************************************************/
void ECSystem::DeRegisterComponent(ObjectId id)
{
//TODO: might not be needed but might need to add a check inside systems for when a component is only removed
for (BaseComponentSystem* sys : Systems_)
{
sys->OnEntityDestroyed(id);
}
}
/*!****************************************************************************
\brief
Gets the list of Systems
\return
reference to the vector of systems
******************************************************************************/
std::vector<BaseComponentSystem*>& ECSystem::GetSystem()
{
return Systems_;
}
}
```