Skip to content

First GameObject

This page walks you through creating your first moving, visible game object from scratch in WolfEngine.

If you want a quick overview of the folder layout, main.cpp, and the startup sequence before diving into code, see Engine Basics.


The Basics

Every game entity in WolfEngine is a GameObject. You create one by inheriting from it and overriding Start() and Update():

#include "WolfEngine/WolfEngine.hpp"
class MyObject : public GameObject {
public:
    void Start() override {
        // called once when the object is created
        transform.position = { 64, 64 };
    }
    void Update() override {
        // called every frame
    }
};

Then create it in app_main() before StartGame():

Engine().StartEngine();
GameObject::Create<MyObject>();
Engine().StartGame();

That's it — the engine handles the rest.

Tip: Refer to GameObject to better understand how GameObjects work.

Tip: Refer to Engine to better understand engine initialization.


Adding Movement

Get a controller reference in Start() and read input in Update():

class MyObject : public GameObject {
public:
    Controller* controller = nullptr;

    void Start() override {
        controller = Input().getController(0); // player 1
    }

    void Update() override {
        if (!controller) return;
        if (controller->getButton<Button::A>()) transform.position.x += 1;
        if (controller->getButton<Button::B>()) transform.position.x -= 1;
        if (controller->getButton<Button::C>()) transform.position.y -= 1;
        if (controller->getButton<Button::D>()) transform.position.y += 1;
    }
};

Or use the joystick for analog movement:

void Update() override {
    if (!controller) return;
    transform.position.x += controller->getAxis(JoyAxis::X) * 2.0f;
    transform.position.y += controller->getAxis(JoyAxis::Y) * 2.0f;
}

Tip: Refer to Input to better understand how input handling works.


Adding a Sprite

First define pixel data and create a Sprite asset in flash, then attach a SpriteRenderer component. If you are using the asset pipeline, you can skip the manual pixel array and include the generated GeneratedAssets/WE_Assets.hpp header instead.

Sprite pixel arrays use [H][W] shape (rows × columns). W and H can be different, and each must be in 1..96.

Pixel data must be declared as a separate constexpr array — inline initializer lists are not supported.

#include "WolfEngine/WolfEngine.hpp"

constexpr uint8_t myPixels[7][7] = {
    {0, 0, 1, 1, 1, 0, 0},
    {0, 1, 1, 1, 1, 1, 0},
    {0, 1, 2, 1, 2, 1, 0},
    {0, 1, 1, 1, 1, 1, 0},
    {0, 1, 2, 1, 2, 1, 0},
    {0, 1, 1, 2, 1, 1, 0},
    {0, 0, 1, 1, 1, 0, 0},
};
constexpr Sprite MY_SPRITE = Sprite::Create(myPixels, PALETTE_WARM);

class MyObject : public GameObject {
public:
    SpriteRenderer spriteRenderer = SpriteRenderer(this, &MY_SPRITE, RenderLayer::Player);
    Controller* controller = nullptr;

    void Start() override {
        transform.position = { 64, 64 };
        controller = Input().getController(0);
    }

    void Update() override {
        if (!controller) return;
        if (controller->getButton<Button::A>()) transform.position.x += 1;
        if (controller->getButton<Button::B>()) transform.position.x -= 1;
    }
};

The sprite anchor draws at transform.position every frame automatically. By default this anchor is centered (W/2, H/2).

0 in pixel data is always transparent. Indices 1–31 map to palette colors. Generated sprites follow the same rule, so the Assets namespace produced by the converter is drop-in compatible with manual Sprite::Create() usage.

Tip: Refer to Sprite Renderer to better understand how sprites work.


Full Example — A Moving Player

#include "WolfEngine/WolfEngine.hpp"

constexpr uint8_t playerPixels[7][7] = {
    {0, 0, 1, 1, 1, 0, 0},
    {0, 1, 1, 1, 1, 1, 0},
    {0, 1, 2, 1, 2, 1, 0},
    {0, 1, 1, 1, 1, 1, 0},
    {0, 1, 2, 1, 2, 1, 0},
    {0, 1, 1, 2, 1, 1, 0},
    {0, 0, 1, 1, 1, 0, 0},
};
constexpr Sprite SPRITE_PLAYER = Sprite::Create(playerPixels, PALETTE_GRAYSCALE);

class Player : public GameObject {
public:
    SpriteRenderer spriteRenderer = SpriteRenderer(this, &SPRITE_PLAYER, RenderLayer::Player);
    Controller* controller = nullptr;

    void Start() override {
        transform.position = { 64, 64 };
        controller = Input().getController(0);
    }

    void Update() override {
        if (!controller) return;
        float speed = 2.0f;
        transform.position.x += controller->getAxis(JoyAxis::X) * speed;
        transform.position.y += controller->getAxis(JoyAxis::Y) * speed;
    }
};

extern "C" void app_main() {
    Engine().StartEngine();
    GameObject::Create<Player>();
    Engine().StartGame();
}

What's Next

⏊ Engine Settings Configure frame rate, background color, and UI region
📌 Pin Setup Set up your GPIO and SPI wiring
đŸ›°ī¸ About GameObjects Learn everything about GameObjects
🎮 Inputs! How to get inputs from the controllers?
🚗 Your First Game Object! Learn how to create and move objects
🎨 How To Set Up Graphics? Get graphics on screen
🔉 How to pew pew? Make the buzzer go brr