Zap Engine

May 24, 2026 - Sebastian Himmer
UniversityProjectsEngine Programming
1422 words 7 min read

Description

Zap is a custom C++ game engine built during the second year at BUas by a team of 7 programmers.

My responsibilities covered the full scripting layer (AngelScript integration via my Seraph library, hot-reloading, reflection, serialization), editor tooling (content browser, undo/redo, spline tooling), Perforce integration, CI/CD, and crash reporting.

Engine Architecture

Zap is split into three build targets: zap-core (engine library), zap-editor (editor executable), and zap-player (shipping runtime). The core uses EnTT for ECS, Jolt for physics, FMOD for audio, and GLM for math. The editor is built entirely in ImGui.

AngelScript is the scripting language, integrated through Seraph - a wrapper library I built during the previous block. All C++ APIs exposed to scripts go through a central ScriptGlue layer that handles type registration, binding, and cross-platform compatibility.

Scripting

AngelScript scripting is the backbone of all gameplay code in Zap. Scripts implement an IComponent interface that exposes lifecycle methods. Properties marked with [Property] appear in the editor inspector and are serialized into scene files. A [Reflect] attribute on data classes enables recursive serialization down to primitive types.

[Reflect] class BoostSettings {
    [Property] float boostMaxDuration = 3.0f;
    [Property] float boostSpeed = 40.0f;
}

class PlayerController : IComponent {
    Entity self;
    void SetSelf(Entity _self) { self = _self; }

    [Property] float moveSpeed = 10.0f;
    [Property] BoostSettings boostSettings;

    void Start() { }
    void Update(float deltaTime) { }
}

Hot-reloading allows script changes to apply in under 100ms without restarting the engine. The system serializes all script state, validates the new code in a temporary engine instance, then reinitializes and deserializes if compilation succeeds.

I also implemented ZapEvent<T>, a generic event dispatcher usable from AngelScript. It was used all over the game code to simplify communication between systems and decouple gameplay logic.

ZapEvent<string> OnMarkerHit;
OnMarkerHit.AddListener(ZapEvent<string>::CallbackType(OnSplineMarkerHit));
OnMarkerHit.Invoke("marker_1");

Editor Tooling

Content Browser

The content browser provides a visual representation of all indexed resources in the project. I designed custom icons in Figma for each resource type and render texture previews directly for image assets. The layout uses a card-style design built in ImGui.

It allows for directory navigation with breadcrumbs, drag-and-drop importing, and double-click actions - scripts open in VSCode with the cursor at the correct file, scenes load into the editor.

Undo/Redo

The undo/redo system uses the command pattern. Every tracked operation is an IAction subclass that captures before/after state and can reverse or reapply itself.

I implemented multiple actions:

  • EntityAction (create/delete)
  • SelectionAction
  • ComponentChangeAction (serializes component state before and after)
  • ParentChangeAction

These were all the actions needed to cover every editor operation, from shortcuts to drag-and-drop.

The main challenge was ImGui's continuous input elements (drag floats, sliders) which fire every frame during interaction. I use ImGui::IsItemActivated() and ImGui::IsItemDeactivatedAfterEdit() to capture only the start and end state:

void Inspector::TrackEdit(const std::string& message)
{
    if (ImGui::IsItemActivated() && !m_pendingAction)
        StartPendingAction();

    if (ImGui::IsItemDeactivatedAfterEdit() && m_pendingAction)
    {
        m_pendingAction->Commit(message);
        m_pendingAction.reset();
    }
}

All editor operations (shortcuts, menus, drag-and-drop) go through a centralized editor_actions.cpp so every code path is tracked.

The undo/redo system is very performant, since actions only serialize the relevant component or entity rather than the entire scene. This allows for near-instant undos even in large scenes with hundreds of entities.

The undo system also drives unsaved change detection. Any committed action (except selection) marks the current scene dirty, triggering a save/discard popup when switching scenes or closing the editor.

Perforce Integration

I built a VersionControl class that wraps the p4 CLI to provide checkout, add, submit, and status queries directly from the editor. The alternative was the official P4 API, but it was too complex to integrate in the available time.

The integration hooks into multiple editor workflows: right-click actions in the content browser, automatic mark for add on resource creation, and warnings when opening scenes checked out by others or saving out-of-date files.

Spline Editor

Our demo game relied on splines for player movement and event timing. I implemented editor tooling for spline creation.

The editor allows selecting and moving segment start/end points and control points. Spline markers (named points at set distances along the spline) can be placed in the editor and listened to from scripts:

array<string>@ markers = spline.EvaluateMarkers(lastDistance, currentDistance);
for (uint i = 0; i < markers.length(); i++) {
    Log::Info(format("Hit {}", markers[i]));
}

CI/CD

When we moved into the production phase for our game, I set up a CI/CD pipeline that allowed us to automatically build and distribute editor and player builds on to the rest of the team. Engine's development continued on GitHub, and I created a workflow that packaged the editor and player and uploaded them to Perforce.

This saved a lot of manual work for the team and assured that we don't make mistakes in the packaging process. Whenever a new build was needed, I just had to merge the latest code and the workflow would take care of the rest.

Closing remarks

I am very grateful for the opportunity to work on this project with other amazing people. It was a huge learning experience and a big insight into how complicated and time-consuming game engine development can be, especially when building tools and pipelines on top of the core engine.