-
Notifications
You must be signed in to change notification settings - Fork 118
/
scene.ts
218 lines (191 loc) · 7.11 KB
/
scene.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
interface SparseArray<T> {
[index: number]: T;
}
/**
* Control the background, tiles and camera
*/
namespace scene {
export enum Flag {
NeedsSorting = 1 << 1,
}
export interface SpriteHandler {
kind: number;
handler: (sprite: Sprite) => void;
}
export interface OverlapHandler {
kind: number;
otherKind: number;
handler: (sprite: Sprite, otherSprite: Sprite) => void;
}
export interface CollisionHandler {
kind: number;
handler: (sprite: Sprite) => void
}
export interface GameForeverHandlers {
lock: boolean;
handler: () => void;
}
// frame handler priorities
export const CONTROLLER_PRIORITY = 8;
export const PHYSICS_PRIORITY = 15;
export const ANIMATION_UPDATE_PRIORITY = 15;
export const UPDATE_CONTROLLER_PRIORITY = 13;
export const CONTROLLER_SPRITES_PRIORITY = 13;
export const UPDATE_INTERVAL_PRIORITY = 19;
export const UPDATE_PRIORITY = 20;
export const RENDER_BACKGROUND_PRIORITY = 60;
export const RENDER_SPRITES_PRIORITY = 90;
export const RENDER_DIAGNOSTICS_PRIORITY = 150;
export const UPDATE_SCREEN_PRIORITY = 200;
// default rendering z indices
export const ON_PAINT_Z = -20;
export const TILE_MAP_Z = -1;
export const SPRITE_Z = 0;
export const ON_SHADE_Z = 80;
export const HUD_Z = 100;
export class Scene {
eventContext: control.EventContext;
background: Background;
tileMap: tiles.TileMap;
allSprites: SpriteLike[];
private spriteNextId: number;
spritesByKind: SparseArray<SpriteSet>;
physicsEngine: PhysicsEngine;
camera: scene.Camera;
flags: number;
destroyedHandlers: SpriteHandler[];
createdHandlers: SpriteHandler[];
overlapHandlers: OverlapHandler[];
overlapMap: SparseArray<number[]>;
collisionHandlers: CollisionHandler[][];
gameForeverHandlers: GameForeverHandlers[];
particleSources: particles.ParticleSource[];
controlledSprites: controller.ControlledSprite[][];
private _millis: number;
private _data: any;
// a set of functions that need to be called when a scene is being initialized
static initializers: ((scene: Scene) => void)[] = [];
constructor(eventContext: control.EventContext) {
this.eventContext = eventContext;
this.flags = 0;
this.physicsEngine = new ArcadePhysicsEngine();
this.camera = new scene.Camera();
this.background = new Background(this.camera);
this.destroyedHandlers = [];
this.createdHandlers = [];
this.overlapHandlers = [];
this.overlapMap = {};
this.collisionHandlers = [];
this.gameForeverHandlers = [];
this.spritesByKind = {};
this.controlledSprites = [];
this._data = {};
this._millis = 0;
}
init() {
if (this.allSprites) return;
power.poke(); // keep game alive a little more
this.allSprites = [];
this.spriteNextId = 0;
// update controller state
this.eventContext.registerFrameHandler(CONTROLLER_PRIORITY, () => {
this._millis += this.eventContext.deltaTimeMillis;
control.enablePerfCounter("controller_update")
controller.__update(this.eventContext.deltaTime);
})
// controller update 13
this.eventContext.registerFrameHandler(CONTROLLER_SPRITES_PRIORITY, controller._moveSprites);
// apply physics and collisions 15
this.eventContext.registerFrameHandler(PHYSICS_PRIORITY, () => {
control.enablePerfCounter("physics and collisions")
const dt = this.eventContext.deltaTime;
this.physicsEngine.move(dt);
this.camera.update();
for (const s of this.allSprites)
s.__update(this.camera, dt);
})
// user update interval 19s
// user update 20
// render 90
this.eventContext.registerFrameHandler(RENDER_SPRITES_PRIORITY, () => {
control.enablePerfCounter("sprite_draw")
this.cachedRender = undefined;
this.renderCore();
});
// render diagnostics
this.eventContext.registerFrameHandler(RENDER_DIAGNOSTICS_PRIORITY, () => {
if (game.stats && control.EventContext.onStats) {
control.EventContext.onStats(
control.EventContext.lastStats +
` sprites:${this.allSprites.length}`
)
}
if (game.debug)
this.physicsEngine.draw();
game.consoleOverlay.draw();
// clear flags
this.flags = 0;
// check for power deep sleep
power.checkDeepSleep();
});
// update screen
this.eventContext.registerFrameHandler(UPDATE_SCREEN_PRIORITY, control.__screen.update);
// register additional components
Scene.initializers.forEach(f => f(this));
}
get data() {
return this._data;
}
/**
* Gets the elapsed time in the scene
*/
millis(): number {
return this._millis;
}
addSprite(sprite: SpriteLike) {
this.allSprites.push(sprite);
sprite.id = this.spriteNextId++;
}
destroy() {
this.eventContext = undefined;
this.background = undefined;
this.tileMap = undefined;
this.allSprites = undefined;
this.spriteNextId = undefined;
this.spritesByKind = undefined;
this.physicsEngine = undefined;
this.camera = undefined;
this.flags = undefined;
this.destroyedHandlers = undefined;
this.createdHandlers = undefined;
this.overlapHandlers = undefined;
this.collisionHandlers = undefined;
this.gameForeverHandlers = undefined;
this._data = undefined;
}
protected cachedRender: Image;
/**
* Renders the current frame as an image
*/
render(): Image {
if (this.cachedRender) {
return this.cachedRender;
}
this.renderCore();
this.cachedRender = screen.clone();
return this.cachedRender;
}
private renderCore() {
control.enablePerfCounter("render background")
this.background.draw();
control.enablePerfCounter("sprite sort")
if (this.flags & Flag.NeedsSorting) {
this.allSprites.sort(function (a, b) { return a.z - b.z || a.id - b.id; })
}
control.enablePerfCounter("sprite draw")
for (const s of this.allSprites) {
s.__draw(this.camera);
}
}
}
}