A dive into the feasability of procedural worlds.
This is the part where we enhance and build upon the discrepancies of 0.1.
I talked earlier about the need for a better Object system, and I did in fact create that.
I started 0.2 by refactoring the way GameObjects manage themselves and created this clever solution:
#pragma once
#include <memory>
#include <string>
#include <type_traits>
class Engine;
class GameObject : public std::enable_shared_from_this<GameObject> {
protected:
GameObject() = default;
GameObject(const char* _name) { name = _name; }
public:
std::string name = "GameObject";
virtual void awake() {};
virtual void start() {};
virtual void render() {};
virtual void update(float dt) {};
virtual void on_object_add() {};
virtual void on_object_remove() {};
virtual ~GameObject() = default;
//Factory
template<typename T, typename... Args>
static std::shared_ptr<T> create(Args&&... args) {
static_assert(std::is_base_of<GameObject, T>::value, "T must be a GameObject");
// Create the object
std::shared_ptr<T> obj = std::make_shared<T>(std::forward<Args>(args)...);
// Register with the Engine
Engine::getInstance()->addObject(obj);
return obj;
}
};
What this essentially does is makes a shared smart pointer of type <T> and adds it to the Engine's instance.
What it also does is implements virtuals to be overriden on certain events.
Another addition was my own input manager that worked in a similar fashion to Unity.
I set out to make class creation for GameObjects streamlined with this new management of GameObjects as well as the Input.
Below is a little example of how simple the code looks compared to the average way you go about this in C++.
class Player : public MeshGameObject {
public:
Player(MeshShape ms) : MeshGameObject(ms) {}
void update(float dt) override {
if (Input::GetButton("Jump"))
{
Move({ 0,1 / 100.f,0 });
}
if (Input::GetButton("Crouch"))
{
Move({ 0,-1 / 100.f,0 });
}
glm::vec2 movement = glm::vec2(Input::GetAxis("Horizontal"), Input::GetAxis("Vertical"));
if (movement != glm::vec2{0.f,0.f})
{
Move({ movement.x / 100.f, 0, movement.y / 100.f });
}
}
void start() override {
Input::MapButton("Jump", GLFW_KEY_SPACE);
Input::MapButton("Crouch", GLFW_KEY_LEFT_CONTROL);
Input::MapButton("GetScene", GLFW_KEY_G);
Input::MapAxis("Horizontal", GLFW_KEY_D, GLFW_KEY_A);
Input::MapAxis("Vertical", GLFW_KEY_W, GLFW_KEY_S);
}
};
This is looking incredibly simple compared to some of the other things you see out there!
Now the only problem with this version was that it never actually ran...
Every component in it worked apart from the rendering itself.
I'm aware of the issue now that the project is over, and I got it working out of shear curiosity, but it just looks the same as the last one.
Which is exactly what it was meant to look like, if I had got it working sooner, I wouldn't have had to switch up the final project last minute.
But alas-