XMLGameEngine

An engine for describing games built around Xerces, exprtk, and SFML.

View the Project on GitHub beefviper/XMLGameEngine

07. Object variables and references between objects

Status: per-object numeric variables and owner.variable text binding implemented (polling); a general Value type and handle-based references are planned

What is needed

Some state belongs to the entity itself, and some state has to be read by another entity:

Decision

The author’s design for the XML: describe the relationship, not the mechanism.

<object name="paddle1"> ... <variables><variable name="score">0</variable></variables> </object>
<object name="score1">  ... <sprite><text><number>paddle1.score</number> ... </text></sprite> </object>

The XML author says the paddle has a score and the scoreboard shows it. Underneath, the engine polls.

Options considered

Option Notes
Polling The reader looks the value up whenever it needs it (each frame it draws). Simple; composes with a declarative file (each frame, read this variable and draw it). One lookup per access.
Listeners / notifiers The owner pushes changes to subscribers. Better when values change rarely and many things react; but the owner can then hold a stale reference to a destroyed subscriber, so cleanup is needed at both ends, and “subscribe” wiring does not look declarative.
Copying the value Goes stale. Rejected.
Raw pointers to the other entity Dangle when storage moves or the entity is removed. Rejected in favor of handles (08).

Chosen: polling, with references resolved to something stable once at load.

Current implementation

An object’s own size in expressions

Centering a text needs its width, which only exists after a backend has measured the font. Before this, the games hand-tuned offsets for each text (window.width.center - 350), which broke whenever the wording, size or font changed.

Built: objectName.width and objectName.height are available in expressions (meant for <position>), and an object refers to itself by its own name like any other field, so a text called title is centered with window.width.center - title.width / 2. (An earlier draft used self.width; dropped because ordinary users would just write the name.) An object’s own <variable> named width/height wins over the size. A circle’s or rectangle’s size follows from its sprite, so its position is exact at load. A text’s or image’s position is marked unknown (printGame says so) until the window has measured it, then worked out, and worked out again whenever its size changes (Game::resolveSizeDependentPositions, run once after Window::init() and each frame). The program prints the game before and after Engine so both states are visible.

Known wart, shadowing: width and height are ordinary variable names, so an object’s own <variable name="width"> shadows its measured size, and the size becomes unreachable from expressions. Precedence (variable wins) keeps existing games working, but it is a collision by design. Alternative spellings that could not collide, none built: a reserved suffix or prefix for built-ins (title.size.width, title.@width, title.$width); a separate namespace (size(title).x, title.size.x); rejecting a <variable> named width/height on objects whose size is measurable, so the clash is an error rather than silent shadowing; or a warning at load time when shadowing happens. Worth deciding before games in the wild depend on the current spelling.

Placing one object by another’s size works the same way (title.width + 10). Other ways it could be spelled, none built: an alignment attribute on the object instead of arithmetic (align="center", an origin at the center); a per-axis anchor. Limits of what is built: a position is only recomputed when the size of an object it names changes, and name.width/name.height read 0 in an expression evaluated before a backend exists (velocity, variables) for text and images.

Planned

Second batch: alternatives

The polling design has a listed alternative that the second batch argued for.

Sources