kiwiengine 0.0.1-alpha

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.
Files changed (145) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -0
  3. package/assets/logo.png +0 -0
  4. package/examples/package.json +13 -0
  5. package/examples/test-dom/index.html +24 -0
  6. package/examples/test-dom/index.ts +21 -0
  7. package/examples/tsconfig.json +22 -0
  8. package/examples/webpack.config.js +31 -0
  9. package/lib/asset/audio.js +158 -0
  10. package/lib/asset/audio.js.map +1 -0
  11. package/lib/asset/loaders/audio.js +35 -0
  12. package/lib/asset/loaders/audio.js.map +1 -0
  13. package/lib/asset/loaders/binary.js +28 -0
  14. package/lib/asset/loaders/binary.js.map +1 -0
  15. package/lib/asset/loaders/font.js +27 -0
  16. package/lib/asset/loaders/font.js.map +1 -0
  17. package/lib/asset/loaders/loader.js +37 -0
  18. package/lib/asset/loaders/loader.js.map +1 -0
  19. package/lib/asset/loaders/spritesheet.js +56 -0
  20. package/lib/asset/loaders/spritesheet.js.map +1 -0
  21. package/lib/asset/loaders/text.js +27 -0
  22. package/lib/asset/loaders/text.js.map +1 -0
  23. package/lib/asset/loaders/texture.js +38 -0
  24. package/lib/asset/loaders/texture.js.map +1 -0
  25. package/lib/asset/preload.js +69 -0
  26. package/lib/asset/preload.js.map +1 -0
  27. package/lib/game-object/game-object-physics.js +188 -0
  28. package/lib/game-object/game-object-physics.js.map +1 -0
  29. package/lib/game-object/game-object-rendering.js +35 -0
  30. package/lib/game-object/game-object-rendering.js.map +1 -0
  31. package/lib/game-object/game-object.js +162 -0
  32. package/lib/game-object/game-object.js.map +1 -0
  33. package/lib/game-object/transform.js +118 -0
  34. package/lib/game-object/transform.js.map +1 -0
  35. package/lib/game-object-ext/animated-sprite.js +117 -0
  36. package/lib/game-object-ext/animated-sprite.js.map +1 -0
  37. package/lib/game-object-ext/dom-container.js +56 -0
  38. package/lib/game-object-ext/dom-container.js.map +1 -0
  39. package/lib/game-object-ext/rect.js +30 -0
  40. package/lib/game-object-ext/rect.js.map +1 -0
  41. package/lib/game-object-ext/spine.js +206 -0
  42. package/lib/game-object-ext/spine.js.map +1 -0
  43. package/lib/game-object-ext/sprite.js +46 -0
  44. package/lib/game-object-ext/sprite.js.map +1 -0
  45. package/lib/game-object-ext/text.js +68 -0
  46. package/lib/game-object-ext/text.js.map +1 -0
  47. package/lib/game-object-ext/tiling-sprite.js +64 -0
  48. package/lib/game-object-ext/tiling-sprite.js.map +1 -0
  49. package/lib/index.js +13 -0
  50. package/lib/index.js.map +1 -0
  51. package/lib/types/asset/audio.d.ts +21 -0
  52. package/lib/types/asset/audio.d.ts.map +1 -0
  53. package/lib/types/asset/loaders/audio.d.ts +7 -0
  54. package/lib/types/asset/loaders/audio.d.ts.map +1 -0
  55. package/lib/types/asset/loaders/binary.d.ts +7 -0
  56. package/lib/types/asset/loaders/binary.d.ts.map +1 -0
  57. package/lib/types/asset/loaders/font.d.ts +7 -0
  58. package/lib/types/asset/loaders/font.d.ts.map +1 -0
  59. package/lib/types/asset/loaders/loader.d.ts +13 -0
  60. package/lib/types/asset/loaders/loader.d.ts.map +1 -0
  61. package/lib/types/asset/loaders/spritesheet.d.ts +11 -0
  62. package/lib/types/asset/loaders/spritesheet.d.ts.map +1 -0
  63. package/lib/types/asset/loaders/text.d.ts +7 -0
  64. package/lib/types/asset/loaders/text.d.ts.map +1 -0
  65. package/lib/types/asset/loaders/texture.d.ts +9 -0
  66. package/lib/types/asset/loaders/texture.d.ts.map +1 -0
  67. package/lib/types/asset/preload.d.ts +8 -0
  68. package/lib/types/asset/preload.d.ts.map +1 -0
  69. package/lib/types/game-object/game-object-physics.d.ts +42 -0
  70. package/lib/types/game-object/game-object-physics.d.ts.map +1 -0
  71. package/lib/types/game-object/game-object-rendering.d.ts +15 -0
  72. package/lib/types/game-object/game-object-rendering.d.ts.map +1 -0
  73. package/lib/types/game-object/game-object.d.ts +81 -0
  74. package/lib/types/game-object/game-object.d.ts.map +1 -0
  75. package/lib/types/game-object/transform.d.ts +43 -0
  76. package/lib/types/game-object/transform.d.ts.map +1 -0
  77. package/lib/types/game-object-ext/animated-sprite.d.ts +29 -0
  78. package/lib/types/game-object-ext/animated-sprite.d.ts.map +1 -0
  79. package/lib/types/game-object-ext/dom-container.d.ts +16 -0
  80. package/lib/types/game-object-ext/dom-container.d.ts.map +1 -0
  81. package/lib/types/game-object-ext/rect.d.ts +17 -0
  82. package/lib/types/game-object-ext/rect.d.ts.map +1 -0
  83. package/lib/types/game-object-ext/spine.d.ts +35 -0
  84. package/lib/types/game-object-ext/spine.d.ts.map +1 -0
  85. package/lib/types/game-object-ext/sprite.d.ts +14 -0
  86. package/lib/types/game-object-ext/sprite.d.ts.map +1 -0
  87. package/lib/types/game-object-ext/text.d.ts +26 -0
  88. package/lib/types/game-object-ext/text.d.ts.map +1 -0
  89. package/lib/types/game-object-ext/tiling-sprite.d.ts +20 -0
  90. package/lib/types/game-object-ext/tiling-sprite.d.ts.map +1 -0
  91. package/lib/types/index.d.ts +14 -0
  92. package/lib/types/index.d.ts.map +1 -0
  93. package/lib/types/utils/debug.d.ts +3 -0
  94. package/lib/types/utils/debug.d.ts.map +1 -0
  95. package/lib/types/utils/go.d.ts +26 -0
  96. package/lib/types/utils/go.d.ts.map +1 -0
  97. package/lib/types/world/world-debug.d.ts +11 -0
  98. package/lib/types/world/world-debug.d.ts.map +1 -0
  99. package/lib/types/world/world-physics.d.ts +16 -0
  100. package/lib/types/world/world-physics.d.ts.map +1 -0
  101. package/lib/types/world/world-rendering.d.ts +28 -0
  102. package/lib/types/world/world-rendering.d.ts.map +1 -0
  103. package/lib/types/world/world.d.ts +38 -0
  104. package/lib/types/world/world.d.ts.map +1 -0
  105. package/lib/utils/debug.js +5 -0
  106. package/lib/utils/debug.js.map +1 -0
  107. package/lib/utils/go.js +33 -0
  108. package/lib/utils/go.js.map +1 -0
  109. package/lib/world/world-debug.js +89 -0
  110. package/lib/world/world-debug.js.map +1 -0
  111. package/lib/world/world-physics.js +45 -0
  112. package/lib/world/world-physics.js.map +1 -0
  113. package/lib/world/world-rendering.js +123 -0
  114. package/lib/world/world-rendering.js.map +1 -0
  115. package/lib/world/world.js +147 -0
  116. package/lib/world/world.js.map +1 -0
  117. package/package.json +23 -0
  118. package/src/asset/audio.ts +176 -0
  119. package/src/asset/loaders/audio.ts +39 -0
  120. package/src/asset/loaders/binary.ts +32 -0
  121. package/src/asset/loaders/font.ts +27 -0
  122. package/src/asset/loaders/loader.ts +39 -0
  123. package/src/asset/loaders/spritesheet.ts +67 -0
  124. package/src/asset/loaders/text.ts +31 -0
  125. package/src/asset/loaders/texture.ts +46 -0
  126. package/src/asset/preload.ts +76 -0
  127. package/src/game-object/game-object-physics.ts +191 -0
  128. package/src/game-object/game-object-rendering.ts +27 -0
  129. package/src/game-object/game-object.ts +190 -0
  130. package/src/game-object/transform.ts +164 -0
  131. package/src/game-object-ext/animated-sprite.ts +140 -0
  132. package/src/game-object-ext/dom-container.ts +67 -0
  133. package/src/game-object-ext/rect.ts +40 -0
  134. package/src/game-object-ext/spine.ts +235 -0
  135. package/src/game-object-ext/sprite.ts +55 -0
  136. package/src/game-object-ext/text.ts +83 -0
  137. package/src/game-object-ext/tiling-sprite.ts +73 -0
  138. package/src/index.ts +14 -0
  139. package/src/utils/debug.ts +5 -0
  140. package/src/utils/go.ts +53 -0
  141. package/src/world/world-debug.ts +114 -0
  142. package/src/world/world-physics.ts +52 -0
  143. package/src/world/world-rendering.ts +145 -0
  144. package/src/world/world.ts +171 -0
  145. package/tsconfig.json +33 -0
@@ -0,0 +1,5 @@
1
+ export let debugMode = false;
2
+
3
+ export function enableDebug() {
4
+ debugMode = true;
5
+ }
@@ -0,0 +1,53 @@
1
+ import { AnimatedSpriteObject } from '../game-object-ext/animated-sprite';
2
+ import { DomContainerObject } from '../game-object-ext/dom-container';
3
+ import { RectangleObject } from '../game-object-ext/rect';
4
+ import { SpineObject } from '../game-object-ext/spine';
5
+ import { SpriteObject } from '../game-object-ext/sprite';
6
+ import { TextObject } from '../game-object-ext/text';
7
+ import { TilingSpriteObject } from '../game-object-ext/tiling-sprite';
8
+ import { GameObject } from '../game-object/game-object';
9
+
10
+ const GameObjectClassMap = {
11
+ 'go': GameObject,
12
+ 'sprite': SpriteObject,
13
+ 'animated-sprite': AnimatedSpriteObject,
14
+ 'tiling-sprite': TilingSpriteObject,
15
+ 'spine': SpineObject,
16
+ 'dom': DomContainerObject,
17
+ 'text': TextObject,
18
+ 'rect': RectangleObject,
19
+ } as const;
20
+
21
+ type GameObjectNameMap = {
22
+ [K in keyof typeof GameObjectClassMap]: InstanceType<(typeof GameObjectClassMap)[K]>;
23
+ };
24
+
25
+ type Name = '' | keyof GameObjectNameMap;
26
+
27
+ type GameObjectByName<T extends Name> = (
28
+ T extends '' ? GameObject
29
+ : (
30
+ T extends keyof GameObjectNameMap ? GameObjectNameMap[T]
31
+ : GameObject
32
+ )
33
+ );
34
+
35
+ function go<T extends Name>(
36
+ name: T = '' as T,
37
+ ...args: (GameObjectByName<T> | Partial<GameObjectByName<T>>)[]
38
+ ): GameObjectByName<T> {
39
+ const go = new GameObjectClassMap[(name || 'go') as keyof GameObjectNameMap]();
40
+
41
+ for (const arg of args) {
42
+ if (arg instanceof GameObject) go.add(arg);
43
+ else if (arg) {
44
+ for (const key in arg) {
45
+ (go as any)[key] = arg[key];
46
+ }
47
+ }
48
+ }
49
+
50
+ return go as GameObjectByName<T>;
51
+ }
52
+
53
+ export { go };
@@ -0,0 +1,114 @@
1
+ import Matter from 'matter-js';
2
+ import Stats from 'stats.js';
3
+ import { debugMode } from '../utils/debug';
4
+
5
+ export class WorldDebug {
6
+ #container: HTMLElement;
7
+ #stats?: Stats;
8
+ #matterDebugRenderer?: Matter.Render;
9
+
10
+ constructor(container: HTMLElement) {
11
+ this.#container = container;
12
+
13
+ if (debugMode) {
14
+ const stats = new Stats();
15
+ stats.dom.style.position = 'absolute';
16
+ stats.showPanel(0);
17
+ container.appendChild(stats.dom);
18
+ this.#stats = stats;
19
+ }
20
+ }
21
+
22
+ update() {
23
+ this.#stats?.update();
24
+ }
25
+
26
+ createMatterDebugRenderer(engine: Matter.Engine, width: number, height: number) {
27
+ if (debugMode) {
28
+ const matterDebugRenderer = Matter.Render.create({
29
+ element: this.#container,
30
+ engine,
31
+ options: {
32
+ width,
33
+ height,
34
+ background: 'transparent',
35
+ wireframes: false,
36
+ showCollisions: true,
37
+ pixelRatio: window.devicePixelRatio,
38
+ },
39
+ });
40
+ this.#matterDebugRenderer = matterDebugRenderer;
41
+
42
+ const debugCanvas = matterDebugRenderer.canvas;
43
+ debugCanvas.style.position = 'absolute';
44
+ debugCanvas.style.zIndex = '1';
45
+ debugCanvas.style.touchAction = 'auto';
46
+ Matter.Render.run(matterDebugRenderer);
47
+
48
+ if (this.#lastRect) this.setMatterDebugRendererSize(this.#lastRect, this.#lastWidth, this.#lastHeight, this.#lastCameraX, this.#lastCameraY);
49
+ }
50
+ }
51
+
52
+ #lastRect?: DOMRectReadOnly;
53
+ #lastWidth = 0;
54
+ #lastHeight = 0;
55
+ #lastCameraX = 0;
56
+ #lastCameraY = 0;
57
+
58
+ setMatterDebugRendererSize(
59
+ rect: DOMRectReadOnly,
60
+ width: number,
61
+ height: number,
62
+ cameraX: number,
63
+ cameraY: number,
64
+ ) {
65
+ this.#lastRect = rect;
66
+ this.#lastWidth = width;
67
+ this.#lastHeight = height;
68
+ this.#lastCameraX = cameraX;
69
+ this.#lastCameraY = cameraY;
70
+
71
+ if (!debugMode || !this.#matterDebugRenderer) return;
72
+
73
+ const r = this.#matterDebugRenderer;
74
+ const pr = window.devicePixelRatio || 1;
75
+
76
+ r.options.width = width;
77
+ r.options.height = height;
78
+
79
+ r.canvas.width = Math.max(1, Math.floor(width * pr));
80
+ r.canvas.height = Math.max(1, Math.floor(height * pr));
81
+
82
+ const scale = Math.min(rect.width / width, rect.height / height);
83
+
84
+ const displayW = width * scale;
85
+ const displayH = height * scale;
86
+
87
+ const left = (rect.width - displayW) / 2;
88
+ const top = (rect.height - displayH) / 2;
89
+
90
+ r.canvas.style.width = `${displayW}px`;
91
+ r.canvas.style.height = `${displayH}px`;
92
+ r.canvas.style.left = `${left}px`;
93
+ r.canvas.style.top = `${top}px`;
94
+
95
+ this.setMatterDebugRendererCamera(cameraX, cameraY);
96
+ }
97
+
98
+ setMatterDebugRendererCamera(cameraX: number, cameraY: number) {
99
+ if (this.#matterDebugRenderer) {
100
+ const r = this.#matterDebugRenderer;
101
+ const halfW = this.#lastWidth / 2;
102
+ const halfH = this.#lastHeight / 2;
103
+
104
+ r.bounds.min.x = cameraX - halfW;
105
+ r.bounds.min.y = cameraY - halfH;
106
+ r.bounds.max.x = cameraX + halfW;
107
+ r.bounds.max.y = cameraY + halfH;
108
+
109
+ Matter.Render.lookAt(r, r.bounds);
110
+ }
111
+ }
112
+
113
+ destroy() { }
114
+ }
@@ -0,0 +1,52 @@
1
+ import { EventEmitter } from '@webtaku/event-emitter';
2
+ import Matter from 'matter-js';
3
+ import { GameObject } from '../game-object/game-object';
4
+
5
+ export class WorldPhysics extends EventEmitter<{
6
+ engineCreated: (engine: Matter.Engine) => void;
7
+ collisionStart: (a: GameObject, b: GameObject) => void;
8
+ }> {
9
+ #engine?: Matter.Engine;
10
+ #gravity = 0;
11
+
12
+ get gravity() { return this.#gravity; }
13
+ set gravity(v: number) {
14
+ this.#gravity = v;
15
+ if (this.#engine) this.#engine.gravity.y = v;
16
+ }
17
+
18
+ #createEngine() {
19
+ this.#engine = Matter.Engine.create();
20
+ this.#engine.gravity.y = this.#gravity;
21
+
22
+ Matter.Events.on(this.#engine, 'collisionStart', (event) => {
23
+ event.pairs.forEach((pair) => {
24
+ const { bodyA, bodyB } = pair;
25
+ this.emit('collisionStart', bodyA.plugin.owner, bodyB.plugin.owner);
26
+ });
27
+ });
28
+
29
+ this.emit('engineCreated', this.#engine);
30
+ }
31
+
32
+ addBody(body: Matter.Body) {
33
+ if (!this.#engine) this.#createEngine();
34
+ Matter.World.add(this.#engine!.world, body);
35
+ }
36
+
37
+ removeBody(body: Matter.Body) {
38
+ if (!this.#engine) return;
39
+ Matter.World.remove(this.#engine!.world, body);
40
+ }
41
+
42
+ update(dt: number) {
43
+ if (!this.#engine) return;
44
+ const matterDt = dt * 1000;
45
+ Matter.Engine.update(this.#engine, matterDt > 16.666 ? 16.666 : matterDt);
46
+ }
47
+
48
+ destroy() {
49
+ if (this.#engine) Matter.Engine.clear(this.#engine);
50
+ this.#engine = undefined;
51
+ }
52
+ }
@@ -0,0 +1,145 @@
1
+ import { autoDetectRenderer, Container, EventEmitter, Renderer, Sprite } from "pixi.js";
2
+ import { textureLoader } from '../asset/loaders/texture';
3
+
4
+ export class WorldRendering extends EventEmitter<{
5
+ positionChanged: () => void;
6
+ }> {
7
+ #renderer?: Renderer;
8
+ #root = new Container();
9
+ #backgroundAlpha = 1;
10
+
11
+ #cameraX = 0;
12
+ #cameraY = 0;
13
+
14
+ centerX = 0;
15
+ centerY = 0;
16
+ renderWidth = 0;
17
+ renderHeight = 0;
18
+ renderScale = 1;
19
+ canvasLeft = 0;
20
+ canvasTop = 0;
21
+
22
+ #backgroundColor = 0x304C79;
23
+ get backgroundColor() { return this.#backgroundColor; }
24
+ set backgroundColor(v: number) {
25
+ this.#backgroundColor = v;
26
+ if (this.#renderer) this.#renderer.background.color = v;
27
+ }
28
+
29
+ get backgroundAlpha() { return this.#backgroundAlpha; }
30
+ set backgroundAlpha(v: number) {
31
+ this.#backgroundAlpha = v;
32
+ if (this.#renderer) this.#renderer.background.alpha = v;
33
+ }
34
+
35
+ async init(container: HTMLElement, width: number | undefined, height: number | undefined) {
36
+ const renderer = await autoDetectRenderer({
37
+ width,
38
+ height,
39
+ backgroundColor: this.#backgroundColor,
40
+ backgroundAlpha: this.#backgroundAlpha,
41
+ eventMode: 'none',
42
+ resolution: window.devicePixelRatio,
43
+ });
44
+ this.#renderer = renderer;
45
+
46
+ const canvas = renderer.canvas;
47
+ canvas.style.position = 'absolute';
48
+ canvas.style.touchAction = 'auto';
49
+ canvas.style.borderRadius = container.style.borderRadius;
50
+ container.appendChild(canvas);
51
+
52
+ if (this.#lastRect) this.setRendererSize(this.#lastRect, this.#lastWidth, this.#lastHeight);
53
+ }
54
+
55
+ #applyPosition() {
56
+ this.#root.x = this.centerX - this.#cameraX;
57
+ this.#root.y = this.centerY - this.#cameraY;
58
+
59
+ if (this.#backgroundSprite) {
60
+ this.#backgroundSprite.x = this.#cameraX;
61
+ this.#backgroundSprite.y = this.#cameraY;
62
+ }
63
+
64
+ this.emit('positionChanged');
65
+ }
66
+
67
+ #lastRect?: DOMRect;
68
+ #lastWidth = 0;
69
+ #lastHeight = 0;
70
+
71
+ setRendererSize(rect: DOMRect, width: number, height: number) {
72
+ this.#lastRect = rect;
73
+ this.#lastWidth = width;
74
+ this.#lastHeight = height;
75
+
76
+ this.centerX = width / 2;
77
+ this.centerY = height / 2;
78
+ this.#applyPosition();
79
+
80
+ this.renderWidth = width;
81
+ this.renderHeight = height;
82
+
83
+ const scale = Math.min(rect.width / width, rect.height / height);
84
+ this.renderScale = scale;
85
+
86
+ const displayW = width * scale;
87
+ const displayH = height * scale;
88
+
89
+ const left = (rect.width - displayW) / 2;
90
+ const top = (rect.height - displayH) / 2;
91
+ this.canvasLeft = left;
92
+ this.canvasTop = top;
93
+
94
+ if (!this.#renderer) return;
95
+ this.#renderer.resize(width, height);
96
+
97
+ const canvas = this.#renderer.canvas;
98
+ canvas.style.width = `${displayW}px`;
99
+ canvas.style.height = `${displayH}px`;
100
+ canvas.style.left = `${left}px`;
101
+ canvas.style.top = `${top}px`;
102
+ }
103
+
104
+ update() {
105
+ this.#renderer?.render(this.#root);
106
+ }
107
+
108
+ get cameraX() { return this.#cameraX; }
109
+ set cameraX(value: number) { this.#cameraX = value; this.#applyPosition(); }
110
+ get cameraY() { return this.#cameraY; }
111
+ set cameraY(value: number) { this.#cameraY = value; this.#applyPosition(); }
112
+
113
+ addPixiChildToRoot(child: Container) {
114
+ this.#root.addChild(child);
115
+ }
116
+
117
+ destroy() {
118
+ this.#renderer?.destroy();
119
+ this.#renderer = undefined;
120
+ }
121
+
122
+ #backgroundSprite?: Sprite;
123
+ setBackgroundImage(image: string | undefined) {
124
+ if (image) {
125
+ if (!textureLoader.checkLoaded(image)) {
126
+ console.info(`Background image not preloaded. Loading now: ${image}`);
127
+ }
128
+ textureLoader.load(image).then((texture) => {
129
+ if (texture) {
130
+ this.#backgroundSprite?.destroy();
131
+ this.#backgroundSprite = new Sprite({
132
+ x: this.#cameraX,
133
+ y: this.#cameraY,
134
+ texture,
135
+ anchor: { x: 0.5, y: 0.5 },
136
+ width: this.renderWidth,
137
+ height: this.renderHeight,
138
+ zIndex: -999999,
139
+ });
140
+ this.#root.addChild(this.#backgroundSprite);
141
+ }
142
+ });
143
+ }
144
+ }
145
+ }
@@ -0,0 +1,171 @@
1
+ import { GameObject, GameObjectOptions } from '../game-object/game-object';
2
+ import { WorldTransform } from '../game-object/transform';
3
+ import { debugMode } from '../utils/debug';
4
+ import { WorldDebug } from './world-debug';
5
+ import { WorldPhysics } from "./world-physics";
6
+ import { WorldRendering } from "./world-rendering";
7
+
8
+ export type WorldOptions = {
9
+ width?: number;
10
+ height?: number;
11
+ backgroundColor?: number;
12
+ backgroundAlpha?: number;
13
+ gravity?: number;
14
+ } & GameObjectOptions;
15
+
16
+ export class World extends GameObject<{
17
+ resize: (width: number, height: number) => void;
18
+ collisionStart: (a: GameObject, b: GameObject) => void;
19
+ }> {
20
+ container = document.createElement('div');
21
+ #containerResizeObserver: ResizeObserver;
22
+
23
+ _worldRendering = new WorldRendering();
24
+ _worldPhysics = new WorldPhysics();
25
+ #worldDebug = new WorldDebug(this.container);
26
+
27
+ #width?: number;
28
+ #height?: number;
29
+
30
+ #hasEverBeenConnected = false;
31
+ #destroyed = false;
32
+
33
+ #pt = new WorldTransform();
34
+ #update(dt: number) {
35
+ if (this.container.isConnected) {
36
+ if (!this.#hasEverBeenConnected) {
37
+ this.#hasEverBeenConnected = true;
38
+ this.#applySize();
39
+ }
40
+
41
+ this._worldPhysics.update(dt);
42
+ this._engineUpdate(dt, this.#pt);
43
+ this._worldRendering.update();
44
+ this.#worldDebug.update();
45
+
46
+ this._containerSizeDirty = false;
47
+ }
48
+
49
+ else if (this.#hasEverBeenConnected) {
50
+ this.#destroy();
51
+ return;
52
+ }
53
+ }
54
+
55
+ #lastContainerW = 0;
56
+ #lastContainerH = 0;
57
+ _containerSizeDirty = false;
58
+
59
+ #applySize() {
60
+ const rect = this.container.getBoundingClientRect();
61
+
62
+ if (rect.width === this.#lastContainerW && rect.height === this.#lastContainerH) return;
63
+ this.#lastContainerW = rect.width;
64
+ this.#lastContainerH = rect.height;
65
+ this._containerSizeDirty = true;
66
+
67
+ if (rect.width === 0 || rect.height === 0) return;
68
+
69
+ const canvasWidth = this.#width ?? rect.width;
70
+ const canvasHeight = this.#height ?? rect.height;
71
+
72
+ this._worldRendering.setRendererSize(rect, canvasWidth, canvasHeight);
73
+ this.#worldDebug.setMatterDebugRendererSize(rect, canvasWidth, canvasHeight, this.cameraX, this.cameraY);
74
+
75
+ this.emit('resize', this.width, this.height);
76
+ }
77
+
78
+ #destroy() {
79
+ this.#containerResizeObserver.disconnect();
80
+ this._worldRendering.destroy();
81
+ this._worldPhysics.destroy();
82
+ this.#worldDebug.destroy();
83
+
84
+ this.#destroyed = true;
85
+ }
86
+
87
+ async #init() {
88
+ await this._worldRendering.init(this.container, this.#width, this.#height);
89
+ this.#applySize();
90
+
91
+ let prevTime = 0;
92
+ let lagSeconds = 0;
93
+ let fpsCap: number | undefined;
94
+
95
+ const step = (timestamp: number) => {
96
+ if (this.#destroyed) return;
97
+
98
+ const dt = (timestamp - prevTime) / 1000;
99
+ if (dt > 0) {
100
+ if (fpsCap !== undefined && fpsCap > 0) {
101
+ lagSeconds += dt;
102
+ const fixedStep = 1 / fpsCap;
103
+ if (lagSeconds >= fixedStep) {
104
+ this.#update(fixedStep);
105
+ if (lagSeconds >= fixedStep * 2) { this.#update(dt); lagSeconds = 0; }
106
+ else { lagSeconds -= fixedStep; }
107
+ }
108
+ } else {
109
+ this.#update(dt);
110
+ }
111
+ prevTime = timestamp;
112
+ }
113
+ requestAnimationFrame(step);
114
+ };
115
+ requestAnimationFrame(step);
116
+
117
+ if (debugMode) {
118
+ if (!document.hasFocus()) fpsCap = 6;
119
+ window.addEventListener('blur', () => fpsCap = 6);
120
+ window.addEventListener('focus', () => fpsCap = undefined);
121
+ window.addEventListener('pageshow', (event) => { if (event.persisted) fpsCap = undefined; });
122
+ }
123
+ }
124
+
125
+ constructor(opts?: WorldOptions) {
126
+ super(opts);
127
+ this._setWorld(this);
128
+ this._worldRendering.addPixiChildToRoot(this._rendering._container);
129
+
130
+ this.#containerResizeObserver = new ResizeObserver(this.#applySize.bind(this));
131
+ this.#containerResizeObserver.observe(this.container);
132
+
133
+ this._worldRendering.on('positionChanged', () => this.#worldDebug.setMatterDebugRendererCamera(this.cameraX, this.cameraY));
134
+ this._worldPhysics.on('engineCreated', (engine) => this.#worldDebug.createMatterDebugRenderer(engine, this.width, this.height));
135
+ this._worldPhysics.on('collisionStart', (a, b) => this.emit('collisionStart', a, b));
136
+ ``
137
+ if (opts) {
138
+ if (opts.width !== undefined) this.#width = opts.width;
139
+ if (opts.height !== undefined) this.#height = opts.height;
140
+ if (opts.backgroundColor !== undefined) this.backgroundColor = opts.backgroundColor;
141
+ if (opts.backgroundAlpha !== undefined) this.backgroundAlpha = opts.backgroundAlpha;
142
+ if (opts.gravity !== undefined) this.gravity = opts.gravity;
143
+ }
144
+
145
+ this.#init();
146
+ }
147
+
148
+ get width() { return this.#width ?? this._worldRendering.renderWidth; }
149
+ set width(v: number) { this.#width = v; this.#applySize(); }
150
+ get height() { return this.#height ?? this._worldRendering.renderHeight; }
151
+ set height(v: number) { this.#height = v; this.#applySize(); }
152
+
153
+ get backgroundColor() { return this._worldRendering.backgroundColor; }
154
+ set backgroundColor(v: number) { this._worldRendering.backgroundColor = v; }
155
+ get backgroundAlpha() { return this._worldRendering.backgroundAlpha; }
156
+ set backgroundAlpha(v: number) { this._worldRendering.backgroundAlpha = v; }
157
+ get gravity() { return this._worldPhysics.gravity; }
158
+ set gravity(v: number) { this._worldPhysics.gravity = v; }
159
+
160
+ get cameraX() { return this._worldRendering.cameraX; }
161
+ set cameraX(v: number) { this._worldRendering.cameraX = v; }
162
+ get cameraY() { return this._worldRendering.cameraY; }
163
+ set cameraY(v: number) { this._worldRendering.cameraY = v; }
164
+
165
+ #backgroundImage?: string;
166
+ get backgroundImage() { return this.#backgroundImage; }
167
+ set backgroundImage(image: string | undefined) {
168
+ this.#backgroundImage = image;
169
+ this._worldRendering.setBackgroundImage(image);
170
+ }
171
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "noImplicitAny": true,
6
+ "preserveConstEnums": true,
7
+ "inlineSources": true,
8
+ "sourceMap": true,
9
+ "esModuleInterop": true,
10
+ "lib": [
11
+ "DOM",
12
+ "ESNext",
13
+ "ScriptHost"
14
+ ],
15
+ "declaration": true,
16
+ "declarationDir": "lib/types",
17
+ "declarationMap": true,
18
+ "composite": true,
19
+ "moduleResolution": "node",
20
+ "skipLibCheck": true,
21
+ "strict": true,
22
+ "rootDir": "./src",
23
+ "outDir": "lib"
24
+ },
25
+ "include": [
26
+ "./src",
27
+ ],
28
+ "exclude": [
29
+ "node_modules",
30
+ "**/lib/**",
31
+ "examples"
32
+ ],
33
+ }