GitHub

Components

A component is a self-contained unit of data that belongs to an entity. An entity can have 0 or more components and can add or remove components throughout the course of its life. Components can describe any data belonging to an entity, such as Transform, Health, Inventory, IsPlayer, and anything else you need.

Writing Components

Components are modeled as normal Javascript classes - they may contain fields of any type, as well as constructors and methods.

class Health {
	current: number = 0;
	max: number = 0;
}
ℹ️

Thyseus identifies the types of components by looking at the object's inherent constructor property. As a result, plain Javascript objects cannot be used as components!

Here we've defined an isolated component that determines an entity's health. Of course, there's nothing stopping current from exceeding max, which we likely do not want. This is a great case for methods:

class Health {
	#max: number = 0;
	#current: number = 0;
 
	heal(amount: number) {
		// Clamp to max
		this.#current = Math.min(
			this.#max,
			this.#current + amount
		);
	}
 
	takeDamage(amount: number): boolean {
		// Clamp to 0, we don't need to go any lower
		this.#current = Math.max(0, this.#current - amount);
		// Return a boolean indicating if this entity died
		return this.#current === 0;
	}
}

We've converted the max and current properties to be # private, requiring consumers to use the heal() and takeDamage() methods. This protects our fields from unexpected combinations while keeping our code dry, localized, and easily testable.

Components can define constructors and be extended as needed

class Health {
	#max: number;
	#current: number;
 
	constructor(max: number, current: number = max) {
		this.#max = max;
		this.#current = current;
	}
}
 
class Vec2 {
	x: number = 0;
	y: number = 0;
}
class Vec3 extends Vec2 {
	z: number = 0;
}
 
class Position extends Vec3 {}
class Velocity extends Vec3 {}

Tag Components

In some cases, you may want to add a "tag" to an entity (e.g., IsPlayer) but have no additional data associated with that component. While normal components work just fine for this, Thyseus allows you to create "tag" components - sometimes referred to as "zero-sized types" (ZSTs).

import { Tag } from 'thyseus';
 
class IsPlayer extends Tag {}