Skip to content

Custom GameObjects ​

Most behavior belongs in components, because they can be mixed and attached from data. Sometimes a GameObject class of your own is the better fit: when a type of object always needs the same fields, or when you create very many of them.

Creating a class ​

ts
import { Entity, GameObject, InspectorBaseClass, InspectorField } from 'bare-engine';

// the prefab fields this class adds, for autocomplete and type checks
export interface EnemyEntity extends Entity
{
    health?: number;
}

@InspectorBaseClass
export class Enemy extends GameObject
{
    declare entity: EnemyEntity | null;

    @InspectorField
    health = 3;

    OnUpdate(deltaTime: number)
    {
        this.x -= 50 * deltaTime;
    }

    Hit()
    {
        if (--this.health <= 0)
            this.Remove();
    }
}

GameObject lifecycle hooks include OnAwake, OnStart, OnAdded, OnUpdate, OnFixedUpdate, OnPreRender, OnRender, OnPostRender, OnRemoved and OnResize. Their ownership and timing differ from scene hooks; see Lifecycle & Cleanup.

Examples: the RPG's Weapon extends ArcadeObject with a strength field and a Slash button, and its Joystick is a GameObject with its own update.

Using it ​

In code:

ts
const enemy = this.AddGameObject(Enemy);
const goblin = this.AddGameObject<Enemy>({
    baseClass: 'Enemy',
    texture: 'goblin',
    health: 5,
});

In a prefab, with baseClass:

json
{
  "name": "goblin",
  "baseClass": "Enemy",
  "texture": "goblin",
  "health": 5
}

@InspectorBaseClass registers the class with the engine automatically, so it can be used by name in prefabs and shows up in the Chrome extension. Without it, register the class yourself with bare.AddClass(Enemy).

Fields marked @InspectorField can be set from prefabs and edited in the extension.

Example: the Showcase's extend demo uses an EmojiObject class as a prefab's baseClass, and the prefabs demo does the same with Fruit.

Typed prefab fields ​

The EnemyEntity interface and the declare entity line in the class above describe the prefab fields your class adds. They make this.AddGameObject<Enemy>({ health: 5 }) type-checked and give you autocomplete. Without them, TypeScript only accepts the standard entity fields, and health: 5 is an error.

Example: the engine's own Button does this with ButtonEntity, which adds text, fontSize, buttonColor and more.

Object pools ​

Creating and removing many objects, like bullets, costs time and memory. A pool keeps removed objects and hands them out again.

Registered GameObject classes get a pool automatically. When you Remove() a pooled object, it goes back to its pool, and the next AddGameObject(Bullet) reuses it.

To create the objects up front:

ts
bare.RegisterGameObjectPool(Bullet, 200);

Pooled objects get their standard values back when they're reused, but your own fields don't. Reset them in OnAwake, and release listeners in OnRemoved; see pooled objects.

bare.pool gives access to all pools by class name, for example bare.pool.get('Bullet').GetSize().

Bare Engine is open source under the MIT license.