Calamity Engine 1.0.0
A cross-platform 2D game engine written in C++ and SDL3.
Loading...
Searching...
No Matches
Basic Notions

First off, if you're new to C++ maybe don't start out with my engine since I'm assuming that anyone who's reading this has some basic C++ knowledge. You should also probably be familiar with how a game engine like Godot or Unity works.

Generally, any project that's built with this framework should have this general structure:

main.cpp
CMakeLists.txt
scripts/
# scripts go here
assets/
# assets go here

Obviously this isn't 100% required, but I heavily recommend it.

By the way, the main way of navigating Calamity Engine's documentation is checking the documentation for a specific class you want info on. There are also the basic examples which you can find in the examples folder of the Calamity Engine repository or on the Calamity Engine website.

Initializing nodes and components

Preface

I use a library called cereal to serialize & deserialize nodes into/from JSON files or strings. You should probably read it's documentation to familiarize yourself with how it works. However, it should be simple enough.

Cereal does NOT like raw pointers, so, every node and component has to be a shared pointer (std::shared_ptr).

Code

Let's take, for example, initializing the camera:

std::shared_ptr<Node> cameraNode = std::make_shared<Node>(); // make the node
cameraNode->addComponent(std::make_shared<Camera>()); // add the camera component to the node
window->root->addChild(cameraNode); // adding the node as a child to the root node of the engine

Any nodes that you want to be visible on screen have to be a child of the engine's root node.

Scripts and other components

Scripts are genuinely just classes in header files that extend components. Since scripts extend components you get convenient virtual functions such as: initialize, update, physics update and exit.

Since cereal doesn't like it when components don't have save and load functions, scripts have to include them. I decided that's probably the best way to go about it since developers (YOU) get more control over what's saved and what isn't.

Here is an example script for moving the camera using the input system:

// scripts/cameraScript.hpp //
#pragma once
// you HAVE to include these two
#include <cereal/types/polymorphic.hpp>
#include <cereal/archives/json.hpp>
class CameraScript : public Script
{
Node *node;
const int SPEED = 500;
public:
template <class Archive>
void save(Archive &ar) const {}
template <class Archive>
void load(Archive &ar) {}
void initialize()
{
node = this->getNode();
}
void update(float deltaTime) {
// PS, you have to add these actions yourself to the input registry. For more info, look at the input example's main.cpp file.
auto vec = Services::input()->getVector("left", "right", "up", "down");
node->transform.position = node->transform.position + (vec * deltaTime * SPEED);
}
};
// you also have to do this at the bottom of your script file
// otherwise your game won't compile due to cereal
CEREAL_REGISTER_TYPE(CameraScript);
Vector2 getVector(const std::string &minX, const std::string &maxX, const std::string &minY, const std::string &maxY, float deadzone=-1.0f) const
Definition input.cpp:551
Definition node.hpp:31
Transform transform
Definition node.hpp:34
Definition components.hpp:387
virtual void initialize()
Definition components.hpp:390
void save(Archive &ar) const
Definition components.hpp:396
virtual void update(float deltaTime)
Definition components.hpp:389
void load(Archive &ar)
Definition components.hpp:399
static Input * input()
Definition services.cpp:33
CEREAL_REGISTER_TYPE(Label)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Component, Label)
Node * getNode() const
Definition components.cpp:11
Vector2 position
Definition definitions.hpp:260

And for this script to actually work, you have to add it to the camera node (in our case). So let's go back to the code we had earlier and update it to add the example script:

// don't forget to include the script :)
#include "scripts/cameraScript.hpp"
std::shared_ptr<Node> cameraNode = std::make_shared<Node>(); // make the node
cameraNode->addComponent(std::make_shared<Camera>()); // add the camera component to the node
cameraNode->addComponent(std::make_shared<CameraScript>()); // add the script to the camera node
window->root->addChild(cameraNode); // add the node as a child to the root node of the engine