Skip to content

Clockwork Engine

Welcome to the documentation! On this home page, you will find a basic introduction to the structure of Clockwork Engine. From there, you should be able to jump around other pages to find what you need.

Why Clockwork Engine?

The reason Clockwork exists is because most game development tools are missing at least one of these features:

  • Dedicated 2D and 3D modes
  • Immediate-mode drawing
  • Interface-free development
  • Project scaleability

Love2D and Processing come close to this sort of project, but both fall a little short. Love2D uses Lua, which is a very fascinating and fun language, but has trouble with scaleability. Processing uses Java, which I suppose is fine, but the build tools are not designed for shipping projects. Finally, there's the Raylib multimedia library. It has all of the necessary features, but you'll have to program a game engine around it if you want to create a decent project. So Clockwork Engine was created.

Installation

This is the easiest part. In Visual Studio, you have two options: 1. Install the template. 2. Create a new console application and install the NuGet package.

Structure

Clockwork Engine is broken up into layers, like so:

Engine
├─ Raylib
├─ Windowing
└─ Game
    ├─ Update Loop
    ├─ Draw Loop
    ├─ Draw GUI Loop
    └─ Scenes
        └─ Entities

In the following sections, I will explain the layers to their absolute minimum complexity. Check out their documentation pages for more information.

Engine

The "engine" initializes a window, controls the core game loop, and is essentially the entry point for the framework. To get started, initialize an engine with settings and start your game (which you will create in the next step):

Program.cs
Engine.Initialize("My Game", 256, 256); // window title, game width, game height
MyGame myGame = new();
Engine.Start(myGame);

There are also shorthand Start overloads if you don't need a full Game class. You can pass a Scene directly, or even just an IEnumerable<Entity>:

Program.cs
Engine.Initialize("Quick Prototype", 256, 256);
Engine.Start(new MyScene());

P.S. Don't forget to add using Clockwork; to the beginning of your scripts.

Game

The "game" is where your code begins, and you can plug into the update and draw loops generated by Clockwork. Create a class and inherit from Game:

MyGame.cs
internal class MyGame : Game
{
    public MyGame()
    {

    }

    public override void OnUpdate()
    {

    }

    public override void OnDraw()
    {

    }

    public override void OnDrawGUI()
    {

    }
}

OnDrawGUI is optional and is drawn after the main draw loop, unaffected by camera transformations. It's useful for HUD elements and debug overlays.

At this point you could go ahead and start programming your game, but you would miss out on the bulk of the engine's tools. The Scene and Entity classes do a lot of heavy lifting, so stay tuned.

Scenes

A scene is essentially a collection of entities with several features:

  • Layering: Modify entity update and draw order.
  • Registry: High performance look up of entities.
  • Timing: Pausing and timer/animation synchronicity.

Your game class is where scenes will be managed. One scene is great for prototyping. Just create a new scene object and then you can add entities to it with ease.

MyGame.cs
internal class MyGame : Game
{
    private Scene scene = new();

    public MyGame()
    {
        scene.AddEntity(new CustomEntity());
    }

    public override void OnUpdate()
    {
        scene.Update();
    }

    public override void OnDraw()
    {
        scene.Draw();
    }
}

But of course, one scene will not be enough for a full game. At minimum, a main menu and game scene will probably be necessary. This is why you would inherit from Scene:

MenuScene.cs
internal class MenuScene : Scene
{
    public MenuScene()
    {
        AddEntity(new StartButton()); // inherits from Entity
    }
}
GameScene.cs
internal class GameScene : Scene
{
    public GameScene()
    {
        AddEntity(new GameManager()); // inherits from Entity
        for (int enemyIndex = 0; enemyIndex < enemyCount; enemyIndex++)
        {
            AddEntity(new Enemy()); // inherits from Entity
        }
    }
}

Custom scenes are useful for initializing a scene state. However, they do not have public update and draw loops. Those are managed internally for handling entities inside a scene.

It may alternatively be convenient for scenes to have their own public facing loops, but ultimately it was decided that managers (inheriting from Entity) would make more sense.

So, now your game class may look like this:

MyGame.cs
internal class MyGame : Game
{
    private Scene activeScene;

    public MyGame()
    {
        activeScene = new MenuScene();
    }

    public override void OnUpdate()
    {
        activeScene.Update();
    }

    public override void OnDraw()
    {
        activeScene.Draw();
    }

    public void StartGame() // called from elsewhere, such as a UI entity in MenuScene
    {
        activeScene = new GameScene();
    }
}

Multiple scenes can also be run at once, drawing over each other. This is useful for pause menus.

Entities

Entities are game objects, actors, or nodes. It doesn't matter what you call them. Clockwork knows them as entities. An entity could be a hero or an enemy. A manager or a utility. In fact, several of the engine's tools such as ParticleEngine2D and Easer inherit from the Entity class. Entity scripts are where most of your game's logic will happen.

Here's an example of an entity that is simply a polygon:

Polygon.cs
public class Polygon : Entity
{
    public Transform2D Transform = new();
    public int SideCount;
    public float Radius;
    public Color Color;

    public Polygon(float radius, int sideCount, Color color)
    {
        Radius = radius;
        SideCount = sideCount;
        Color = color;
    }

    public override void OnDraw()
    {
        Primitives2D.DrawPolygon(Transform.WorldPosition, SideCount, Radius, Transform.WorldRotation, Color);
    }
}

Bindings

You may be wondering how to render sprites or play audio. That's where the bindings come in. Clockwork is built on top of the Raylib multimedia library, which handles textures, audio, input, and much more. It is also written in C. So, in order to communicate with Raylib, Clockwork contains hundreds of bindings that speak to the C code. You saw one binding in the previous example:

Primitives2D.DrawPolygon(Transform.WorldPosition, SideCount, Radius, Transform.WorldRotation, Color);

Here's another example:

Sound explosionSound = Sound.Load("explosion.wav");
explosionSound.Play();

All of these bindings are nested into their own namespaces as well. For instance, for drawing 2D primitives like polygons, you would need to import the Graphics namespace:

using Clockwork.Graphics;
using Clockwork.Graphics.Draw2D;

Similarly, for audio:

using Clockwork.Audio;

If you are familiar with Raylib, you will notice the bindings have been tweaked a good bit. They were modified to align with modern C# standards. You may have to go digging around a bit to find Clockwork's Raylib equivalents.

Learn More

Congratulations! You're an expert. That covers the basics. From here I would recommend checking out the examples and reading the source code when documentation isn't sufficient. The source is well organized, and you should be able to find your way around.

Thanks for trying out Clockwork! Have fun!