Skip to content

Systems

Giacomo Cavalieri edited this page Oct 14, 2021 · 3 revisions

A System is used to perform operations on a world's entities. It essentially is a shortcut for iterating over views (but it proves very useful in order to write concise, readable code).

How does a system work?

Generally speaking, a system describes a computation that is performed each time the world's update method is called. A simple System simply uses the delta time and world's reference to perform its computation. A special kind of System is the IteratingSystem: it is a wrapper of a view that allows to perform some computation over all its entities.

System

To create a System you can simply use its apply method specifying its update behaviour:

val system = System((deltaTime, world) => ???)
val printSystem = System((_, _) => println("Hello, world!"))
// This system will print "Hello, world!" each time the world in which it is inserted
// is updated

IteratingSystem

An IteratingSystem is a wrapper of a View; it defines some methods:

  • shouldRun: it is checked every time the system should be executed, if it returns false the system is not executed
  • before: a function that is executed once before updating the entities over which the system iterates
  • update: defines how to update a single entity, will be automatically applied to all the system's entities
  • after: a function that is executed once after updating the entities over which the system iterates

To create an IteratingSystem you can use a handy builder syntax:

import dev.atedeg.ecscala.given

val system = System[Position &: Velocity &: CNil]
  .withPrecondition { () => ??? }
  .withBefore { (deltaTime, world, view) => ??? }
  .withAfter { (deltaTime, world, view) => ??? }
  .withUpdate { (entity, components, deltaTime) => ??? }

Some things to note:

  • We must annotate the type of the components over which the system will iterate (System[Position &: Velocity &: CNil] iterates over all entities with a Position and a Velocity components)
  • The call to withPrecondition, withBefore and withAfter are all optional and can be made in any order
  • The call to withUpdate is needed to actually create the system and specifies how it will update each entity
  • withUpdate can also be called with the lambda (entity, components, deltaTime, world, view) => ???
  • components in the lambda parameters is the CList of components specified in the system type at the beginning (i.e. here it is a CList Position &: Velocity &: CNil)

ExcludingSystem

Is a wrapper of an ExcludingView, building it is very similar to building an IteratingSystem, to specify the components' types to exclude you can simply write:

import dev.atedeg.ecscala.given

val system = System[Position &: Velocity &: CNil].excluding[Mass &: CNil]
  .withPrecondition { () => ??? }
  .withBefore { (deltaTime, world, view) => ??? }
  .withAfter { (deltaTime, world, view) => ??? }
  .withUpdate { (entity, components, deltaTime) => ??? }

Adding a system to a world

To add a system to a world you can write:

object Example with ECScalaDSL {
  val world = World()
  val mySystem = System[Position &: CNil].withUpdate(???)
  world hasA system(mySystem)
}

Removing a system from a world

To remove a system from a world you can write:

object Example with ECScalaDSL {
  val world = World()
  val mySystem = System[Position &: CNil].withUpdate(???)
  world hasA system(mySystem)
  remove mySystem from world
}
Clone this wiki locally