← Back to blog

Zixel: The Miscellaneous Sprint

Sprint 4

Sprint 4 took a little bit of an unexpected detour. I started working on adding some core features to the room system. Notably, transition effects between rooms. After the room transitions were functioning I took a brief detour to add some 2D lighting to the game.
My goal is to start working on The Vendor’s game sometime soon. Without a UI system, that wasn’t going to be possible. Detour #2 for this sprint: a UI system! This turned out to be a lot more work (and fun) than expected. It’s still a work in progress, but I’m pretty happy with the progress so far.

Room Transitions

The Room class is one of the major building blocks for Zixel. Each room is a collection of Object instances. It’s a way to break apart functionality and also keep the code organized. Examples of a room include: - The main menu - The vendor’s shop - The game’s main gameplay room - The game’s end screen

Moving between rooms is a very common operation that requires a nice transition effect. That’s what this feature is for! Moving between rooms is designed to be a simple function call against the room manager.
In the example below, the room manager will transition to the ParticleTestRoom room using a wipe transition effect.

roomMgr.ChangeRoom(
    std::make_shared<ParticleTestRoom>(),
    zixel::TransitionType::Wipe,
    0.6f
);

Demo

2D Lighting

Another random thought that turned into an afternoon of workβ€”simple 2D lighting! This isn’t a full-blown lighting system, but it’s a start. The idea here is that light sources are drawn to an overlay texture that is applied (with a blending shader) to the scene.
Here’s an example of a simple light that we attach to a test game object, “Frank”.

zixel::Light frankLight;
frankLight.position = Vector2{m_pFrank->GetPosition().x, m_pFrank->GetPosition().y};
frankLight.radius = 150.0f;
frankLight.color = Color{255, 220, 180, 255}; // Warm white
frankLight.intensity = 1.2f;
frankLight.falloff = 1.5f;
frankLight.allowCulling = false; // Always render player light
m_frankLightIndex = lighting.AddLight(frankLight);

Demo

Font Scaling (SDF)

Font scaling is an interesting challenge for any UI system. Traditional scaling techniques only work well for monospaced fonts, but SDF fonts are much more flexible. The idea is to render the font to a texture, then scale the texture based on the font size.
I won’t go into the details of how this works, but there’s an expertly written article on the topic here.

Demo

Shader management system

The rabbit hole goes deeper! When working on the SDF shader, I realized that Zixel didn’t have a unified shader management system. Rather than simply adding a shader manager, I wanted to ensure that every Object had the ability to use its own custom shader and not be forced to use a default sprite renderer.
All the shader effects will be added to Zixel to keep the game logic as simple as possible. Using them is as simple as overriding the Object::OnDraw() virtual method. Inside of it, call shaderMgr.EnableEffect(effect); and then invoke the base Object::OnDraw() method.

Demo

UI Theme & Basic Components

FINALLY! After all the precursor work, it’s time to get cracking on a UI system. The Vendor will be very UI heavy. Lots of inventory management, dialog, and other UI elements will be needed. Designing the UI system with Claude, I was able to put together a retained mode UI system for my needs. Base plumbing for the system is in place, including texture support, modals, and controls. Beyond the base work, I’d like to add as much “juice” as possible. Making it very visually engaging.

Demo

GitHub CoPilot Agent gets smart(er)

While doing the UI work, some debugging was necessary to fix issues that came up. My workflow at this point is as follows: - Create a GitHub issues ticket describing the required feature as if it were a product requirements document - Assign the ticket to GitHub CoPilot Agent - CoPilot will automatically create a pull request with the required changes - Pull down the PR branch and test it locally - (optionally) fix any issues locally or tag @copilot in the PR and ask it to address - Iterate until the PR is ready to merge

During the initial implementation of the UI panel component, CoPilot finished the implementation by updating the PR description with…A SCREENSHOT. That’s notable because CoPilot operates in a headless environment within the GitHub Actions CI pipeline. The model figured out a way to capture screenshots and use its multimodal ability to determine if it had completed the task.
Below is the screenshot of my interaction with CoPilot, asking how it obtained the screenshot. copilot-screenshot.png
Needless to say, I’m very impressed with that little bit of functionality. So much so, that it was added to the CoPilot agent definition file that is used for the Zixel repo.

Sprint 5

Next up - I’d like to round out the UI functionality, keeping in mind that it’d be great to stub out some of the shop management functionality for The Vendor.
Additional Controls: - Slider - Checkbox - Dropdown - Tooltips - List - Scrollbar (for lists) - Radio buttons - Image - Tabs

Animations: - In/Out - Easing - Bouncing - Wiggle

Sounds: - Button clicks - Error/Success

Ensuring that the UI system is robust and complete will enable moving on to The Vendor.