minimojs 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (55) hide show
  1. package/README.md +82 -285
  2. package/dist/internal/AnimationSystem.js +345 -0
  3. package/dist/internal/AssetSystem.d.ts +1 -0
  4. package/dist/internal/AssetSystem.js +101 -0
  5. package/dist/internal/BackgroundSystem.d.ts +1 -0
  6. package/dist/internal/BackgroundSystem.js +26 -0
  7. package/dist/internal/CanvasSystem.d.ts +1 -0
  8. package/dist/internal/CanvasSystem.js +51 -0
  9. package/dist/internal/ExplosionSystem.d.ts +1 -0
  10. package/dist/internal/ExplosionSystem.js +540 -0
  11. package/dist/internal/InputSystem.d.ts +1 -0
  12. package/dist/internal/InputSystem.js +265 -0
  13. package/dist/internal/LoopSystem.d.ts +1 -0
  14. package/dist/internal/LoopSystem.js +61 -0
  15. package/dist/internal/PhysicsSystem.d.ts +1 -0
  16. package/dist/internal/PhysicsSystem.js +174 -0
  17. package/dist/internal/RenderSystem.d.ts +1 -0
  18. package/dist/internal/RenderSystem.js +910 -0
  19. package/dist/internal/SoundSystem.d.ts +1 -0
  20. package/dist/internal/SoundSystem.js +55 -0
  21. package/dist/internal/SpriteSystem.d.ts +1 -0
  22. package/dist/internal/SpriteSystem.js +32 -0
  23. package/dist/internal/TextSystem.d.ts +1 -0
  24. package/dist/internal/TextSystem.js +16 -0
  25. package/dist/internal/TimerSystem.d.ts +1 -0
  26. package/dist/internal/TimerSystem.js +43 -0
  27. package/dist/internal/TrailSystem.d.ts +1 -0
  28. package/dist/internal/TrailSystem.js +116 -0
  29. package/dist/internal/TransitionSystem.d.ts +1 -0
  30. package/dist/internal/TransitionSystem.js +74 -0
  31. package/dist/internal/arcade-racer/ArcadeRacerCollisionSystem.d.ts +1 -0
  32. package/dist/internal/arcade-racer/ArcadeRacerCollisionSystem.js +198 -0
  33. package/dist/internal/arcade-racer/ArcadeRacerLaneSystem.d.ts +1 -0
  34. package/dist/internal/arcade-racer/ArcadeRacerLaneSystem.js +120 -0
  35. package/dist/internal/arcade-racer/ArcadeRacerRenderSystem.d.ts +1 -0
  36. package/dist/internal/arcade-racer/ArcadeRacerRenderSystem.js +599 -0
  37. package/dist/internal/arcade-racer/ArcadeRacerRoadSprite.d.ts +1 -0
  38. package/dist/internal/arcade-racer/ArcadeRacerRoadSprite.js +13 -0
  39. package/dist/internal/arcade-racer/ArcadeRacerTrackSystem.d.ts +1 -0
  40. package/dist/internal/arcade-racer/ArcadeRacerTrackSystem.js +447 -0
  41. package/dist/minimo-arcaderacer.d.ts +1431 -0
  42. package/dist/minimo-arcaderacer.js +2060 -0
  43. package/dist/minimo.d.ts +1412 -162
  44. package/dist/minimo.js +2083 -816
  45. package/package.json +3 -2
  46. package/dist/animations.js +0 -30
  47. package/dist/audio.js +0 -17
  48. package/dist/game.js +0 -1105
  49. package/dist/input.js +0 -185
  50. package/dist/internal-types.js +0 -4
  51. package/dist/physics.js +0 -10
  52. package/dist/render.js +0 -75
  53. package/dist/sprite.js +0 -149
  54. package/dist/timers.js +0 -23
  55. /package/dist/{pointer-info.js → internal/AnimationSystem.d.ts} +0 -0
@@ -0,0 +1,265 @@
1
+ /** @internal */
2
+ export class InputSystem {
3
+ constructor(
4
+ /** @internal */ game,
5
+ /** @internal */ canvas) {
6
+ this.game = game;
7
+ this.canvas = canvas;
8
+ /** @internal */
9
+ this._keysDown = new Set();
10
+ /** @internal */
11
+ this._keysPressed = new Set();
12
+ /** @internal */
13
+ this._pointerDown = false;
14
+ /** @internal */
15
+ this._pointerPressed = false;
16
+ /** @internal */
17
+ this._pointerX = 0;
18
+ /** @internal */
19
+ this._pointerY = 0;
20
+ /** @internal */
21
+ this._mouseDown = false;
22
+ /** @internal */
23
+ this._mousePressed = false;
24
+ /** @internal */
25
+ this._mouseX = 0;
26
+ /** @internal */
27
+ this._mouseY = 0;
28
+ /** @internal */
29
+ this._touchPointers = new Map();
30
+ /** @internal */
31
+ this._primaryTouchId = null;
32
+ }
33
+ get pointerX() {
34
+ return this._pointerX;
35
+ }
36
+ get pointerY() {
37
+ return this._pointerY;
38
+ }
39
+ bindInputEvents() {
40
+ window.addEventListener("keydown", (e) => {
41
+ if (!this._keysDown.has(e.key)) {
42
+ this._keysPressed.add(e.key);
43
+ }
44
+ this._keysDown.add(e.key);
45
+ });
46
+ window.addEventListener("keyup", (e) => {
47
+ this._keysDown.delete(e.key);
48
+ });
49
+ this.canvas.addEventListener("mousedown", (e) => {
50
+ const p = this.getCanvasPoint(e.clientX, e.clientY);
51
+ this._mouseX = p.x;
52
+ this._mouseY = p.y;
53
+ this._mouseDown = true;
54
+ this._mousePressed = true;
55
+ this.syncPrimaryPointer();
56
+ });
57
+ this.canvas.addEventListener("mouseup", () => {
58
+ this._mouseDown = false;
59
+ this.syncPrimaryPointer();
60
+ });
61
+ this.canvas.addEventListener("mousemove", (e) => {
62
+ const p = this.getCanvasPoint(e.clientX, e.clientY);
63
+ this._mouseX = p.x;
64
+ this._mouseY = p.y;
65
+ this.syncPrimaryPointer();
66
+ });
67
+ this.canvas.addEventListener("touchstart", (e) => {
68
+ for (const touch of Array.from(e.changedTouches)) {
69
+ const p = this.getCanvasPoint(touch.clientX, touch.clientY);
70
+ this._touchPointers.set(touch.identifier, {
71
+ x: p.x,
72
+ y: p.y,
73
+ pressed: true,
74
+ });
75
+ if (this._primaryTouchId === null) {
76
+ this._primaryTouchId = touch.identifier;
77
+ }
78
+ }
79
+ this.syncPrimaryPointer();
80
+ e.preventDefault();
81
+ }, { passive: false });
82
+ this.canvas.addEventListener("touchend", (e) => {
83
+ for (const touch of Array.from(e.changedTouches)) {
84
+ this._touchPointers.delete(touch.identifier);
85
+ if (this._primaryTouchId === touch.identifier) {
86
+ this._primaryTouchId = null;
87
+ }
88
+ }
89
+ this.syncPrimaryPointer();
90
+ e.preventDefault();
91
+ }, { passive: false });
92
+ this.canvas.addEventListener("touchcancel", (e) => {
93
+ for (const touch of Array.from(e.changedTouches)) {
94
+ this._touchPointers.delete(touch.identifier);
95
+ if (this._primaryTouchId === touch.identifier) {
96
+ this._primaryTouchId = null;
97
+ }
98
+ }
99
+ this.syncPrimaryPointer();
100
+ e.preventDefault();
101
+ }, { passive: false });
102
+ this.canvas.addEventListener("touchmove", (e) => {
103
+ for (const touch of Array.from(e.changedTouches)) {
104
+ const p = this.getCanvasPoint(touch.clientX, touch.clientY);
105
+ const existing = this._touchPointers.get(touch.identifier);
106
+ if (existing) {
107
+ existing.x = p.x;
108
+ existing.y = p.y;
109
+ }
110
+ else {
111
+ this._touchPointers.set(touch.identifier, {
112
+ x: p.x,
113
+ y: p.y,
114
+ pressed: false,
115
+ });
116
+ }
117
+ }
118
+ this.syncPrimaryPointer();
119
+ e.preventDefault();
120
+ }, { passive: false });
121
+ }
122
+ isKeyDown(key) {
123
+ return this._keysDown.has(key);
124
+ }
125
+ isKeyPressed(key) {
126
+ return this._keysPressed.has(key);
127
+ }
128
+ isPointerDown() {
129
+ return this._pointerDown;
130
+ }
131
+ isPointerPressed() {
132
+ return this._pointerPressed;
133
+ }
134
+ isPointerDownOverSprite(sprite) {
135
+ if (!sprite)
136
+ return false;
137
+ if (this._mouseDown &&
138
+ this.isScreenPointOverSprite(this._mouseX, this._mouseY, sprite)) {
139
+ return true;
140
+ }
141
+ for (const pointer of this._touchPointers.values()) {
142
+ if (this.isScreenPointOverSprite(pointer.x, pointer.y, sprite)) {
143
+ return true;
144
+ }
145
+ }
146
+ return false;
147
+ }
148
+ isPointerPressedOverSprite(sprite) {
149
+ if (!sprite)
150
+ return false;
151
+ if (this._mousePressed &&
152
+ this.isScreenPointOverSprite(this._mouseX, this._mouseY, sprite)) {
153
+ return true;
154
+ }
155
+ for (const pointer of this._touchPointers.values()) {
156
+ if (pointer.pressed &&
157
+ this.isScreenPointOverSprite(pointer.x, pointer.y, sprite)) {
158
+ return true;
159
+ }
160
+ }
161
+ return false;
162
+ }
163
+ getPointers() {
164
+ return this.collectPointers();
165
+ }
166
+ getPointersOverSprite(sprite) {
167
+ if (!sprite)
168
+ return [];
169
+ return this.collectPointers().filter((pointer) => this.isScreenPointOverSprite(pointer.x, pointer.y, sprite));
170
+ }
171
+ isMobileDevice() {
172
+ if (typeof navigator === "undefined")
173
+ return false;
174
+ const ua = navigator.userAgent ?? "";
175
+ const mobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile/i.test(ua);
176
+ const iPadOS = navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1;
177
+ const coarsePointer = typeof window !== "undefined" &&
178
+ typeof window.matchMedia === "function" &&
179
+ window.matchMedia("(pointer: coarse)").matches;
180
+ return mobileUA || iPadOS || coarsePointer;
181
+ }
182
+ clearFramePressedState() {
183
+ this._keysPressed.clear();
184
+ this._mousePressed = false;
185
+ for (const pointer of this._touchPointers.values()) {
186
+ pointer.pressed = false;
187
+ }
188
+ this.syncPrimaryPointer();
189
+ }
190
+ resetPressedState() {
191
+ this.clearFramePressedState();
192
+ }
193
+ /** @internal */
194
+ getCanvasPoint(clientX, clientY) {
195
+ const rect = this.canvas.getBoundingClientRect();
196
+ const scaleX = this.canvas.width / rect.width;
197
+ const scaleY = this.canvas.height / rect.height;
198
+ return {
199
+ x: (clientX - rect.left) * scaleX,
200
+ y: (clientY - rect.top) * scaleY,
201
+ };
202
+ }
203
+ /** @internal */
204
+ isScreenPointOverSprite(x, y, sprite) {
205
+ const halfWidth = sprite.displayWidth / 2;
206
+ const halfHeight = sprite.displayHeight / 2;
207
+ const drawX = sprite.ignoreScroll ? sprite.renderX : sprite.renderX - this.game.scrollX;
208
+ const drawY = sprite.ignoreScroll ? sprite.renderY : sprite.renderY - this.game.scrollY;
209
+ return Math.abs(x - drawX) <= halfWidth && Math.abs(y - drawY) <= halfHeight;
210
+ }
211
+ /** @internal */
212
+ collectPointers() {
213
+ const pointers = [];
214
+ if (this._mouseDown) {
215
+ pointers.push({
216
+ id: "mouse",
217
+ kind: "mouse",
218
+ x: this._mouseX,
219
+ y: this._mouseY,
220
+ pressed: this._mousePressed,
221
+ });
222
+ }
223
+ for (const [id, pointer] of this._touchPointers.entries()) {
224
+ pointers.push({
225
+ id,
226
+ kind: "touch",
227
+ x: pointer.x,
228
+ y: pointer.y,
229
+ pressed: pointer.pressed,
230
+ });
231
+ }
232
+ return pointers;
233
+ }
234
+ /** @internal */
235
+ syncPrimaryPointer() {
236
+ if (this._primaryTouchId !== null) {
237
+ const primaryTouch = this._touchPointers.get(this._primaryTouchId);
238
+ if (primaryTouch) {
239
+ this._pointerX = primaryTouch.x;
240
+ this._pointerY = primaryTouch.y;
241
+ this._pointerDown = true;
242
+ this._pointerPressed = primaryTouch.pressed;
243
+ return;
244
+ }
245
+ this._primaryTouchId = null;
246
+ }
247
+ if (this._touchPointers.size > 0) {
248
+ const firstTouchEntry = this._touchPointers.entries().next().value;
249
+ if (firstTouchEntry) {
250
+ const [touchId, touch] = firstTouchEntry;
251
+ this._primaryTouchId = touchId;
252
+ this._pointerX = touch.x;
253
+ this._pointerY = touch.y;
254
+ this._pointerDown = true;
255
+ this._pointerPressed = touch.pressed;
256
+ return;
257
+ }
258
+ }
259
+ this._primaryTouchId = null;
260
+ this._pointerX = this._mouseX;
261
+ this._pointerY = this._mouseY;
262
+ this._pointerDown = this._mouseDown;
263
+ this._pointerPressed = this._mousePressed;
264
+ }
265
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ /** @internal */
2
+ export class LoopSystem {
3
+ constructor(/** @internal */ onFrame) {
4
+ this.onFrame = onFrame;
5
+ /** @internal */
6
+ this._rafId = null;
7
+ /** @internal */
8
+ this._lastTimestamp = null;
9
+ /** @internal */
10
+ this._running = false;
11
+ /** @internal */
12
+ this._hasCreated = false;
13
+ /** @internal */
14
+ this._onCreate = null;
15
+ /** @internal */
16
+ this.loop = (timestamp) => {
17
+ if (!this._running)
18
+ return;
19
+ if (this._lastTimestamp === null) {
20
+ this._lastTimestamp = timestamp;
21
+ }
22
+ let dt = (timestamp - this._lastTimestamp) / 1000;
23
+ this._lastTimestamp = timestamp;
24
+ if (dt > 0.1)
25
+ dt = 0.1;
26
+ this.onFrame(dt, dt * 1000);
27
+ this._rafId = requestAnimationFrame(this.loop);
28
+ };
29
+ }
30
+ get onCreate() {
31
+ return this._onCreate;
32
+ }
33
+ set onCreate(callback) {
34
+ this._onCreate = callback;
35
+ }
36
+ get isRunning() {
37
+ return this._running;
38
+ }
39
+ start() {
40
+ if (this._running)
41
+ return;
42
+ if (!this._hasCreated) {
43
+ this.invokeCreate();
44
+ }
45
+ this._running = true;
46
+ this._lastTimestamp = null;
47
+ this._rafId = requestAnimationFrame(this.loop);
48
+ }
49
+ stop() {
50
+ this._running = false;
51
+ if (this._rafId !== null) {
52
+ cancelAnimationFrame(this._rafId);
53
+ this._rafId = null;
54
+ }
55
+ this._lastTimestamp = null;
56
+ }
57
+ invokeCreate() {
58
+ this._hasCreated = true;
59
+ this._onCreate?.();
60
+ }
61
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,174 @@
1
+ /** @internal */
2
+ export class PhysicsSystem {
3
+ constructor() {
4
+ /** @internal */
5
+ this._gravityX = 0;
6
+ /** @internal */
7
+ this._gravityY = 0;
8
+ /** @internal */
9
+ this._enabled = false;
10
+ }
11
+ get gravityX() {
12
+ return this._gravityX;
13
+ }
14
+ set gravityX(value) {
15
+ this._gravityX = value;
16
+ }
17
+ get gravityY() {
18
+ return this._gravityY;
19
+ }
20
+ set gravityY(value) {
21
+ this._gravityY = value;
22
+ }
23
+ get enabled() {
24
+ return this._enabled;
25
+ }
26
+ set enabled(value) {
27
+ this._enabled = value;
28
+ }
29
+ update(sprites, dt) {
30
+ for (const sprite of sprites) {
31
+ if (sprite.isStatic) {
32
+ continue;
33
+ }
34
+ if (sprite.gravityScale !== 0) {
35
+ sprite.vx += this._gravityX * sprite.gravityScale * dt;
36
+ sprite.vy += this._gravityY * sprite.gravityScale * dt;
37
+ }
38
+ sprite.x += sprite.vx * dt;
39
+ sprite.y += sprite.vy * dt;
40
+ }
41
+ }
42
+ overlap(a, b) {
43
+ const halfWidthA = a.bodyDisplayWidth / 2;
44
+ const halfHeightA = a.bodyDisplayHeight / 2;
45
+ const halfWidthB = b.bodyDisplayWidth / 2;
46
+ const halfHeightB = b.bodyDisplayHeight / 2;
47
+ return (Math.abs(a.bodyCenterX - b.bodyCenterX) < halfWidthA + halfWidthB &&
48
+ Math.abs(a.bodyCenterY - b.bodyCenterY) < halfHeightA + halfHeightB);
49
+ }
50
+ overlapAny(listA, listB) {
51
+ for (const a of listA) {
52
+ for (const b of listB) {
53
+ if (this.overlap(a, b)) {
54
+ return [a, b];
55
+ }
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ collide(a, b) {
61
+ this.assertEnabled();
62
+ if (a === b)
63
+ return null;
64
+ const collision = this.getCollisionResolution(a, b);
65
+ if (!collision)
66
+ return null;
67
+ if (!a.isStatic) {
68
+ a.x += collision.separationX;
69
+ a.y += collision.separationY;
70
+ if (collision.axis === "x") {
71
+ a.vx = 0;
72
+ }
73
+ else {
74
+ a.vy = 0;
75
+ }
76
+ }
77
+ else if (!b.isStatic) {
78
+ b.x -= collision.separationX;
79
+ b.y -= collision.separationY;
80
+ if (collision.axis === "x") {
81
+ b.vx = 0;
82
+ }
83
+ else {
84
+ b.vy = 0;
85
+ }
86
+ }
87
+ return collision.info;
88
+ }
89
+ collideAny(listA, listB) {
90
+ this.assertEnabled();
91
+ for (const a of listA) {
92
+ for (const b of listB) {
93
+ const info = this.collide(a, b);
94
+ if (info)
95
+ return [a, b, info];
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ /** @internal */
101
+ assertEnabled() {
102
+ if (!this._enabled) {
103
+ throw new Error("MinimoJS: collide() and collideAny() require game.physics = true.");
104
+ }
105
+ }
106
+ /** @internal */
107
+ getCollisionResolution(a, b) {
108
+ const halfWidthA = a.bodyDisplayWidth / 2;
109
+ const halfHeightA = a.bodyDisplayHeight / 2;
110
+ const halfWidthB = b.bodyDisplayWidth / 2;
111
+ const halfHeightB = b.bodyDisplayHeight / 2;
112
+ const dx = b.bodyCenterX - a.bodyCenterX;
113
+ const dy = b.bodyCenterY - a.bodyCenterY;
114
+ const overlapX = halfWidthA + halfWidthB - Math.abs(dx);
115
+ const overlapY = halfHeightA + halfHeightB - Math.abs(dy);
116
+ if (overlapX <= 0 || overlapY <= 0) {
117
+ return null;
118
+ }
119
+ let axis;
120
+ if (overlapX < overlapY) {
121
+ axis = "x";
122
+ }
123
+ else if (overlapY < overlapX) {
124
+ axis = "y";
125
+ }
126
+ else {
127
+ const relVX = Math.abs(a.vx - b.vx);
128
+ const relVY = Math.abs(a.vy - b.vy);
129
+ axis = relVX > relVY ? "x" : "y";
130
+ }
131
+ const info = {
132
+ left: false,
133
+ right: false,
134
+ top: false,
135
+ bottom: false,
136
+ grounded: false,
137
+ };
138
+ if (axis === "x") {
139
+ if (dx >= 0) {
140
+ info.right = true;
141
+ return {
142
+ info,
143
+ axis,
144
+ separationX: -overlapX,
145
+ separationY: 0,
146
+ };
147
+ }
148
+ info.left = true;
149
+ return {
150
+ info,
151
+ axis,
152
+ separationX: overlapX,
153
+ separationY: 0,
154
+ };
155
+ }
156
+ if (dy >= 0) {
157
+ info.bottom = true;
158
+ info.grounded = true;
159
+ return {
160
+ info,
161
+ axis,
162
+ separationX: 0,
163
+ separationY: -overlapY,
164
+ };
165
+ }
166
+ info.top = true;
167
+ return {
168
+ info,
169
+ axis,
170
+ separationX: 0,
171
+ separationY: overlapY,
172
+ };
173
+ }
174
+ }
@@ -0,0 +1 @@
1
+ export {};