Interacting with Behaviors
Fetching other behaviors attached to an entity.
import {
Behavior,
Entity,
EntityCollision,
ColoredSquare,
} from "@dreamlab/engine";
import PlayerBehavior from "./player.ts"; // this import is not an api, the user will have to have or create a player behavior for this example.
/*
Example: Using `getBehavior()` to Access Behaviors
The `getBehavior()` method allows you to retrieve an existing behavior attached to an entity.
This is particularly useful when you need to interact with or update a behavior that has already been set up,
such as a health bar or UI component, without needing to instantiate it again.
In this example, `getBehavior()` is used to update the player's score when an asteroid is destroyed,
as well as to interact with the asteroid's health bar.
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.
Benefits of `getBehavior()`:
- Prevents duplication of behavior instances.
- Allows direct access to existing behaviors for updates or interactions.
- Ensures that only one instance of the behavior is manipulated, maintaining consistency.
*/
export default class AsteroidBehavior extends Behavior {
onInitialize(): void {
this.listen(this.entity, EntityCollision, (e) => {
if (e.started) this.onCollide(e.other);
});
}
onCollide(other: Entity) {
if (!other.name.startsWith("Bullet")) return;
other.destroy();
// Retrieve the HealthBar behavior for this entity
const healthBar = this.entity.getBehavior(HealthBar);
// Reduce the asteroid's health by 1
healthBar.takeDamage(1);
// If health reaches zero, update the player's score and destroy the asteroid
if (healthBar.currentHealth <= 0) {
const player = this.game.world._.Player;
// Use getBehavior to access the PlayerBehavior and update the score
player.getBehavior(PlayerBehavior).score += 50;
// Destroy the asteroid entity (healthBar destruction is handled by takeDamage)
this.entity.destroy();
}
}
}
// Health bar behavior for reference
import {
GamePostTick,
Sprite,
Vector2,
syncedValue,
} from "@dreamlab/engine";
export default class HealthBar extends Behavior {
@syncedValue()
maxHealth = 100;
@syncedValue()
currentHealth = 100;
healthBarEntity!: Entity;
onInitialize(): void {
this.healthBarEntity = this.game.world.spawn({
type: Sprite,
name: "HealthBar",
transform: { position: { x: 0, y: 1, }, scale: { x: 1, y: 0.1 } },
values: { texture: "res://assets/healthbar.png" },
});
this.game.on(GamePostTick, () => {
this.healthBarEntity.pos = this.entity.pos.add(new Vector2(0, 1));
this.updateHealthBar();
});
}
updateHealthBar(): void {
const healthRatio = this.currentHealth / this.maxHealth;
this.healthBarEntity.transform.scale.x = healthRatio;
}
takeDamage(damage: number): void {
this.currentHealth -= damage;
if (this.currentHealth <= 0) {
this.currentHealth = 0;
this.entity.destroy();
this.healthBarEntity.destroy();
this.spawnExplosionPieces();
}
this.updateHealthBar();
}
spawnExplosionPieces(): void {
const pieceCount = Math.random() * 5 + 3;
const pieceSize = { x: 0.15, y: 0.15 };
for (let i = 0; i < pieceCount; i++) {
this.entity.game.world.spawn({
type: Sprite,
name: "ExplosionPiece",
transform: {
position: this.entity.transform.position.clone(),
scale: pieceSize,
},
behaviors: [],
children: [
{
type: Sprite,
name: "PieceSprite",
values: { texture: "res://assets/asteroid.png" },
},
],
});
}
}
}