@dryanovski/gamefoo 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/animate.js +147 -0
- package/dist/core/asset.js +74 -0
- package/dist/core/behaviour.js +88 -0
- package/dist/core/behaviours/collidable.js +186 -0
- package/dist/core/behaviours/control.js +75 -0
- package/dist/core/behaviours/healtkit.js +153 -0
- package/dist/core/behaviours/sprite_render.js +193 -0
- package/dist/core/camera.js +134 -0
- package/dist/core/engine.d.ts +1 -1
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +527 -0
- package/dist/core/fonts/font_bitmap.js +205 -0
- package/dist/core/fonts/font_bitmap_prebuild.js +137 -0
- package/dist/core/fonts/internal/font_3x5.js +169 -0
- package/dist/core/fonts/internal/font_4x6.js +171 -0
- package/dist/core/fonts/internal/font_5x5.js +129 -0
- package/dist/core/fonts/internal/font_6x8.js +171 -0
- package/dist/core/fonts/internal/font_8x13.js +171 -0
- package/dist/core/fonts/internal/font_8x8.js +171 -0
- package/dist/core/game_object_register.js +134 -0
- package/dist/core/input.js +170 -0
- package/dist/core/sprite.js +222 -0
- package/dist/core/utils/perlin_noise.js +183 -0
- package/dist/core/world.js +304 -0
- package/dist/debug/monitor.js +47 -0
- package/dist/decorators/index.js +1 -0
- package/dist/decorators/log.js +42 -0
- package/dist/entities/dynamic_entity.js +99 -0
- package/dist/entities/entity.js +283 -0
- package/dist/entities/player.js +93 -0
- package/dist/entities/text.js +62 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -29
- package/dist/subsystems/camera_system.d.ts +2 -2
- package/dist/subsystems/camera_system.d.ts.map +1 -1
- package/dist/subsystems/camera_system.js +41 -0
- package/dist/subsystems/collision_system.js +17 -0
- package/dist/subsystems/monitor_system.js +20 -0
- package/dist/subsystems/object_system.d.ts +1 -1
- package/dist/subsystems/object_system.d.ts.map +1 -1
- package/dist/subsystems/object_system.js +29 -0
- package/dist/subsystems/types.d.ts +1 -1
- package/dist/subsystems/types.d.ts.map +1 -1
- package/dist/subsystems/types.js +0 -0
- package/dist/types.js +10 -0
- package/package.json +17 -6
- package/src/core/animate.ts +159 -0
- package/src/core/asset.ts +76 -0
- package/src/core/behaviour.ts +145 -0
- package/src/core/behaviours/collidable.ts +296 -0
- package/src/core/behaviours/control.ts +80 -0
- package/src/core/behaviours/healtkit.ts +166 -0
- package/src/core/behaviours/sprite_render.ts +216 -0
- package/src/core/camera.ts +145 -0
- package/src/core/engine.ts +607 -0
- package/src/core/fonts/font_bitmap.ts +232 -0
- package/src/core/fonts/font_bitmap_prebuild.ts +141 -0
- package/src/core/fonts/internal/font_3x5.ts +178 -0
- package/src/core/fonts/internal/font_4x6.ts +180 -0
- package/src/core/fonts/internal/font_5x5.ts +137 -0
- package/src/core/fonts/internal/font_6x8.ts +180 -0
- package/src/core/fonts/internal/font_8x13.ts +180 -0
- package/src/core/fonts/internal/font_8x8.ts +180 -0
- package/src/core/game_object_register.ts +146 -0
- package/src/core/input.ts +182 -0
- package/src/core/sprite.ts +339 -0
- package/src/core/utils/perlin_noise.ts +196 -0
- package/src/core/world.ts +331 -0
- package/src/debug/monitor.ts +60 -0
- package/src/decorators/index.ts +1 -0
- package/src/decorators/log.ts +45 -0
- package/src/entities/dynamic_entity.ts +106 -0
- package/src/entities/entity.ts +322 -0
- package/src/entities/player.ts +99 -0
- package/src/entities/text.ts +72 -0
- package/src/index.ts +51 -0
- package/src/subsystems/camera_system.ts +52 -0
- package/src/subsystems/collision_system.ts +21 -0
- package/src/subsystems/monitor_system.ts +26 -0
- package/src/subsystems/object_system.ts +37 -0
- package/src/subsystems/types.ts +46 -0
- package/src/types.ts +178 -0
- package/dist/index.js.map +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/subsystems/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/subsystems/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,gBAAgB,CAAC;AAEzC;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,UAAU,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC,SAAS,CAAC,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAChD,MAAM,CAAC,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC7C,UAAU,CAAC,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAEjD,OAAO,CAAC,IAAI,IAAI,CAAC;CAClB"}
|
|
File without changes
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions used throughout the GameFoo engine.
|
|
3
|
+
*
|
|
4
|
+
* This module contains the foundational interfaces and type aliases that
|
|
5
|
+
* form the contract between the engine core, entities, and behaviours.
|
|
6
|
+
*
|
|
7
|
+
* @category Types
|
|
8
|
+
* @module types
|
|
9
|
+
* @since 0.1.0
|
|
10
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dryanovski/gamefoo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "A lightweight 2D game engine with behavior-based component system",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
7
|
-
"dist"
|
|
7
|
+
"dist",
|
|
8
|
+
"src",
|
|
9
|
+
"README.md"
|
|
8
10
|
],
|
|
9
11
|
"type": "module",
|
|
10
12
|
"sideEffects": false,
|
|
13
|
+
"source": "./src/index.ts",
|
|
11
14
|
"main": "./dist/index.js",
|
|
12
15
|
"module": "./dist/index.js",
|
|
13
16
|
"types": "./dist/index.d.ts",
|
|
14
17
|
"exports": {
|
|
15
18
|
".": {
|
|
16
19
|
"types": "./dist/index.d.ts",
|
|
17
|
-
"import": "./dist/index.js"
|
|
18
|
-
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./source": {
|
|
24
|
+
"types": "./src/index.ts",
|
|
25
|
+
"import": "./src/index.ts",
|
|
26
|
+
"default": "./src/index.ts"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
19
29
|
},
|
|
20
30
|
"publishConfig": {
|
|
21
31
|
"access": "public"
|
|
22
32
|
},
|
|
23
33
|
"scripts": {
|
|
24
34
|
"dev": "bun --watch demos/server.ts",
|
|
25
|
-
"build": "rm -rf dist &&
|
|
35
|
+
"build": "rm -rf dist && bunx tsc -p tsconfig.build.json",
|
|
26
36
|
"typecheck": "tsc --noEmit",
|
|
27
37
|
"typecheck:watch": "tsc --noEmit --watch",
|
|
28
38
|
"lint": "bunx biome check src/",
|
|
@@ -36,7 +46,8 @@
|
|
|
36
46
|
"docs:collect": "tsx scripts/collect-docs.ts",
|
|
37
47
|
"docs:dev": "npm run docs:generate && astro dev --root ./docs",
|
|
38
48
|
"docs:preview": "astro preview --root ./docs",
|
|
39
|
-
"docs:watch": "chokidar 'src/**/*.ts' -c 'bun run docs:generate' --initial"
|
|
49
|
+
"docs:watch": "chokidar 'src/**/*.ts' -c 'bun run docs:generate' --initial",
|
|
50
|
+
"test:publish": "bun run --cwd publish-test sanity"
|
|
40
51
|
},
|
|
41
52
|
"dependencies": {
|
|
42
53
|
"@microsoft/tsdoc": "^0.16.0",
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frame-based sprite animation controller.
|
|
3
|
+
*
|
|
4
|
+
* `Animate` steps through a sequence of spritesheet cells at a given
|
|
5
|
+
* frame rate. It tracks elapsed time internally and advances the
|
|
6
|
+
* current frame index each time the interval elapses.
|
|
7
|
+
*
|
|
8
|
+
* > **Note:** The {@link Animate.draw} method is currently a stub —
|
|
9
|
+
* > it resolves the correct frame but does not yet perform the actual
|
|
10
|
+
* > `drawImage` call. Use {@link SpriteRender} for production
|
|
11
|
+
* > sprite rendering.
|
|
12
|
+
*
|
|
13
|
+
* @category Core
|
|
14
|
+
* @since 0.1.0
|
|
15
|
+
*
|
|
16
|
+
* @example Creating a walk animation
|
|
17
|
+
* ```ts
|
|
18
|
+
* const walkFrames = [
|
|
19
|
+
* { col: 0, row: 0 },
|
|
20
|
+
* { col: 1, row: 0 },
|
|
21
|
+
* { col: 2, row: 0 },
|
|
22
|
+
* { col: 3, row: 0 },
|
|
23
|
+
* ];
|
|
24
|
+
*
|
|
25
|
+
* const anim = new Animate("walk", walkFrames, 32, 32, 12);
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example Updating in a game loop
|
|
29
|
+
* ```ts
|
|
30
|
+
* function update(delta: number) {
|
|
31
|
+
* anim.update(delta);
|
|
32
|
+
* anim.draw(ctx, entity.x, entity.y);
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @see {@link SpriteRender} — behaviour-based alternative for entity rendering
|
|
37
|
+
* @see {@link Sprite} — spritesheet metadata container
|
|
38
|
+
*/
|
|
39
|
+
export default class Animate {
|
|
40
|
+
/** Identifier for this animation (e.g. `"walk"`, `"idle"`). */
|
|
41
|
+
private key: string;
|
|
42
|
+
|
|
43
|
+
/** Ordered list of spritesheet cells that make up the animation. */
|
|
44
|
+
private frames: { col: number; row: number }[];
|
|
45
|
+
|
|
46
|
+
/** Width of a single frame in pixels. */
|
|
47
|
+
private frameW: number;
|
|
48
|
+
|
|
49
|
+
/** Height of a single frame in pixels. */
|
|
50
|
+
private frameH: number;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Index into {@link Animate.frames} of the frame currently being
|
|
54
|
+
* displayed.
|
|
55
|
+
*
|
|
56
|
+
* @defaultValue `0`
|
|
57
|
+
*/
|
|
58
|
+
private currentFrame: number = 0;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Milliseconds accumulated since the last frame advance.
|
|
62
|
+
*
|
|
63
|
+
* @defaultValue `0`
|
|
64
|
+
*/
|
|
65
|
+
private elapsed = 0;
|
|
66
|
+
|
|
67
|
+
/** Computed time between frames in milliseconds (`1000 / fps`). */
|
|
68
|
+
private interval: number;
|
|
69
|
+
|
|
70
|
+
/** Playback speed in frames per second. */
|
|
71
|
+
private fps: number;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Creates a new animation sequence.
|
|
75
|
+
*
|
|
76
|
+
* @param key - A unique name for this animation (used as a look-up key).
|
|
77
|
+
* @param frames - An ordered array of `{ col, row }` cells from the
|
|
78
|
+
* spritesheet.
|
|
79
|
+
* @param frameW - Width of each frame in pixels.
|
|
80
|
+
* @param frameH - Height of each frame in pixels.
|
|
81
|
+
* @param fps - Playback speed in frames per second.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* const idle = new Animate(
|
|
86
|
+
* "idle",
|
|
87
|
+
* [{ col: 0, row: 1 }, { col: 1, row: 1 }],
|
|
88
|
+
* 64, 64,
|
|
89
|
+
* 8,
|
|
90
|
+
* );
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
constructor(key: string, frames: { col: number; row: number }[], frameW: number, frameH: number, fps: number) {
|
|
94
|
+
this.key = key;
|
|
95
|
+
this.frames = frames;
|
|
96
|
+
this.frameW = frameW;
|
|
97
|
+
this.frameH = frameH;
|
|
98
|
+
this.fps = fps;
|
|
99
|
+
|
|
100
|
+
this.interval = 1000 / this.fps;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Advances the animation clock and moves to the next frame when the
|
|
105
|
+
* interval has elapsed.
|
|
106
|
+
*
|
|
107
|
+
* @param delta - Time elapsed since the last call, **in milliseconds**.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* // Inside a requestAnimationFrame loop:
|
|
112
|
+
* anim.update(deltaMs);
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
public update(delta: number) {
|
|
116
|
+
this.elapsed += delta;
|
|
117
|
+
|
|
118
|
+
if (this.elapsed >= this.interval) {
|
|
119
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
120
|
+
this.elapsed = 0;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Draws the current animation frame to the canvas.
|
|
126
|
+
*
|
|
127
|
+
* @remarks
|
|
128
|
+
* This method is currently a **stub**. It resolves the correct
|
|
129
|
+
* `{ col, row }` cell but does not perform the actual
|
|
130
|
+
* `ctx.drawImage()` call. Wire it to {@link Asset} or use
|
|
131
|
+
* {@link SpriteRender} for full rendering.
|
|
132
|
+
*
|
|
133
|
+
* @param _ctx - The canvas 2-D rendering context.
|
|
134
|
+
* @param _destX - Destination X coordinate on the canvas.
|
|
135
|
+
* @param _destY - Destination Y coordinate on the canvas.
|
|
136
|
+
*/
|
|
137
|
+
public draw(_ctx: CanvasRenderingContext2D, _destX: number, _destY: number) {
|
|
138
|
+
const frame = this.frames[this.currentFrame];
|
|
139
|
+
if (!frame) return;
|
|
140
|
+
const { col: _col, row: _row } = frame;
|
|
141
|
+
// Asset.drawFrame(ctx, key, col, row, frameW, frameH, destX, destY)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Resets the animation to its first frame.
|
|
146
|
+
*
|
|
147
|
+
* Call this when switching animations or restarting a sequence.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* anim.reset();
|
|
152
|
+
* anim.update(0); // ensures frame 0 is active
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
public reset() {
|
|
156
|
+
this.currentFrame = 0;
|
|
157
|
+
this.elapsed = 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static image asset loader with an in-memory cache.
|
|
3
|
+
*
|
|
4
|
+
* `Asset` wraps the native `Image` constructor with a `Promise`-based
|
|
5
|
+
* API and caches loaded images by URL so repeated requests for the same
|
|
6
|
+
* source resolve instantly.
|
|
7
|
+
*
|
|
8
|
+
* @category Core
|
|
9
|
+
* @since 0.1.0
|
|
10
|
+
*
|
|
11
|
+
* @example Loading an image
|
|
12
|
+
* ```ts
|
|
13
|
+
* const image = await Asset.load("sprites/hero.png");
|
|
14
|
+
* ctx.drawImage(image, 0, 0);
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @example Pre-loading multiple assets
|
|
18
|
+
* ```ts
|
|
19
|
+
* await Promise.all([
|
|
20
|
+
* Asset.load("sprites/hero.png"),
|
|
21
|
+
* Asset.load("sprites/enemy.png"),
|
|
22
|
+
* Asset.load("tiles/grass.png"),
|
|
23
|
+
* ]);
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @see {@link Sprite} — consumes loaded images for spritesheet slicing
|
|
27
|
+
*/
|
|
28
|
+
export default class Asset {
|
|
29
|
+
/**
|
|
30
|
+
* Internal cache mapping source URLs to their loaded
|
|
31
|
+
* `HTMLImageElement` instances.
|
|
32
|
+
*/
|
|
33
|
+
private static cache: Map<string, HTMLImageElement> = new Map();
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Loads an image from the given URL.
|
|
37
|
+
*
|
|
38
|
+
* If the image has been loaded before, the cached `HTMLImageElement`
|
|
39
|
+
* is returned immediately (the `Promise` resolves synchronously on
|
|
40
|
+
* the microtask queue).
|
|
41
|
+
*
|
|
42
|
+
* @param src - URL or relative path of the image to load.
|
|
43
|
+
* @returns A `Promise` that resolves with the loaded
|
|
44
|
+
* `HTMLImageElement`.
|
|
45
|
+
*
|
|
46
|
+
* @throws {Error} If the image fails to load (e.g. 404 or network
|
|
47
|
+
* error). The error message includes the failing `src`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* try {
|
|
52
|
+
* const img = await Asset.load("missing.png");
|
|
53
|
+
* } catch (err) {
|
|
54
|
+
* console.error(err); // "Failed to load image: missing.png"
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
static async load(src: string): Promise<HTMLImageElement> {
|
|
59
|
+
const cache = Asset.cache.get(src);
|
|
60
|
+
|
|
61
|
+
if (cache) {
|
|
62
|
+
return cache;
|
|
63
|
+
}
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const image = new Image();
|
|
66
|
+
image.onload = () => {
|
|
67
|
+
Asset.cache.set(src, image);
|
|
68
|
+
resolve(image);
|
|
69
|
+
};
|
|
70
|
+
image.onerror = (_error) => {
|
|
71
|
+
reject(new Error(`Failed to load image: ${src}`));
|
|
72
|
+
};
|
|
73
|
+
image.src = src;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type Entity from "../entities/entity";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for all entity behaviours in the GameFoo engine.
|
|
5
|
+
*
|
|
6
|
+
* A **behaviour** is a self-contained unit of logic (input handling,
|
|
7
|
+
* collision response, health tracking, rendering, etc.) that can be
|
|
8
|
+
* attached to any {@link Entity} at runtime via
|
|
9
|
+
* {@link Entity.attachBehaviour}.
|
|
10
|
+
*
|
|
11
|
+
* Subclasses **must** implement:
|
|
12
|
+
* - {@link Behaviour.type | type} — a unique string identifier (e.g. `"control"`, `"healthkit"`).
|
|
13
|
+
* - {@link Behaviour.update | update} — called once per frame with `deltaTime`.
|
|
14
|
+
*
|
|
15
|
+
* Subclasses **may** override:
|
|
16
|
+
* - {@link Behaviour.render | render} — draw debug visuals or overlays.
|
|
17
|
+
* - {@link Behaviour.onAttach | onAttach} — setup hook when added to an entity.
|
|
18
|
+
* - {@link Behaviour.onDetach | onDetach} — teardown hook when removed.
|
|
19
|
+
*
|
|
20
|
+
* @typeParam T - The entity type this behaviour operates on.
|
|
21
|
+
* Defaults to {@link Entity}; narrow it to {@link DynamicEntity} or
|
|
22
|
+
* {@link Player} when the behaviour needs velocity, speed, etc.
|
|
23
|
+
*
|
|
24
|
+
* @category Behaviours
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
*
|
|
27
|
+
* @example Creating a custom behaviour
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { Behaviour, type Entity } from "gamefoo";
|
|
30
|
+
*
|
|
31
|
+
* class Gravity extends Behaviour<Entity> {
|
|
32
|
+
* readonly type = "gravity";
|
|
33
|
+
*
|
|
34
|
+
* update(deltaTime: number): void {
|
|
35
|
+
* this.owner.y += 9.8 * 60 * deltaTime;
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example Attaching to an entity
|
|
41
|
+
* ```ts
|
|
42
|
+
* const entity = new Player("hero", 100, 100, 32, 32);
|
|
43
|
+
* entity.attachBehaviour(new Gravity(entity));
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @see {@link Entity.attachBehaviour}
|
|
47
|
+
* @see {@link Entity.detachBehaviour}
|
|
48
|
+
*/
|
|
49
|
+
export abstract class Behaviour<T extends Entity = Entity> {
|
|
50
|
+
/**
|
|
51
|
+
* Reference to the entity that owns this behaviour.
|
|
52
|
+
* Available to subclasses for reading and mutating entity state.
|
|
53
|
+
*/
|
|
54
|
+
protected owner: T;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Unique string identifier for this behaviour type.
|
|
58
|
+
*
|
|
59
|
+
* Used as the look-up key in {@link Entity.getBehaviour} and
|
|
60
|
+
* {@link Entity.hasBehaviour}. Must be a compile-time constant
|
|
61
|
+
* (`readonly`).
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* class Gravity extends Behaviour {
|
|
66
|
+
* readonly type = "gravity";
|
|
67
|
+
* // ...
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
abstract readonly type: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Execution priority — lower numbers run first.
|
|
75
|
+
*
|
|
76
|
+
* When an entity has multiple behaviours, they are sorted by priority
|
|
77
|
+
* before each update/render pass.
|
|
78
|
+
*
|
|
79
|
+
* @defaultValue `1`
|
|
80
|
+
*/
|
|
81
|
+
public priority: number = 1;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Whether this behaviour is currently active.
|
|
85
|
+
*
|
|
86
|
+
* Disabled behaviours are skipped during both
|
|
87
|
+
* {@link Entity.updateBehaviours} and {@link Entity.renderBehaviours}.
|
|
88
|
+
*
|
|
89
|
+
* @defaultValue `true`
|
|
90
|
+
*/
|
|
91
|
+
public enabled: boolean = true;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Derived look-up key, equal to {@link Behaviour.type} in lowercase.
|
|
95
|
+
*
|
|
96
|
+
* Used internally by the entity's behaviour map so that look-ups are
|
|
97
|
+
* case-insensitive.
|
|
98
|
+
*/
|
|
99
|
+
get key(): string {
|
|
100
|
+
return this.type.toLowerCase();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a new behaviour bound to the given entity.
|
|
105
|
+
*
|
|
106
|
+
* @param owner - The entity this behaviour will operate on.
|
|
107
|
+
*/
|
|
108
|
+
constructor(owner: T) {
|
|
109
|
+
this.owner = owner;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Called once per frame to advance this behaviour's logic.
|
|
114
|
+
*
|
|
115
|
+
* @param deltaTime - Seconds elapsed since the previous frame.
|
|
116
|
+
*/
|
|
117
|
+
abstract update(deltaTime: number): void;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Optional rendering hook invoked after the entity's own
|
|
121
|
+
* {@link Entity.render} call.
|
|
122
|
+
*
|
|
123
|
+
* Override this to draw debug shapes, health bars, status effects, etc.
|
|
124
|
+
*
|
|
125
|
+
* @param ctx - The canvas 2-D rendering context.
|
|
126
|
+
*/
|
|
127
|
+
render?(ctx: CanvasRenderingContext2D): void;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Lifecycle hook called immediately after the behaviour is attached
|
|
131
|
+
* to an entity via {@link Entity.attachBehaviour}.
|
|
132
|
+
*
|
|
133
|
+
* Use this for one-time setup such as registering with the
|
|
134
|
+
* collision {@link World}.
|
|
135
|
+
*/
|
|
136
|
+
onAttach?(): void;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Lifecycle hook called when the behaviour is removed from an entity
|
|
140
|
+
* via {@link Entity.detachBehaviour}.
|
|
141
|
+
*
|
|
142
|
+
* Use this to unregister from external systems or release resources.
|
|
143
|
+
*/
|
|
144
|
+
onDetach?(): void;
|
|
145
|
+
}
|