Game Engine

Overview

  • Platform: PC
  • Team Size: 1
  • Project Length: Development since 2014 (off and on)
  • Languages: C++, GLSL
  • Tools: Adobe Suite, Blender, Visual Studio

Game Engine (which probably needs a better name) started as a class project during my third year at Becker College. We were each tasked with developing upon a very basic template of an engine, adding new features each week. By the end of the class, the engine supported several features, including PLY file loading, forward rendering and different light types.

Since then, I've made significant changes to the engine, including the creation of an entity-component system, the addition of deferred rendering, shadow mapping, a shader preprocessor system, and more. Although there are bits and pieces of the original codebase from the class, most of what's in there now was added much later.

This project is something I like to come back to when I want to try new things, or implement something found in an existing engine to gain a better understanding of how it works. Although I don't see it as a platform to build a commercial product upon, I still enjoy coming back now and then to make it better.

Features

  • Multipass forward and deferred rendering
  • PLY and OBJ file loading
  • Texture mapping
  • Shadow mapping
  • Material structures
  • Quaternion-backed rotations with euler accessors
  • Shader preprocessor system
  • Entity-component system

GameObject Class

The GameObject class represents a single object or entity in a 3D scene. Every GameObject has a Transform component attached to it, to hold position, rotation and scale for the object. Component objects are created and attached to the GameObject, which are then updated during the game loop. When Component objects are attached to the GameObject, they are added to the appropriate system for quick access later (lights are added to LightSystem, etc).

// ------------
// GameObject.h
// ------------

#pragma once

#include "Component.h"
#include "Components/Camera.h"
#include "Transform.h"

#include 

using namespace std;

class GameObject {
public:

  GameObject();

  Transform transform;

  void AddComponent(Component *c);
  void Update(double deltaTime);

private:
  vector components;
};
// --------------
// GameObject.cpp
// --------------

#include "Components/Light.h"
#include "Components/MeshRenderer.h"
#include "GameObject.h"
#include "Systems/LightSystem.h"
#include "Systems/GameObjectSystem.h"
#include "Systems/RenderSystem.h"

GameObject::GameObject() {
  GameObjectSystem::GetInstance().AddGameObject(this);
}

void GameObject::AddComponent(Component *c) {
  components.push_back(c);

  c->transform = &transform;
  
  if (c->componentName() == "MeshRenderer") {
    RenderSystem::GetInstance().AddMeshRenderer((MeshRenderer *)c);
  } else if (c->componentName() == "DirectionalLight") {
    LightSystem::GetInstance().AddDirectionalLight((DirectionalLight *)c);
  } else if (c->componentName() == "PointLight") {
    LightSystem::GetInstance().AddPointLight((PointLight *)c);
  } else if (c->componentName() == "SpotLight") {
    LightSystem::GetInstance().AddSpotLight((SpotLight *)c);
  } else if (c->componentName() == "Camera") {
    RenderSystem::GetInstance().AddCamera((Camera *)c);
  } else {
    printf("Unknown component added");
  }
}

void GameObject::Update(double deltaTime) {
  transform.Update(deltaTime);

  for each (Component *component in components) {
    component->Update(deltaTime);
  }
}

CubeMoverPingPong Class

CubeMoverPingPong is a very simple class which animates the X position of a GameObject over time using the sine function. This demo was created to verify that components are able to access and modify their GameObject's Transform properties, and that the game loop was updating GameObjects' components properly. This demo can be seen in the looping video above.

// -------------------
// CubeMoverPingPong.h
// -------------------

#pragma once

#include "../Engine/Component.h"

class CubeMoverPingPong : public Component {
public:
  std::string componentName() const { return "CubeMoverPingPong"; }
  void Update(double deltaTime) override;
private:
  float angle = 0.0f;
};

// ---------------------
// CubeMoverPingPong.cpp
// ---------------------

#include "CubeMoverPingPong.h"

void CubeMoverPingPong::Update(double deltaTime) {
  angle += 1.0f * deltaTime;
  if (angle >= 360.0f) angle -= 360.0f;
  float pos = Math::Sin(angle) * 10.0f;
  transform->position.x = pos;
}