System Overview - PathogenDavid/Periodic GitHub Wiki
The main app architecture of the Periodic project can be distilled into four parts:
- Sifteo Cube Management
- Element Cube
- Element Core
- Reaction Processing
Architecture
Sifteo Cube Management (main.cpp - PeriodicCore above)
This portion of the app is responsible for listening to Sifteo SDK events and dispatching them to the reaction processing system. It also wrangles the ElementCube
s and triggers their rendering.
Its most important role is that it figures out what elements are involved in a reaction, and creates a Reaction
instance for processing.
Element Cube (ElementCube)
An ElementCube
wraps an instance of Element
primarily to provide rendering facilities for that Element
and to associate it with a specific Cube
. It also provides some utility methods for managing the state of the element on the cube.
Element Core (Element)
An Element
is primarily responsible for handling the database of available elements on the periodic table. It is also responsible for maintaining Bond
information with other Element
s and mutating its own state to a specific Reaction
, Compound
pair. Additionally, Element
contains many utility functions for getting information about Element
s it has bonds with.
Reaction Processing (Reaction, Element, Compound, Bond, BondSolution)
By far the most complex portion of the Periodic system is the reaction processing.
Following is a short list of important associations in the reaction processing system.
- Every
Element
is involved in exactly oneReaction
at most, allElement
s in aReaction
are connected (perhaps indirectly) by aBond
. - Each
Element
has up to fourBond
s with otherElement
s. EachBond
may have manyBondSolution
s associated between it and aCompound
. - A
Compound
is a potential result of aReaction
. EachReaction
may contain manyCompound
s. TheReaction.Process
method determines whichCompound
will be displayed to the user, thisCompound
will become thecurrentCompound
for eachElement
it is associated with and thatCompound
is what will be used to mutate theElement
s inElement.ApplyCompound
.
Flow of events
Follows is a rough overview of the flow of control, starting in PeriodicCore.ProcessNeighborhood
:
- A
Reaction
is created with a singleElement
in it, representing the rootElement
. - All neighbors of that
Element
are added to theReaction
viaElement.AddBond
. - Perform 2 recursively for each of those newly added neighbor
Element
s until no more new cubes can be added. - Call
Reaction.Process
to process the reaction. - Process the
Element
s in thisReaction
to see if they might form aCompound
. If we find a (potential)Compound
, we create a new one and set all the relevant bond information for thatCompound
in eachElement
involved in theCompound
. - Determine the ideal
Compound
to be displayed to the user. (Right now, this algorithm is "Prefer theCompound
with the most elements that doesn't contain potential bonds.") - Apply that
Compound
to relevantElement
s viaCompound.Apply
, which invokesElement.ApplyCompound
.
Details of potential reaction processing
Please refer to the reaction possibility engine page for details on how it works.
General Notes
Static Allocation
Since by default, the Sifteo SDK doesn't have any facilities for dynamic memory allocation, everything needed by the app is allocated statically at compile time. Therefore, reactions manipulate the existing instance of Element
rather than creating a new Element
with the relevant attributes.
Because of this, we differentiate elements between raw base elements (which are in the element database) and mutated elements (which are the ones used in reactions.) All mutated elements have an associated raw base element. A mutated element can be reset to default using Element::ResetToBasicState
or by changing it to a new raw element with one of the Element::GetRawElement
methods.
As of v0.2s2, some basic dyanmic memory allocation via the ObjectPool class is available. The object pool is detailed in the following section.
If you do attempt to allocate a non-ObjectPool class dynamically (with new
), you will get the following cryptic error:EXEC : -!- Slinky error : Taking address of undefined symbol '_Znwm'
Dynamic Allocation via ObjectPool
As of v0.2s2, some basic dynamic memory allocation facilities are available via the ObjectPool class. This class allows using new and delete to allocate objects from a statically-sized pool. The objects are still allocated statically by the compiler, but it is easier to instantiate and destroy the objects at runtime, which can make code easier to read.
To enable a type to use the object pool, simply include ObjectPool.h and publicly inherit it from the ObjectPool type. You will need to specify your type and the desired size of the object pool.
For example, the following will allow allocating up to 10 instances of SomeObject at runtime.
class SomeObject : public ObjectPool<SomeObject, 10>
{ /* ... */ }
Note: The ObjectPool has not been tested with child types, and may behave incorrectly if you attempt to do so.
Standard C Library
Because the Sifteo SDK does not include the standard C library, we don't use any of it. Any standard functions you see, such as strlen
or strcmp
are actually implemented within periodic.cpp
.
Therefore: You should be wary of developing / testing outside of the Sifteo environment as you may develop code that won't compile.