like2d 2.12.0 → 2.13.0
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/README.md +20 -30
- package/assets/logo-banner-optimized.svg +1 -1
- package/dist/engine.d.ts +13 -7
- package/dist/engine.js +21 -46
- package/dist/events.d.ts +61 -59
- package/dist/graphics/graphics.d.ts +5 -4
- package/dist/graphics/graphics.js +3 -3
- package/dist/graphics/index.d.ts +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -2
- package/dist/input/gamepad.d.ts +2 -2
- package/dist/input/gamepad.js +2 -2
- package/dist/input/mouse.d.ts +8 -8
- package/dist/input/mouse.js +8 -8
- package/dist/like.d.ts +45 -67
- package/dist/math/rect.d.ts +1 -0
- package/dist/math/rect.js +1 -0
- package/dist/math/vector2.d.ts +3 -0
- package/dist/math/vector2.js +3 -0
- package/dist/scene/index.d.ts +368 -0
- package/dist/scene/index.js +204 -0
- package/dist/scene/prefab/fadeTransition.d.ts +25 -0
- package/dist/scene/prefab/fadeTransition.js +55 -0
- package/dist/scene/prefab/mapGamepad.d.ts +47 -0
- package/dist/scene/prefab/mapGamepad.js +189 -0
- package/dist/scene/prefab/startScreen.d.ts +47 -0
- package/dist/{prefab-scenes → scene/prefab}/startScreen.js +25 -84
- package/package.json +11 -6
- package/dist/prefab-scenes/index.d.ts +0 -10
- package/dist/prefab-scenes/index.js +0 -9
- package/dist/prefab-scenes/mapGamepad.d.ts +0 -42
- package/dist/prefab-scenes/mapGamepad.js +0 -199
- package/dist/prefab-scenes/startScreen.d.ts +0 -58
- package/dist/scene.d.ts +0 -143
- package/dist/scene.js +0 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "like2d",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "A web-native game framework inspired by Love2D",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,10 +15,6 @@
|
|
|
15
15
|
"import": "./dist/math/index.js",
|
|
16
16
|
"types": "./dist/math/index.d.ts"
|
|
17
17
|
},
|
|
18
|
-
"./prefab-scenes": {
|
|
19
|
-
"import": "./dist/prefab-scenes/index.js",
|
|
20
|
-
"types": "./dist/prefab-scenes/index.d.ts"
|
|
21
|
-
},
|
|
22
18
|
"./graphics": {
|
|
23
19
|
"types": "./dist/graphics/index.d.ts"
|
|
24
20
|
},
|
|
@@ -33,6 +29,14 @@
|
|
|
33
29
|
"./timer": {
|
|
34
30
|
"import": "./dist/timer/index.js",
|
|
35
31
|
"types": "./dist/timer/index.d.ts"
|
|
32
|
+
},
|
|
33
|
+
"./scene": {
|
|
34
|
+
"import": "./dist/scene/index.js",
|
|
35
|
+
"types": "./dist/scene/index.d.ts"
|
|
36
|
+
},
|
|
37
|
+
"./scene/prefab/*": {
|
|
38
|
+
"import": "./dist/scene/prefab/*.js",
|
|
39
|
+
"types": "./dist/scene/prefab/*.d.ts"
|
|
36
40
|
}
|
|
37
41
|
},
|
|
38
42
|
"files": [
|
|
@@ -61,9 +65,10 @@
|
|
|
61
65
|
],
|
|
62
66
|
"author": "",
|
|
63
67
|
"license": "MIT",
|
|
68
|
+
"homepage": "https://likeorg.github.io/Like2D/",
|
|
64
69
|
"repository": {
|
|
65
70
|
"type": "git",
|
|
66
|
-
"url": "https://github.com/
|
|
71
|
+
"url": "https://github.com/likeOrg/Like2D"
|
|
67
72
|
},
|
|
68
73
|
"devDependencies": {
|
|
69
74
|
"typescript": "^5.9.3"
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A set of built-in scenes to aid with game development.
|
|
3
|
-
*
|
|
4
|
-
* To learn more about scenes, see {@link index.Scene}.
|
|
5
|
-
*
|
|
6
|
-
* @module prefab-scenes
|
|
7
|
-
*/
|
|
8
|
-
export { StartScreen } from "./startScreen";
|
|
9
|
-
export { MapGamepad, buttonSetAll, buttonSetNES, buttonSetPS1, buttonSetSNES, type MapMode } from "./mapGamepad";
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A set of built-in scenes to aid with game development.
|
|
3
|
-
*
|
|
4
|
-
* To learn more about scenes, see {@link index.Scene}.
|
|
5
|
-
*
|
|
6
|
-
* @module prefab-scenes
|
|
7
|
-
*/
|
|
8
|
-
export { StartScreen } from "./startScreen";
|
|
9
|
-
export { MapGamepad, buttonSetAll, buttonSetNES, buttonSetPS1, buttonSetSNES } from "./mapGamepad";
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { Like } from "..";
|
|
2
|
-
import { type LikeButton } from "../input";
|
|
3
|
-
import { Scene } from "../scene";
|
|
4
|
-
export declare const buttonSetNES: Set<LikeButton>;
|
|
5
|
-
export declare const buttonSetGBA: Set<LikeButton>;
|
|
6
|
-
export declare const buttonSetSNES: Set<LikeButton>;
|
|
7
|
-
export declare const buttonSetPS1: Set<LikeButton>;
|
|
8
|
-
export declare const buttonSetAll: Set<LikeButton>;
|
|
9
|
-
export type MapMode = {
|
|
10
|
-
buttons: Set<LikeButton>;
|
|
11
|
-
stickCount: number;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* An automagical gamepad mapper.
|
|
15
|
-
*
|
|
16
|
-
* ```ts
|
|
17
|
-
* like.gamepadconnected = (index) =>
|
|
18
|
-
* like.pushScene(new MapGamepad({buttons: buttonSetGBA, sticks: 0}), index)
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* Add this to your codebase and activating a gamepad causes a button mapping screen to pop up.
|
|
22
|
-
* It will request to map any buttons not already covered by the automapping database.
|
|
23
|
-
*
|
|
24
|
-
* Note: many browsers do this on first button press, so always writing "P2: press any button" is a fine idea.
|
|
25
|
-
*/
|
|
26
|
-
export declare class MapGamepad implements Scene {
|
|
27
|
-
private mapMode;
|
|
28
|
-
private targetPad;
|
|
29
|
-
private currentlyUnmapped;
|
|
30
|
-
private mapping;
|
|
31
|
-
private held?;
|
|
32
|
-
private alreadyMapped;
|
|
33
|
-
private frameWait;
|
|
34
|
-
constructor(mapMode: MapMode, targetPad: number);
|
|
35
|
-
load(like: Like): void;
|
|
36
|
-
update(): void;
|
|
37
|
-
draw(like: Like): void;
|
|
38
|
-
gamepadpressed(like: Like, source: number, _name: LikeButton, num: number): void;
|
|
39
|
-
gamepadreleased(_like: Like, source: number, _name: LikeButton, num: number): void;
|
|
40
|
-
mousepressed(like: Like): void;
|
|
41
|
-
}
|
|
42
|
-
//# sourceMappingURL=mapGamepad.d.ts.map
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { defaultMapping } from "../input";
|
|
2
|
-
const mapOrder = [
|
|
3
|
-
"BRight",
|
|
4
|
-
"BBottom",
|
|
5
|
-
"Up",
|
|
6
|
-
"Down",
|
|
7
|
-
"Left",
|
|
8
|
-
"Right",
|
|
9
|
-
"MenuLeft",
|
|
10
|
-
"MenuRight",
|
|
11
|
-
// 8: NES buttons
|
|
12
|
-
"L1",
|
|
13
|
-
"R1",
|
|
14
|
-
// 10: GBA buttons
|
|
15
|
-
"BLeft",
|
|
16
|
-
"BTop",
|
|
17
|
-
// 12: SNES buttons
|
|
18
|
-
"L2",
|
|
19
|
-
"R2",
|
|
20
|
-
// 14: PS1 buttons
|
|
21
|
-
"LeftStick",
|
|
22
|
-
"RightStick",
|
|
23
|
-
];
|
|
24
|
-
export const buttonSetNES = new Set(mapOrder.slice(0, 8));
|
|
25
|
-
export const buttonSetGBA = new Set(mapOrder.slice(0, 10));
|
|
26
|
-
export const buttonSetSNES = new Set(mapOrder.slice(0, 12));
|
|
27
|
-
export const buttonSetPS1 = new Set(mapOrder.slice(0, 14));
|
|
28
|
-
export const buttonSetAll = new Set(mapOrder);
|
|
29
|
-
const drawCircButt = (pos, size) => (like, color) => like.gfx.circle("fill", color, pos, size);
|
|
30
|
-
const drawDpadPart = (rot) => (like, color) => {
|
|
31
|
-
like.gfx.withTransform(() => {
|
|
32
|
-
like.gfx.translate([2.5, 6]);
|
|
33
|
-
like.gfx.rotate(rot);
|
|
34
|
-
like.gfx.rectangle("fill", color, [0.5, -0.5, 1.3, 1]);
|
|
35
|
-
});
|
|
36
|
-
};
|
|
37
|
-
const drawShoulder = (y, width, flip) => (like, color) => {
|
|
38
|
-
const r = 0.8;
|
|
39
|
-
const rectPos = [5 - width, y];
|
|
40
|
-
const circPos = [5 - width - r, y];
|
|
41
|
-
like.gfx.withTransform(() => {
|
|
42
|
-
if (flip) {
|
|
43
|
-
like.gfx.translate([16, 0]);
|
|
44
|
-
like.gfx.scale([-1, 1]);
|
|
45
|
-
}
|
|
46
|
-
like.gfx.circle("fill", color, circPos, r, { arc: [Math.PI, Math.PI * 3 / 2], center: false });
|
|
47
|
-
like.gfx.rectangle("fill", color, [...rectPos, width, r]);
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
|
-
// Buttons assume a centered resolution of 16x9px. Transforms exist for a reason lol.
|
|
51
|
-
// LLLLL . RRRRR
|
|
52
|
-
// LLLLLLLLL . RRRRRRRRR
|
|
53
|
-
// .
|
|
54
|
-
// DDD S . S B
|
|
55
|
-
// -.....DDD.....................................
|
|
56
|
-
// DDD DDD . B B
|
|
57
|
-
// DDD LS . RS
|
|
58
|
-
// DDD . B
|
|
59
|
-
// .
|
|
60
|
-
const buttonProps = {
|
|
61
|
-
BLeft: { draw: drawCircButt([12, 6], 0.8) },
|
|
62
|
-
BRight: { draw: drawCircButt([15, 6], 0.8) },
|
|
63
|
-
BTop: { draw: drawCircButt([13.5, 4.5], 0.8) },
|
|
64
|
-
BBottom: { draw: drawCircButt([13.5, 7.5], 0.8) },
|
|
65
|
-
MenuLeft: { draw: drawCircButt([6, 4], 0.5) },
|
|
66
|
-
MenuRight: { draw: drawCircButt([10, 4], 0.5) },
|
|
67
|
-
LeftStick: { draw: drawCircButt([6.5, 7], 1.4) },
|
|
68
|
-
RightStick: { draw: drawCircButt([9.5, 7], 1.4) },
|
|
69
|
-
L1: { draw: drawShoulder(2, 3, false) },
|
|
70
|
-
L2: { draw: drawShoulder(1, 2, false) },
|
|
71
|
-
R1: { draw: drawShoulder(2, 3, true) },
|
|
72
|
-
R2: { draw: drawShoulder(1, 2, true) },
|
|
73
|
-
Right: { draw: drawDpadPart(0) },
|
|
74
|
-
Up: { draw: drawDpadPart(-Math.PI / 2) },
|
|
75
|
-
Left: { draw: drawDpadPart(Math.PI) },
|
|
76
|
-
Down: { draw: drawDpadPart(Math.PI / 2) },
|
|
77
|
-
};
|
|
78
|
-
/**
|
|
79
|
-
* An automagical gamepad mapper.
|
|
80
|
-
*
|
|
81
|
-
* ```ts
|
|
82
|
-
* like.gamepadconnected = (index) =>
|
|
83
|
-
* like.pushScene(new MapGamepad({buttons: buttonSetGBA, sticks: 0}), index)
|
|
84
|
-
* ```
|
|
85
|
-
*
|
|
86
|
-
* Add this to your codebase and activating a gamepad causes a button mapping screen to pop up.
|
|
87
|
-
* It will request to map any buttons not already covered by the automapping database.
|
|
88
|
-
*
|
|
89
|
-
* Note: many browsers do this on first button press, so always writing "P2: press any button" is a fine idea.
|
|
90
|
-
*/
|
|
91
|
-
export class MapGamepad {
|
|
92
|
-
constructor(mapMode, targetPad) {
|
|
93
|
-
Object.defineProperty(this, "mapMode", {
|
|
94
|
-
enumerable: true,
|
|
95
|
-
configurable: true,
|
|
96
|
-
writable: true,
|
|
97
|
-
value: mapMode
|
|
98
|
-
});
|
|
99
|
-
Object.defineProperty(this, "targetPad", {
|
|
100
|
-
enumerable: true,
|
|
101
|
-
configurable: true,
|
|
102
|
-
writable: true,
|
|
103
|
-
value: targetPad
|
|
104
|
-
});
|
|
105
|
-
Object.defineProperty(this, "currentlyUnmapped", {
|
|
106
|
-
enumerable: true,
|
|
107
|
-
configurable: true,
|
|
108
|
-
writable: true,
|
|
109
|
-
value: []
|
|
110
|
-
});
|
|
111
|
-
Object.defineProperty(this, "mapping", {
|
|
112
|
-
enumerable: true,
|
|
113
|
-
configurable: true,
|
|
114
|
-
writable: true,
|
|
115
|
-
value: void 0
|
|
116
|
-
});
|
|
117
|
-
Object.defineProperty(this, "held", {
|
|
118
|
-
enumerable: true,
|
|
119
|
-
configurable: true,
|
|
120
|
-
writable: true,
|
|
121
|
-
value: void 0
|
|
122
|
-
});
|
|
123
|
-
Object.defineProperty(this, "alreadyMapped", {
|
|
124
|
-
enumerable: true,
|
|
125
|
-
configurable: true,
|
|
126
|
-
writable: true,
|
|
127
|
-
value: new Set()
|
|
128
|
-
});
|
|
129
|
-
Object.defineProperty(this, "frameWait", {
|
|
130
|
-
enumerable: true,
|
|
131
|
-
configurable: true,
|
|
132
|
-
writable: true,
|
|
133
|
-
value: 0
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
load(like) {
|
|
137
|
-
this.frameWait = 10;
|
|
138
|
-
this.mapping = like.gamepad.getMapping(this.targetPad) ?? defaultMapping(2);
|
|
139
|
-
const alreadyMapped = new Set(Object.values(this.mapping.buttons));
|
|
140
|
-
for (const btn of mapOrder.reverse()) {
|
|
141
|
-
if (this.mapMode.buttons.has(btn) && !alreadyMapped.has(btn)) {
|
|
142
|
-
this.currentlyUnmapped.push(btn);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
like.canvas.setMode([320, 240]);
|
|
146
|
-
}
|
|
147
|
-
update() {
|
|
148
|
-
this.frameWait--;
|
|
149
|
-
}
|
|
150
|
-
draw(like) {
|
|
151
|
-
const centerText = {
|
|
152
|
-
font: "1px sans-serif",
|
|
153
|
-
align: "center",
|
|
154
|
-
width: 16,
|
|
155
|
-
};
|
|
156
|
-
const active = this.currentlyUnmapped.at(-1);
|
|
157
|
-
like.gfx.clear();
|
|
158
|
-
like.gfx.scale(20);
|
|
159
|
-
like.gfx.translate([0, 1]);
|
|
160
|
-
like.gfx.print("white", `Map gamepad ${this.targetPad}`, [8, 0.0], centerText);
|
|
161
|
-
for (const prop of this.mapMode.buttons.keys()) {
|
|
162
|
-
const color = this.held == prop
|
|
163
|
-
? "green"
|
|
164
|
-
: active == prop
|
|
165
|
-
? "red"
|
|
166
|
-
: this.mapMode.buttons.has(prop)
|
|
167
|
-
? "gray"
|
|
168
|
-
: "black";
|
|
169
|
-
buttonProps[prop].draw(like, color);
|
|
170
|
-
}
|
|
171
|
-
like.gfx.print("white", active
|
|
172
|
-
? `Press ${like.gamepad.fullButtonName(active)}!`
|
|
173
|
-
: "Press any button to resume.", [2, 10], { font: "1px sans-serif" });
|
|
174
|
-
}
|
|
175
|
-
gamepadpressed(like, source, _name, num) {
|
|
176
|
-
if (source !== this.targetPad || this.held || this.frameWait > 0)
|
|
177
|
-
return;
|
|
178
|
-
const active = this.currentlyUnmapped.pop();
|
|
179
|
-
if (active && !this.alreadyMapped.has(num)) {
|
|
180
|
-
this.alreadyMapped.add(num);
|
|
181
|
-
this.mapping.buttons[num] = active;
|
|
182
|
-
this.held = active;
|
|
183
|
-
}
|
|
184
|
-
else if (!active) {
|
|
185
|
-
like.gamepad.setMapping(this.targetPad, this.mapping);
|
|
186
|
-
setTimeout(() => like.popScene(), 100);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
gamepadreleased(_like, source, _name, num) {
|
|
190
|
-
if (source !== this.targetPad)
|
|
191
|
-
return;
|
|
192
|
-
if (this.held == this.mapping.buttons[num]) {
|
|
193
|
-
this.held = undefined;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
mousepressed(like) {
|
|
197
|
-
like.popScene();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { type Scene } from '../scene';
|
|
2
|
-
import { Like } from '..';
|
|
3
|
-
/**
|
|
4
|
-
* ## Why
|
|
5
|
-
*
|
|
6
|
-
* 1. Because the LIKE logo looks awesome.
|
|
7
|
-
* 2. Autoplay restriction, doesn't let you play audio until the page is clicked.
|
|
8
|
-
* 3. You have to click on the game in order to send inputs, anyway.
|
|
9
|
-
* 4. It's polite.
|
|
10
|
-
*
|
|
11
|
-
* ## Usage
|
|
12
|
-
*
|
|
13
|
-
* ```typescript
|
|
14
|
-
* import { createLike, StartScreen } from 'like';
|
|
15
|
-
* import { GameScene } from './game';
|
|
16
|
-
*
|
|
17
|
-
* const container = document.getElementById("myGame");
|
|
18
|
-
* const like = createLike(container);
|
|
19
|
-
*
|
|
20
|
-
* // these callbacks will be ignored until the scene is clicked
|
|
21
|
-
* like.update = function () { ... }
|
|
22
|
-
* like.draw = function () { ... }
|
|
23
|
-
*
|
|
24
|
-
* // Set up the start screen
|
|
25
|
-
* like.pushScene(new StartScreen())
|
|
26
|
-
* like.start();
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* Alternatively, copy-paste this code into your own project and modify it freely.
|
|
30
|
-
* Update imports:
|
|
31
|
-
*
|
|
32
|
-
* ```ts
|
|
33
|
-
* import { type Scene } from 'like/scene';
|
|
34
|
-
* import type { ImageHandle } from 'like/graphics';
|
|
35
|
-
* import { Vec2 } from 'like/math';
|
|
36
|
-
* import { Like } from 'like';
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* ## Custom Rendering
|
|
40
|
-
*
|
|
41
|
-
* Pass a custom draw function to replace the default logo:
|
|
42
|
-
*
|
|
43
|
-
* ```typescript
|
|
44
|
-
* const startup = new StartupScene(gameScene, (like) => {
|
|
45
|
-
* like.gfx.clear([0, 0, 0, 1]);
|
|
46
|
-
* like.gfx.print([1, 1, 1], 'Click to Start', [100, 100]);
|
|
47
|
-
* });
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
export declare class StartScreen implements Scene {
|
|
51
|
-
private onDraw?;
|
|
52
|
-
private logo;
|
|
53
|
-
constructor(onDraw?: ((like: Like) => void) | undefined);
|
|
54
|
-
load(like: Like): void;
|
|
55
|
-
draw(like: Like): void;
|
|
56
|
-
mousepressed(like: Like): void;
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=startScreen.d.ts.map
|
package/dist/scene.d.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import type { LikeEvent, EventMap } from './events';
|
|
2
|
-
import type { Like } from './like';
|
|
3
|
-
/**
|
|
4
|
-
* An interface for creating scenes.
|
|
5
|
-
*
|
|
6
|
-
* ## Why Scenes?
|
|
7
|
-
*
|
|
8
|
-
* For any game with more than one scene, we have to either:
|
|
9
|
-
* - switch-case on game state in every single callback
|
|
10
|
-
* - rebind all of the callbacks ourselves
|
|
11
|
-
* - wrap handleEvent (hint: that's what this does)
|
|
12
|
-
*
|
|
13
|
-
* Also, no need to pass around a `like` object.
|
|
14
|
-
* Here, `like` instead piggybacks on a closure that follows around
|
|
15
|
-
* your running scene and shows up as an additional first argument
|
|
16
|
-
* to every callback.
|
|
17
|
-
*
|
|
18
|
-
* ## The scene stack
|
|
19
|
-
*
|
|
20
|
-
* There is a stack of scenes for state management and/or overlays.
|
|
21
|
-
*
|
|
22
|
-
* Use {@link Like.pushScene} and {@link Like.popScene} to manage the stack.
|
|
23
|
-
*
|
|
24
|
-
* {@link like.setScene} Sets the top of the stack only, replacing the current scene if any.
|
|
25
|
-
*
|
|
26
|
-
* ## Quick Start
|
|
27
|
-
*
|
|
28
|
-
* Have a scene handle all the callbacks, disabling global
|
|
29
|
-
* callbacks.
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // set up a scene
|
|
32
|
-
* class MagicalGrowingRectangle implements Scene {
|
|
33
|
-
* rectangleSize = 10;
|
|
34
|
-
* constructor() {}
|
|
35
|
-
*
|
|
36
|
-
* keypressed(_like: Like) {
|
|
37
|
-
* this.rectangleSize += 10;
|
|
38
|
-
* }
|
|
39
|
-
*
|
|
40
|
-
* draw(like: Like) {
|
|
41
|
-
* like.gfx.rectangle('fill', 'green',
|
|
42
|
-
* [10, 10, this.rectangleSize, this.rectangleSize])
|
|
43
|
-
* }
|
|
44
|
-
* }
|
|
45
|
-
*
|
|
46
|
-
* like.pushScene(new MagicalGrowingRectangle(), false);
|
|
47
|
-
* ```
|
|
48
|
-
*
|
|
49
|
-
* To get back to global callbacks, just use {@link Like.popScene}
|
|
50
|
-
*
|
|
51
|
-
* ## Scene Lifecycle
|
|
52
|
-
*
|
|
53
|
-
* Works a lot like global callbacks.
|
|
54
|
-
*
|
|
55
|
-
* 1. `like.setScene(scene)` or `like.pushScene(scene)` is called
|
|
56
|
-
* 2. Scene's `load` callback fires immediately
|
|
57
|
-
* 3. `update` and `draw` begin on next frame
|
|
58
|
-
* 4. Scene receives input events as they occur
|
|
59
|
-
*
|
|
60
|
-
* ## Composing scenes
|
|
61
|
-
*
|
|
62
|
-
* Thought you'd never ask.
|
|
63
|
-
* Just like the `like` object, scenes have handleEvent on them.
|
|
64
|
-
* So, you could layer them like this, for example:
|
|
65
|
-
*
|
|
66
|
-
* ```typescript
|
|
67
|
-
* class UI implements Scene {
|
|
68
|
-
* constructor(public game: Scene) {}
|
|
69
|
-
*
|
|
70
|
-
* handleEvent(like: Like, event: LikeEvent) {
|
|
71
|
-
* // Block mouse events in order to create a top bar.
|
|
72
|
-
* const mouseY = like.mouse.getPosition()[1];
|
|
73
|
-
* if (!event.type.startsWith('mouse') || mouseY > 100) {
|
|
74
|
-
* sceneDispatch(this.game, like, event);
|
|
75
|
-
* }
|
|
76
|
-
*
|
|
77
|
-
* // Then, call my own callbacks.
|
|
78
|
-
* // By calling it here, the UI draws on top.
|
|
79
|
-
* callSceneHandlers(this, like, event);
|
|
80
|
-
* }
|
|
81
|
-
* ...
|
|
82
|
-
* }
|
|
83
|
-
*
|
|
84
|
-
* class Game implements Scene {
|
|
85
|
-
* ...
|
|
86
|
-
* }
|
|
87
|
-
*
|
|
88
|
-
* like.pushScene(new UI(new Game()), false)
|
|
89
|
-
* ```
|
|
90
|
-
*
|
|
91
|
-
* Composing scenes lets you filter events, layer game elements,
|
|
92
|
-
* and more. Don't sleep on it.
|
|
93
|
-
*
|
|
94
|
-
* The main advance of composing scenes versus the stack-overlay
|
|
95
|
-
* technique is that the parent scene knows about its child.
|
|
96
|
-
* Because there's a **known interface**, the two scenes
|
|
97
|
-
* can communicate.
|
|
98
|
-
*
|
|
99
|
-
* This makes it perfect for reusable UI,
|
|
100
|
-
* level editors, debug viewers, and more.
|
|
101
|
-
*
|
|
102
|
-
* ## Overlay scenes
|
|
103
|
-
*
|
|
104
|
-
* You might assume that the purpose of a scene stack is
|
|
105
|
-
* visual: first push the BG, then the FG, etc.
|
|
106
|
-
*
|
|
107
|
-
* Actually, composing scenes (above) is a
|
|
108
|
-
* better pattern for that, since it's both explicit
|
|
109
|
-
* _and_ the parent can have a known interface on its child.
|
|
110
|
-
* Here, the **upper** scene only knows that the
|
|
111
|
-
* **lower** scene _is_ a scene.
|
|
112
|
-
*
|
|
113
|
-
* That's the tradeoff. Overlay scenes are good for things
|
|
114
|
-
* like pause screens or gamepad overlays. Anything where
|
|
115
|
-
* the upper doesn't care _what_ the lower is, and where
|
|
116
|
-
* the upper scene should be easily addable/removable.
|
|
117
|
-
*
|
|
118
|
-
* Using `like.getScene(-2)`, the overlay scene can see
|
|
119
|
-
* the lower scene and choose how to propagate events.
|
|
120
|
-
*
|
|
121
|
-
* The only technical difference between overlay and
|
|
122
|
-
* opaque is whether or not the scene we've pushed
|
|
123
|
-
* on top of stays loaded.
|
|
124
|
-
*
|
|
125
|
-
*/
|
|
126
|
-
export type Scene = {
|
|
127
|
-
[K in keyof EventMap]?: (like: Like, ...args: EventMap[K]) => void;
|
|
128
|
-
} & {
|
|
129
|
-
handleEvent?(like: Like, event: LikeEvent): void;
|
|
130
|
-
};
|
|
131
|
-
/**
|
|
132
|
-
* Used to call a scene's own handlers like `update` or `draw`,
|
|
133
|
-
* typically at the end of handleEvent
|
|
134
|
-
* after modifying the event stream or composing sub-scenes.
|
|
135
|
-
*/
|
|
136
|
-
export declare const callSceneHandlers: (scene: Scene, like: Like, event: LikeEvent) => void;
|
|
137
|
-
/**
|
|
138
|
-
* Used to call sub scenes while respecting potential `handleEvent` within them.
|
|
139
|
-
* The main scene is similar to a sub-scene of the root (like) object in this
|
|
140
|
-
* regard.
|
|
141
|
-
*/
|
|
142
|
-
export declare const sceneDispatch: (scene: Scene, like: Like, event: LikeEvent) => void;
|
|
143
|
-
//# sourceMappingURL=scene.d.ts.map
|
package/dist/scene.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Used to call a scene's own handlers like `update` or `draw`,
|
|
3
|
-
* typically at the end of handleEvent
|
|
4
|
-
* after modifying the event stream or composing sub-scenes.
|
|
5
|
-
*/
|
|
6
|
-
export const callSceneHandlers = (scene, like, event) => {
|
|
7
|
-
if (event.type in scene) {
|
|
8
|
-
scene[event.type](like, ...event.args);
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Used to call sub scenes while respecting potential `handleEvent` within them.
|
|
13
|
-
* The main scene is similar to a sub-scene of the root (like) object in this
|
|
14
|
-
* regard.
|
|
15
|
-
*/
|
|
16
|
-
export const sceneDispatch = (scene, like, event) => {
|
|
17
|
-
if (scene.handleEvent) {
|
|
18
|
-
scene.handleEvent(like, event);
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
callSceneHandlers(scene, like, event);
|
|
22
|
-
}
|
|
23
|
-
};
|