Skip to main content

Basic Structure

Behavior classes are used to implement all game functionality.

import {
Behavior,
Vector2,
Vector2Adapter,
syncedValue,
ColoredSquare,
} from "@dreamlab/engine";
/*
In "@dreamlab/engine", a `Behavior` represents a modular piece of logic that can be attached to an entity.
This allows you to encapsulate functionality, such as movement, health management, or AI, in reusable components.

Key Components:
- **Lifecycle Methods:**
- `onInitialize`: Called once when the behavior is first attached to an entity, used for setup tasks.
- `onTick`: Called on every game tick, ideal for updating logic like movement or state changes.
- `onPreTick`, `onPostTick`, `onFrame`: Additional lifecycle hooks for more granular control over update timing.

- **Values:** Behaviors can have properties (values) that are synchronized across the network or exposed to
an inspector GUI. These values are defined using `defineValue` or `defineValues` methods and can be of various
types, including primitives and complex types with adapters.

- **Signals:** Behaviors can listen for signals (events) from the game or other entities and respond accordingly.
This is done using the `listen` method for subscribing to signals, and `fire` to emit them.

- **Destruction:** Behaviors can be destroyed manually using `destroy()` or automatically via the entity lifecycle.
This cleanup process ensures all listeners and values are properly disposed of.

The `Behavior` class is highly flexible, supporting complex game mechanics through a combination of values, signals,
and lifecycle hooks. It serves as the foundation for defining how entities behave in the game world.

Accessing entity children:
Use `this.entity._.ChildName` to access a child entity directly.
For example: `this.entity._.ColoredSquare` will work if the entity has a child named 'ColoredSquare'.

If the child's name contains a space, use bracket notation: `this.entity._["My_Entity"]`.

You can also access children of children by chaining:
`this.entity.myChild.myOtherChild`.

Important:
Do NOT use `this.entity.children.find(child => child.name === "ChildName")` as it is inefficient and unnecessary.
The `children` property provides a `ReadonlyMap` for reference but should not be used for lookups.

Important Notes:
- **Do Not Use Renderer for Game Screen Dimensions:**
The game screen is defined by the camera(s) in the game scene, not by the renderer or app.
Attempting to access `this.game.renderer.app.screen.width` or `this.game.renderer.app.screen.height` is incorrect.
To limit game space or define boundaries, use colliders (e.g., walls) in the world.
Avoid relying on renderer properties as they do not exist on `game` and are unrelated to defining game space.

*/

// example Behavior that allows for WASD movement as well as a pattern for firing projectiles.
// this serves as an example for the general structure of a behavior
export default class Movement extends Behavior {
// the speed of the player
@syncedValue()
speed = 5.0;

// example value
@syncedValue()
anotherValue = 42.0;

// the current velocity of the player
@syncedValue(Vector2Adapter)
velocity = Vector2.ZERO;

// Input bindings for movement
// (method) Inputs.create(name: string, label: string, defaultBinding: Input): Action
#up = this.inputs.create("@movement/up", "Move Up", "KeyW");
#down = this.inputs.create("@movement/down", "Move Down", "KeyS");
#left = this.inputs.create("@movement/left", "Move Left", "KeyA");
#right = this.inputs.create("@movement/right", "Move Right", "KeyD");

onInitialize(): void {
// if you want to disable/enable an entity (useful for hiding and showing things), simply use
this.entity.enabled = false;
}

onTick(): void {
const movement = new Vector2(0, 0);
const currentSpeed = this.speed;

if (this.#up.held) movement.y += 1;
if (this.#down.held) movement.y -= 1;
if (this.#right.held) movement.x += 1;
if (this.#left.held) movement.x -= 1;

this.velocity = movement
.normalize()
.mul((this.game.physics.tickDelta / 100) * currentSpeed);

const newPosition = this.entity.transform.position.add(this.velocity);
}
}