Game of Ur 0.3.3
This is a computer adaptation of Game of Ur, written in C++ mainly using SDL and OpenGL.
|
The ToyMaker::SceneSystem is responsible for maintaining and exposing the currently active scene. It does so by holding a reference to a scene tree.
The scene tree is made up of scene nodes derived from ToyMaker::SceneNodeCore. Each node is a wrapper over an ToyMaker::Entity. This entity is guaranteed to have at least 3 components:
Additional components added to the entity, along with that entity's system configuration, determine its participation in any particular ToyMaker::System defined for this project.
The hierarchical organization of the nodes is left up to the developers of an application. While scene nodes anywhere may be organized into a tree, only nodes attached to ToyMaker::SceneSystem's scene tree will be considered active and receive inputs and application updates.
The root node of the ToyMaker::SceneSystem's scene tree is a ToyMaker::ViewportNode, configurable via the "root_viewport_render_configuration"
property of the application's project.json
file.
The application's project.json
also contains a "root_scene_path"
property, pointing to the scene file loaded as the first scene in the application.
The scene system is to a game or application what the DOM tree is to a browser, or what a directory tree is to an OS' filesystem. It allows its users to logically group objects together per the requirements of the application.
Scene nodes connected by a child-parent relationship also have a spatial relationship with each other. The child's ToyMaker::Placement component specifies, by default, the child's placement relative to its parent's position, scale, and orientation, in the world.
This can be useful in a number of different scenarios: player character (parent) holding one swappable weapon (child), moving train (parent) carrying passengers (children), UI box (parent) containing UI text (child), and so on.
The enablement of the root node of a subtree also determines whether its descendants are active. A dialog box, for example, can be displayed or hidden simply by enabling or disabling its root node.
In ToyMaker, a scene file is a JSON file adhering to a specific structure. The scene file is divided into 3 sections: "resources"
, "nodes"
, and "connections"
This is a list of resources. It is an array mapped to the scene file's root object's "resources"
property.
Each resource is an object necessarily containing the name of the resource, the type of resource it is, its resource constructor (called method), and the parameters the method uses.
Resources defined by an application at an earlier point may be used in scenes that are loaded at a later point. The newly loaded scene needn't redefine the resource, and may proceed as though the resource definition is already present in the database.
Note, however, it is not permitted to define the same resource twice – each resource can be defined only once. It is up to the developer to ensure that when a scene loaded later in an application requires the same resource as a scene loaded earlier, that the resource definition is only present in the scene loaded earlier.
See classes derived from ToyMaker::ResourceConstructor for the parameters required by different resources and their constructors.
This is a list of nodes in the present scene. It is an array mapped to the scene file's root object's "nodes"
property. Like "resources"
, each node is also a JSON object in an array.
There are three types of nodes currently defined: SceneNode, SimObject, and ViewportNode. The root node of every scene file must be a ToyMaker::SimObject; every other node may be any one of the defined node types.
The root node must also have an empty string ""
as the value of its "parent"
property. Every other node must have a non-empty "parent"
property, where "/"
corresponds to the root node of this scene file, and where the parent path corresponds to a node defined earlier in this section.
ToyMaker::SceneNode is the most basic type of scene node, comprised of nothing more than its names and ToyMaker::ECSWorld components. It has the following appearance in a scene file:
The ToyMaker::SimObject is a type of scene node designed to provide a object-oriented and component-centric interface for application developers. Like a regular scene node, it also has a name and ToyMaker::ECSWorld components, but has an additional "aspects"
property.
A ToyMaker::SimObjectAspect is the base class of aspects used by ToyMaker::SimSystem. Aspects encapsulate both data and behaviour related to the object they are attached to. They play a similar role in ToyMaker that MonoBehaviours play in unity, or scripts in Godot, by providing a simple interface into scene node lifecycle events, application loop events, and the engine's signal and input systems.
As noted earlier, the root node of any scene file must be a SimObject. The appearance of a SimObject in a scene file is given below:
See classes derived from ToyMaker::SimObjectAspect for details on parameters required by specific aspects.
SimObjects have one more special feature in a scene file.
Since the root node of a scene file is always guaranteed to be a SimObject, when one scene is imported into another scene, the import*ing* scene may specify overrides for the name, components, and aspects, of the import*ed* scene's root node, like so:
A ToyMaker::ViewportNode is one of the main interfaces between the developer and the ToyMaker::RenderSystem. It is used to control the frequency of rendering updates to the target texture owned by this node, as well as the dimensions of that texture.
According to its configuration, it may also mark the boundary between the part of the scene tree corresponding to its parent viewport's ToyMaker::ECSWorld, and its own ECSWorld.
An example of where these properties are useful is if a game wants its UI to be rendered at the platform's native resolution, while rendering its 3D game world at a lower resolution. The parent viewport and the UI viewport can have their render textures set to the size of the application window in native pixel dimensions. The game world viewport has its resolution scaled down. The parent viewport produces the final window texture by combining the results from the UI viewport and the game world viewport.
This also ensures that nodes in the UI world aren't affected by the systems active in the game world, and vice versa.
The appearance of the viewport node in a scene file is given below:
The root viewport of the ToyMaker::SceneSystem is also a viewport node, retrievable using ToyMaker::SceneSystem::getRootViewport().
ToyMaker::SimObjectAspect, which is the engine's scripting interface, supports signals. Any aspect subclass may declare its own signal or signal observer like so:
Then, in the "connections"
section of the scene file, use this to connect a signal from one node aspect to another:
... where all paths are relative to the current scene file's root node. Signals and observers from other scene files, provided they've been added to this scene's tree, may also be referenced.