A lightweight 2D game engine written in C++, built on top of OpenGL. Designed for simplicity — create windows, render shapes and text, play audio, build UIs, handle input, and compose game objects with a clean component system.
✨ Features
- Component-based GameObject system — Attach and detach components (
Transform, QuadRendererComponent, TextRendererComponent, and custom ones) at runtime
- Built-in UI objects —
Label, Button, InputField and Panel game objects with click/return event handlers, placeholders and styling
- Camera — Movable
Camera object; attach custom components to control panning and view
- 2D Rendering — Render colored/textured quads, triangles and text out of the box
- Audio playback — Load and control sounds via the
AudioManager (play, pause, stop, seek, volume, looping) powered by miniaudio
- Collision detection — Rectangle overlap (SAT, rotation/scale aware) and point-in-rect checks
- Input handling — Keyboard (
getKey, getKeyDown, getKeyUp) and mouse events (click, release, move, scroll, enter)
- FPS & delta time —
getFPS(), getInstantFPS(), getDeltaTime() on the Window object
- Shader system — Load and manage GLSL shaders with minimal boilerplate
- Texture loading — Load PNG/JPEG images via
stb_image
- Simple app abstraction — Subclass
CangineApp and override onFirstFrame() / onFrame(dt) for a clean game loop, with instantiateObject<T>() for spawning objects
📦 Dependencies
| Library | Purpose |
| GLFW | Window creation & input |
| GLAD | OpenGL function loader |
| FreeType | Font rendering |
| stb_image | Texture/image loading |
| miniaudio | Audio playback |
| zlib | Compression (FreeType dependency) |
All dependencies are bundled under cangine/external/.
🔧 Building
Requirements
- CMake ≥ 3.10
- A C++17-compatible compiler (GCC, Clang, or MSVC)
Build the engine
Build in debug mode
Build and run an example
make example EXAMPLE=simplehelloworld
make example EXAMPLE=ui
make example EXAMPLE=audio
make example EXAMPLE=sandbox
Debug an example
make exampled EXAMPLE=sandbox
Clean build files
Makefile variables
| Variable | Default | Description |
EXAMPLE | sandbox | Example to build/run |
BUILDDIR | build | CMake output directory |
BUILDEXAMPLES | OFF | Build example projects |
EXPORTCOMPILECOMMANDS | ON | Export compile_commands.json |
🚀 Quick Start
Install dependencies
sudo apt install libglfw3-dev libfreetype-dev libepoxy-dev libfontconfig-dev
Clone and build
git clone https://github.com/huseyinhealth/cangine.git
cd cangine
make engine
The simplest way to use cangine is to subclass CangineApp and spawn objects with instantiateObject<T>():
public:
void onFirstFrame() override {
Label* hello = instantiateObject<Label>(
"Hello, world!");
}
void onFrame(double dt) override {
}
};
int main() {
MyApp().run();
return 0;
}
Public entry point for the cangine engine.
Base application class that owns the window and main loop.
Definition cangine.hpp:43
Convenience game object that displays a line of text.
Definition label_object.hpp:23
Vector2 getSize()
Returns the rendered size of the text.
Definition label_object.cpp:14
Definition audiomanager.cpp:4
Three-component floating-point vector.
Definition vector3.hpp:13
🧩 Architecture
cangine/
├── engine/
│ ├── GameObject # Base entity — holds a list of IComponents
│ ├── ObjectManager # Manages all active GameObjects
│ ├── components/
│ │ ├── IComponent # Base class for all components
│ │ ├── Transform # Position, rotation, scale (+ posFor helper)
│ │ ├── CameraComponent # View/camera transform
│ │ ├── QuadRendererComponent # Renders a colored/textured rectangle
│ │ ├── TextRendererComponent # Renders a string with FreeType
│ │ └── ui/
│ │ ├── ButtonComponent
│ │ ├── InputFieldComponent
│ │ └── PanelComponent
│ └── gameobjects/
│ ├── CameraObject # Camera entity (auto-attaches CameraComponent)
│ └── ui/
│ ├── Label # Text label object
│ ├── Button # Clickable button object
│ ├── InputField # Text input object
│ └── Panel # Container/background panel object
├── audio/
│ ├── AudioManager # Loads and controls sound playback (miniaudio)
│ └── Sound # Sound source description (path, name, volume)
├── platform/
│ ├── Window # GLFW window wrapper, frame loop, FPS
│ ├── Input # Static keyboard query (getKey / getKeyDown / getKeyUp)
│ ├── Key # Key enum
│ └── Mouse # Mouse event types and data
├── render/
│ ├── Shader # GLSL shader loader/linker
│ ├── Texture # stb_image texture wrapper
│ ├── VAO / VBO / EBO # OpenGL buffer object wrappers
│ └── renderer/
│ ├── RenderSystem # Top-level renderer, drives quad/text/primitive rendering
│ ├── QuadRenderer # Batches and draws textured quads
│ ├── TextRenderer # Draws glyphs via FreeType
│ └── PrimitiveRenderer # Draws untextured primitives
├── shapes/
│ ├── Rectangle # Shape + overlap / containsPoint helpers
│ ├── Triangle # Triangle shape definition
│ └── Vertex # Vertex struct (position, color, UV)
├── types/
│ ├── Vector2 / Vector3 # Math types
│ └── Dimensions # Width/height helper
└── util/
├── Color # RGBA color (0–255 inputs, normalized internally)
└── Position # Screen-to-clip-space normalization helpers
🎨 Core API Reference
CangineApp
void onFirstFrame() override { }
void onFrame(double dt) override { }
};
GameObject* obj = instantiateObject<GameObject>();
Label* lbl = instantiateObject<Label>(
"text");
audioMan->add("./music.mp3", "music");
audioMan->play("music", true);
Base class for everything that lives in the scene.
Definition game_object.hpp:20
Color
Color semiTransparent(0, 128, 255, 0.5f);
Colors::BLACK, Colors::WHITE, Colors::GRAY, Colors::DARK_GRAY,
Colors::RED, Colors::GREEN, Colors::BLUE
RGBA color stored as normalized floating-point components.
Definition color.hpp:12
Transform
Transform::posFor(gameObject,
Vector3(x, y, z));
Layering: the Z component acts as a layer. A Z index of 80 and above is treated as the UI layer (rendered on top of world objects).
UI objects
Label* lbl = instantiateObject<Label>(
"Score: 0");
Button* btn = instantiateObject<Button>(
"Click me!");
});
InputField* field = instantiateObject<InputField>();
});
void setText(std::string text)
Sets the displayed text.
Definition label_object.cpp:22
void setColor(Color colorIn)
Sets the text color.
Definition label_object.cpp:30
A mouse event carrying its type, button, position and scroll offset.
Definition mouse.hpp:37
Two-component floating-point vector.
Definition vector2.hpp:13
QuadRendererComponent
qrc->setRectHeight(64);
qrc->setRectColor(Colors::WHITE);
qrc->setTexture(tex);
Component that draws its game object as a textured rectangle.
Definition quadrenderer_component.hpp:22
virtual void setRectWidth(int widthIn)
Sets the rectangle width.
Definition quadrenderer_component.cpp:26
Wraps an OpenGL texture object.
Definition texture.hpp:12
TextRendererComponent
trc->color = Colors::GREEN;
trc->backgroundColor =
Color(0, 0, 0, 0.5f);
Component that renders a text string, optionally over a background.
Definition textrenderer_component.hpp:18
std::string text
The string to render.
Definition textrenderer_component.hpp:31
Camera
Game object representing the scene camera.
Definition camera_object.hpp:11
void appendComponent(T *component)
Attaches an existing component to this object.
Definition game_object.hpp:58
Audio
audioMan->add("./sound.mp3", "sfx");
audioMan->play("sfx", false);
audioMan->pause("sfx");
audioMan->resume("sfx");
audioMan->stop("sfx");
audioMan->setVolume("sfx", 0.5f);
audioMan->seek("sfx", 10.0f);
float pos = audioMan->getPosition("sfx");
float dur = audioMan->getDuration("sfx");
bool playing = audioMan->isPlaying("sfx");
Input
if (Input::getKey(Key::A)) { ... }
if (Input::getKeyDown(Key::Space)) { ... }
if (Input::getKeyUp(Key::Escape)) { ... }
Mouse events
Override onMouseEvent in a custom IComponent:
if (e->
event == MouseEventType::MouseClick &&
e->
button == MouseButton::Right) {
}
}
MouseEventType event
The kind of event.
Definition mouse.hpp:38
MouseButton button
Button involved; only meaningful for click/release events.
Definition mouse.hpp:39
Rectangle collision
bool hit = Rectangle::containsPoint(rect, transform, mousePos);
bool colliding = Rectangle::overlaps(rectA, transformA, rectB, transformB);
📁 Project Structure
cangine/
├── cangine/ # Engine library source
│ ├── src/
│ ├── external/ # Bundled third-party libraries
│ ├── shaders/ # default.vert / default.frag
│ └── test/
├── examples/
│ ├── simplehelloworld/ # Minimal CangineApp subclass example
│ ├── helloworld/ # Manual engine setup example
│ ├── ui/ # Buttons and labels
│ ├── inputfield/ # Text input + submit handling
│ ├── panel/ # Panel/container UI
│ ├── audio/ # Audio playback controls
│ ├── camera/ # Draggable camera
│ ├── aimtrainer/ # Aim trainer mini-game
│ ├── survival/ # Survival mini-game
│ └── sandbox/ # Full-featured test/demo scene
├── CMakeLists.txt
└── Makefile # Convenience wrapper around CMake
📄 License
See LICENSE.txt for details.