Custom components
Custom components #
If you need to store information about an entity that isn’t handled by the default components of the SDK (see component reference ), then you can create a custom type of component on your scene.
Tip: Custom components can be defined in your scene’s game.ts
file, but for larger projects we recommend defining them in a separate .ts
file and importing them.
A component can store as many fields as you want.
@Component("wheelSpin")
export class WheelSpin {
spinning: boolean
speed: number
}
Note that we’re defining two names for the component: wheelSpin
and WheelSpin
in this case. The class name, the one in upper case, is the one you use to add the component to entities. The space name, the one starting with a lower case letter, can mostly be ignored, except if you want to use it as an Interchangeable component.
Once defined, you can use the component in the entities of your scene:
// Create entities
const wheel = new Entity()
const wheel2 = new Entity()
// Create instances of the component
wheel.addComponent(new WheelSpin())
wheel2.addComponent(new WheelSpin())
// Set values on component
wheel.getComponent(WheelSpin).spinning = true
wheel.getComponent(WheelSpin).speed = 10
wheel2.getComponent(WheelSpin).spinning = false
Each entity that has the component added to it is instancing a new copy of it, holding specific data for that entity.
Constructors #
Adding a constructor to a component allows you to configure its values in the same expression as you create an instance of it.
@Component("wheelSpin")
export class WheelSpin {
spinning: boolean
speed: number
constructor(spinning: boolean, speed: number) {
this.spinning = spinning
this.speed = speed
}
}
If the component includes a constructor, you can use the following syntax:
// Create entity
const wheel = new Entity()
// Create instance of component and set its values
wheel.addComponent(new WheelSpin(true, 10))
💡 Tip: If you use a source code editor, when instancing a component that has a constructor, you can see what the parameters are by mousing over the expression.
You can make the parameters optional by setting default values on each. If there are default values and you don’t declare the parameters when instancing a component, it will use the default.
@Component("wheelSpin")
export class WheelSpin {
spinning: boolean
speed: number
constructor(spinning?: boolean = false, speed?: number = 3) {
this.spinning = spinning
this.speed = speed
}
}
// Create entity
const wheel = new Entity()
// Create instance of component with default values
wheel.addComponent(new WheelSpin())
Interchangeable components #
Certain components intentionally can’t coexist in a single entity. For example, an entity can’t have both BoxShape
and PlaneShape
. If you assign one using .addComponentOrReplace()
, you overwrite the other if present.
You can create custom components that follow this same behavior against each other, where it only makes sense for each entity to have only one of them assigned.
To define components that are interchangeable and that occupy a same space in an entity, set the same name for both on the component’s internal name:
@Component("animal")
export class Dog {
(...)
}
@Component("animal")
export class Cat {
(...)
}
In the example above, note that both components occupy the animal space. Each entity in the scene can only have one animal component assigned.
If you use .addComponentOrReplace()
to assign a Dog component to an entity that has a Cat component, then the Dog component will overwrite the Cat component.
Components as flags #
You may want to add a component that simply flags an entity to differentiate it from others, without using it to store any data.
This is especially useful when using Component groups. Since component groups list entities based on components they own, a simple flag component can tell entities apart from others.
@Component("myFlag")
export class MyFlag {}