7 Scene Actor Component model
~keith edited this page 2022-02-23 23:42:32 +00:00

Scenes, actors, and components are the fundamental building blocks of wh-engine games. Together, they define the structure, state, and behaviour of everything within the game world.

Scenes

A scene defines a level, area, or other part of the game, and acts as a container for actors. Scenes are largely independent of each other, and more than one can be running at the same time.

In general, scenes (and the actors within them) should not reference other scenes directly; instead, they should interact via the message bus.

Actors

Actors represent the game entities within a scene. They have a transform (location, rotation, and scale), may be a child of another actor, and contain a set of components which define their behaviour. They also store a set of tags, which can be used to classify and filter for specific types of objects (e.g. terrain, enemies, players, UI).

Newly created actors should be initialized using the (initialize-actors-in) function, like so:

(initialize-actors-in my-scene
    (new! actor :name "Example"
        :component (new! sprite :texture my-texture)
    (new! actor :name "Another example"
        :location (vec2 4.20 -6.9)
        :component (new! sprite :texture another-texture))

Components

Components define a group of behaviours and properties for the actor they're attached to. They can interact with other components and actors.

If a component needs to automatically establish a reference to another component or actor, it should do this during late-stage initialization, eg. in (activate). Otherwise, the other object may not have been instantiated yet.

Lifecycle

Component lifecycle diagram

  • Initialization methods: (resume) (early), (activate) & (start) (late)

  • De-initialization methods: (destroy)

  • If the component is active-p after the initial (resume), (activate) will be executed immediately afterwards. However, if it is not active-p, the call to (activate) will take place when the component is activated by some other piece of code. This is not guaranteed to occur! The component may be suspended or destroyed before it ever becomes active-p and enters the update loop.

  • Correction to diagram: At any point that (destroy) may be called, (suspend) may also be called. If the component is suspended while it is not active-p, and then resumed, (activate) will be called before the component enters the update loop. Otherwise, it will be returned to the update loop immediately.

  • (suspend) is not a de-initialization method! It exists to prepare the component's internal state for serialization, and serious issues will occur if it affects any other data. Clean up references and resources in (destroy) instead.

  • Avoid clobbering existing state. (resume) may be used for early-stage initialization, but it should not overwrite data that is already valid. Otherwise, actor deserialization will not function properly.

    • Likewise, (activate) should not assume it is being called on an uninitialized component.
    • Check the validity of the state, not the origin of the method call.
    • Consider writing tests which (suspend), (resume), and (activate) a component with valid state, to ensure it is not corrupted by this process.
      • Also consider running these tests at random during beta builds of your game.