How a game is loaded and played, the libraries behind it, how to build it, and where each part of the code lives.
- Parse and validate (
load/xml). If the file names a schema it is validated: Xerces fully ("strong"); the other XML libraries with a small built-in validator for the XSD the schema uses ("weak",load/xsd). - Work out the kit and every
from=on the XML (load/merge). - Read the tags into a
GameData(game/data.h), a group as one raw object per member. A generated program starts here, with itsGameDatacompiled in. - Lay out states and scenes (
layOutScenes,game/scenes.cpp): owned objects named by path, every name written out in full. - Evaluate (
load/expr,load/calc): every value worked out (<random>drawn), objects, states and sounds built, every name checked. Nothing needs a window yet. - Open the window and sound (
Engine): sounds made into samples, sizes measured, size-dependent positions finished, the first state pushed. If sound will not start the game plays silently, with a warning.
Engine::step reads the keys (or the demo's, or the computer's) and runs the current state's bindings for each press and release, then its on="hold" bindings. Then playOneFrame (play/frame.cpp):
- animations and blinking count;
- timers count, and those due run;
- paths set their followers' velocities; maze walkers choose; held moves on cells step;
- climbing, grip, acceleration, held thrust, turns and swings, pulls and seeking, altitudes;
- screen-edge rules for what is moving;
- the move: hops are made, carried things lent their carrier's motion, everything moves (a swing turns through it), and each touch found on the way runs its rules;
- sticks hold, carried things are placed, tethers and shadows follow, light and dark worked out, poses picked;
- conditions: the state's, then its current scene's;
- copies made join, despawned ones go.
Then the sounds asked for play, loops start or stop, and the frame is drawn: what a <show state> shows still, then what is in play, except objects not <drawn>.
An object is in play when it is not out of play (<active>false</active>, dead, despawned) and belongs to the current state, its current scene, or the game, or is shown by the state. Movement is pixels per frame and timers count frames; there is no time step.
| Job | Interface | Libraries |
|---|---|---|
| Read XML | XmlDocument / XmlNode (xml/document.h) |
Xerces (default), TinyXML2, PugiXML, RapidXML |
| Window, drawing, keys, mouse, pads | Window (window/window.h) |
SFML 3 (default), raylib, SDL2, OpenGL (GLFW); xgegui's Qt renderer |
| Sound | Audio (audio/audio.h) |
SFML 3 (default), raylib, SDL2, none |
GameandEnginesee only the interfaces. One factory per kind (XmlDocumentFactory,WindowFactory,AudioFactory) knows every library.- A build has some, not all: SFML 3 and Xerces by default;
-DXGE_WITH_<NAME>=ONadds one,-DXGE_ALL_BACKENDS=ONor-DBUILD_TESTING=ONall. A library's code compiles only behindXGE_WITH_<NAME>. Each factory says what it has (available(),availableBackends(),defaultBackend(),name());create()of one not built throws, naming those that are. - Pictures are drawn by the engine, so a window library only shows a bitmap; only text and image files are its own.
- Sound is made by the engine (
synthesize(),audio/sound.h), so it is the same whichever library plays it.Gamenever makes a noise:<play>asks, andEnginehands the frame's sounds to itsAudio. Window and sound libraries are chosen apart; any goes with any. Engine::replaceWindow()swaps the window of a running game (the old destroyed first),Engine::replaceAudio()the sound,Engine::silence()stops what plays,Engine::pump()keeps a paused window responsive.
cmake -B build # SFML 3 and Xerces
cmake --build build --parallel
output/Debug/xgecli frogger
cmake -B build -DBUILD_TESTING=ON # every backend, and the tests
output/Debug/xgetest # Catch2 filters work: "[kaboom]"
cmake --build build --target xgetest-generated && output/Debug/xgetest-generated
| Target | What |
|---|---|
xgelib |
the engine (xge/lib/), static by default (-DXGE_BUILD_SHARED=ON for shared) |
xgecli, xgegui |
the programs (xge/cli/, xge/gui/; the second only when Qt 6 is found) |
xgetest, xgetest-generated |
the tests; the second generates every game and is never in an ordinary build |
xgedata |
copies games/ beside the programs |
- Output. Everything to run lands in
output/<Config>/: the programs, a copy ofgames/with the schema, and the libraries inlibraries/(found through a manifest on Windows, a relative run path elsewhere). The folder can be copied anywhere. - Dependencies are found through vcpkg or the system, or fetched and built (
FORCE_LOCAL_<NAME>forces a fetch). Qt 6 and libxslt are only found, never fetched. CMake modules are inscripts/cmake/. - Warnings stay at zero under a strict set on GCC, Clang and MSVC (
xge_warnings(),platform.cmake).
Design: build-and-layout.
| Part | Files | What |
|---|---|---|
| reading | load/xml.cpp |
tags into a GameData (readGame()) |
load/merge.cpp |
the kit and from= on the XML (layOut, addWaiting), as merge.xsl does |
|
load/expr.cpp |
values, <formula>, building Objects and States, pictures (buildPicture) |
|
load/calc.cpp |
arithmetic in text, compiled once into steps | |
load/check.cpp |
load-time checks of names, and where commands may go (ruleFor) |
|
load/xsd.cpp, load/spelling.cpp |
the weak validator; "did you mean" (didYouMean, listOf) |
|
| the game | game/game.cpp |
the interpreter: objects, the state stack, scenes, conditions, resets, paths, spawns, the answers to FrameRules |
game/scenes.cpp |
layOutScenes, states from= others |
|
game/command.cpp |
raw command tags into typed Commands; operationShape |
|
game/object.*, game/states.*, game/data.h, game/random.cpp |
the data model; the one random source | |
game/cells.cpp, game/cards.cpp, game/think.cpp |
maps of cells and board games; cards; the board-game search | |
| the frame | play/frame.cpp |
playOneFrame: the order of a frame and the moving |
play/geometry.cpp, play/collision.cpp |
touching (box, circle, swept, pixel walk, contactOf) and the verbs' arithmetic |
|
play/verbs.cpp, play/executor.cpp |
what a verb does; which verb and on what | |
play/maze.cpp |
walking a map's tiles | |
| pictures | picture/bitmap.cpp, svg.cpp, font.cpp, color.cpp |
pixels, flips and turns; SVG with lunasvg; fonts and the 8x8 fallback; colour names |
| loop and libraries | engine/engine.cpp, backends.cpp, keys.cpp, folder.cpp |
the loop (loop(), or step() and render()), choosing libraries, key names, the games folder and findSchema |
window/*, audio/*, xml/* |
each kind's interface and factory, a file per library; audio/sound.cpp is the synthesizer |
|
| programs | xge/cli/source/ |
cli.cpp (options, finding the game), generate.cpp (--generate), main.cpp |
xge/gui/source/ |
main_window, game_session, game_stage, game_view, qt_window, key_queue, options_dialog, session_options, app_settings (xgegui.ini), inspector, theme |
|
| generator | games/generators/windows-cpp/ |
generate.xsl, merge.xsl, data.xsl, program.xsl, text.xsl, engine.xml, modules/game_parts.h |
| tests | xge/tests/ |
one test_<topic>.cpp per area and per game (played frame by frame). played.h is shared, invaders_fixture.h a frozen Space Invaders, scratch.h a scratch name per run. xgetest "[.speed]" prints load and frame times |