Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
FogNetwork
GitHub Repository: FogNetwork/Tsunami
Path: blob/main/public/games/files/garbage-collector/js/game.js
1036 views
1
/*jshint bitwise: false, camelcase: false*/
2
/*globals define*/
3
define(function( require ) {
4
'use strict';
5
6
var Box2D = require( 'box2d' );
7
var Input = require( 'input' );
8
var Intersection = require( 'geometry/intersection' );
9
var Camera = require( 'entities/camera' );
10
var Player = require( 'entities/player' );
11
var Explosion = require( 'entities/explosion' );
12
var Trigger = require( 'entities/trigger' );
13
var Door = require( 'entities/door' );
14
var Background = require( 'effects/background' );
15
var Shake = require( 'effects/shake' );
16
var Colors = require( 'config/colors' );
17
var Material = require( 'config/material' );
18
var Settings = require( 'config/settings' );
19
var world = require( 'world' );
20
21
var DebugDraw = Box2D.Dynamics.b2DebugDraw;
22
var ContactListener = Box2D.Dynamics.b2ContactListener;
23
24
function Game() {
25
this.prevTime = Date.now();
26
this.currTime = this.prevTime;
27
28
this.running = true;
29
30
this.element = document.createElement( 'div' );
31
this.canvas = document.createElement( 'canvas' );
32
this.ctx = this.canvas.getContext( '2d' );
33
34
this.element.appendChild( this.canvas );
35
36
var width = 640,
37
height = 480;
38
39
this.canvas.width = width;
40
this.canvas.height = height;
41
42
this.removed = [];
43
44
this.entities = [];
45
this.player = null;
46
47
this.camera = new Camera();
48
this.camera.margin = 10;
49
this.camera.world = this;
50
51
this.shake = new Shake();
52
53
this.level = null;
54
55
this.input = new Input();
56
this.input.game = this;
57
58
// dt should never exceed this (milliseconds).
59
this.MAX_FRAME_TIME = 1000 / 30;
60
this.MIN_FRAME_TIME = 1000 / 120;
61
// Frame time (seconds).
62
this.FRAME_TIME = 1 / 60;
63
64
this.debug = false;
65
this.debugAABB = false;
66
67
this.text = '';
68
69
this.background = new Background( width, height );
70
this.background.camera = this.camera;
71
this.background.game = this;
72
this.background.prerender();
73
74
this.world = world;
75
world.GetGravity().SetZero();
76
77
// Debug view variables.
78
this.box2dDebug = false;
79
this.debugCanvas = null;
80
this.debugCtx = null;
81
82
var contactListener = new ContactListener();
83
84
function userData( fixture ) {
85
return fixture.GetBody().GetUserData();
86
}
87
88
contactListener.BeginContact = function( contact ) {
89
var fixtureA = contact.GetFixtureA(),
90
fixtureB = contact.GetFixtureB();
91
92
var a = userData( fixtureA ),
93
b = userData( fixtureB );
94
95
// Handle player explosions.
96
var player, other;
97
if ( a instanceof Player && !fixtureB.IsSensor() ) {
98
player = a;
99
other = b;
100
} else if ( b instanceof Player && !fixtureA.IsSensor() ) {
101
player = b;
102
other = a;
103
}
104
105
var explosion, fill;
106
if ( player && !( player.material & other.material ) &&
107
player.game && other.game ) {
108
player.emotion = Player.Emotion.HIT;
109
if ( player.emotionTimeout ) {
110
clearTimeout( player.emotionTimeout );
111
}
112
113
player.emotionTimeout = setTimeout(function() {
114
player.emotion = Player.Emotion.NORMAL;
115
clearTimeout( player.emotionTimeout );
116
player.emotionTimeout = null;
117
}, 700 );
118
119
if ( Settings.explosions ) {
120
fill = Colors.Explosion[ Material.type( other.material )];
121
122
if ( fill ) {
123
explosion = new Explosion( other.x, other.y );
124
explosion.fill.set( fill );
125
this.add( explosion );
126
}
127
}
128
129
this.shake.shake( 1, 0.4 );
130
this.removed.push( other );
131
return;
132
}
133
134
// Handle explosions.
135
if ( !player &&
136
!fixtureA.IsSensor() &&
137
!fixtureB.IsSensor() &&
138
!( a.material & b.material ) &&
139
a.game &&
140
b.game ) {
141
var explosionA,
142
explosionB;
143
144
var fillA,
145
fillB;
146
147
if ( Settings.explosions ) {
148
fillA = Colors.Explosion[ Material.type( a.material )];
149
fillB = Colors.Explosion[ Material.type( b.material )];
150
151
if ( fillA ) {
152
explosionA = new Explosion( a.x, a.y );
153
explosionA.fill.set( fillA );
154
this.add( explosionA );
155
}
156
157
if ( fillB ) {
158
explosionB = new Explosion( b.x, b.y );
159
explosionB.fill.set( fillB );
160
this.add( explosionB );
161
}
162
}
163
164
this.removed.push( a );
165
this.removed.push( b );
166
}
167
168
// Handles trigger.
169
var trigger;
170
if ( a instanceof Trigger &&
171
!fixtureB.IsSensor() &&
172
!( b instanceof Player ) ) {
173
trigger = a;
174
other = b;
175
} else if ( b instanceof Trigger &&
176
!fixtureA.IsSensor() &&
177
!( a instanceof Player ) ) {
178
trigger = b;
179
other = a;
180
}
181
182
if ( trigger &&
183
!trigger.active &&
184
( trigger.material & other.material ) ) {
185
trigger.object = other;
186
}
187
188
// Handle door.
189
var door;
190
if ( a instanceof Door && b instanceof Player ) {
191
door = a;
192
player = b;
193
} else if ( b instanceof Door && a instanceof Player ) {
194
door = b;
195
player = a;
196
}
197
198
if ( door && door.open ) {
199
door.player = player;
200
}
201
}.bind( this );
202
203
world.SetContactListener( contactListener );
204
}
205
206
Game.instance = null;
207
208
Game.prototype.initializeDebugView = function() {
209
this.debugCanvas = document.createElement( 'canvas' );
210
this.debugCtx = this.debugCanvas.getContext( '2d' );
211
212
document.body.appendChild( this.debugCanvas );
213
214
this.debugCanvas.id = 'box2d-debug-canvas';
215
this.debugCanvas.width = this.canvas.width;
216
this.debugCanvas.height = this.canvas.height;
217
218
var debugDraw = new DebugDraw();
219
debugDraw.SetSprite( this.debugCtx );
220
debugDraw.SetDrawScale( 1 );
221
debugDraw.SetFillAlpha( 0.3 );
222
debugDraw.SetLineThickness( 1 );
223
debugDraw.SetFlags( DebugDraw.e_shapeBit );
224
world.SetDebugDraw( debugDraw );
225
};
226
227
Game.prototype.update = function() {
228
this.currTime = Date.now();
229
var dt = this.currTime - this.prevTime;
230
if ( dt < this.MIN_FRAME_TIME ) {
231
return;
232
}
233
234
this.prevTime = this.currTime;
235
236
if ( dt > this.MAX_FRAME_TIME ) {
237
dt = this.MAX_FRAME_TIME;
238
}
239
240
dt *= 1e-3;
241
242
this.input.update( dt );
243
// Camera controls.
244
if ( this.debug ) {
245
this.updateDebug( dt );
246
}
247
248
this.entities.forEach(function( entity ) {
249
entity.update( dt );
250
});
251
252
this.player.update( dt );
253
this.camera.update( dt );
254
this.shake.update( dt );
255
256
this.world.Step( this.FRAME_TIME, 8, 3 );
257
258
this.world.ClearForces();
259
260
this.removed.forEach(function( removed ) {
261
this.remove( removed );
262
263
if ( removed.body ) {
264
this.world.DestroyBody( removed.body );
265
}
266
}.bind( this ));
267
268
this.removed = [];
269
};
270
271
Game.prototype.draw = function() {
272
if ( this.box2dDebug ) {
273
this.drawDebug();
274
}
275
276
var ctx = this.ctx;
277
278
var level = this.level;
279
if ( level && level.fill.alpha ) {
280
ctx.fillStyle = level.fill.rgba();
281
ctx.fillRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
282
} else {
283
ctx.clearRect( 0, 0, ctx.canvas.width, ctx.canvas.height );
284
}
285
286
ctx.save();
287
this.camera.applyTransform( ctx );
288
this.shake.applyTransform( ctx );
289
290
if ( Settings.background ) {
291
this.background.draw( ctx );
292
}
293
294
this.entities.forEach(function( entity ) {
295
entity.draw( ctx );
296
});
297
298
this.player.draw( ctx );
299
this.camera.draw( ctx );
300
301
if ( this.debugAABB ) {
302
this.drawAABBs( ctx );
303
}
304
305
ctx.restore();
306
307
this.input.draw( ctx );
308
309
if ( this.text ) {
310
ctx.font = this.font;
311
ctx.fillStyle = 'white';
312
ctx.textAlign = 'center';
313
ctx.textBaseline = 'middle';
314
315
ctx.shadowBlur = 10;
316
ctx.shadowColor = 'black';
317
ctx.fillText( this.text, 0.5 * ctx.canvas.width, 0.25 * ctx.canvas.height );
318
ctx.shadowBlur = 0;
319
320
ctx.textAlign = 'start';
321
ctx.textBaseline = 'alphabetic';
322
}
323
};
324
325
Game.prototype.updateDebug = function( dt ) {
326
var aspectRatio = this.camera.width / this.camera.height;
327
// Basic camera controls.
328
// I. Zoom in.
329
if ( this.input.keys[ 73 ] ) {
330
this.camera.width = Math.max( this.camera.width - 1.5 * aspectRatio, 32 );
331
this.camera.height = Math.max( this.camera.height - 1.5, 24 );
332
}
333
// J. Zoom out.
334
if ( this.input.keys[ 74 ] ) {
335
this.camera.width += 1.5 * aspectRatio;
336
this.camera.height += 1.5;
337
}
338
// K. Rotate left.
339
if ( this.input.keys[ 75 ] ) {
340
this.camera.angle += dt;
341
}
342
// L. Rotate right.
343
if ( this.input.keys[ 76 ] ) {
344
this.camera.angle -= dt;
345
}
346
// O. Reset camera.
347
if ( this.input.keys[ 79 ] ) {
348
this.camera.width = 64;
349
this.camera.height = 48;
350
this.camera.angle = 0;
351
}
352
};
353
354
Game.prototype.drawAABBs = function( ctx ) {
355
ctx.beginPath();
356
357
var aabb;
358
this.entities.forEach(function( entity ) {
359
aabb = entity.aabb();
360
if ( aabb ) {
361
ctx.rect( aabb.xmin, aabb.ymin, aabb.xmax - aabb.xmin, aabb.ymax - aabb.ymin );
362
}
363
});
364
365
aabb = this.player.aabb();
366
if ( aabb ) {
367
ctx.rect( aabb.xmin, aabb.ymin, aabb.xmax - aabb.xmin, aabb.ymax - aabb.ymin );
368
}
369
370
aabb = this.camera.aabb();
371
if ( aabb ) {
372
ctx.rect( aabb.xmin, aabb.ymin, aabb.xmax - aabb.xmin, aabb.ymax - aabb.ymin );
373
}
374
375
ctx.strokeStyle = '#f00';
376
ctx.lineWidth = 0.2;
377
ctx.stroke();
378
};
379
380
Game.prototype.drawDebug = function() {
381
var debugCtx = this.debugCtx;
382
383
var width = debugCtx.canvas.width,
384
height = debugCtx.canvas.height;
385
386
debugCtx.clearRect( 0, 0, width, height );
387
debugCtx.save();
388
389
debugCtx.translate( 0.5 * width, 0.5 * height );
390
this.world.DrawDebugData();
391
392
debugCtx.restore();
393
};
394
395
Game.prototype.tick = function() {
396
if ( !this.running ) {
397
return;
398
}
399
400
this.update();
401
this.draw();
402
403
window.requestAnimationFrame( this.tick.bind( this ) );
404
};
405
406
Game.prototype.add = function( entity ) {
407
this.entities.push( entity );
408
entity.game = this;
409
};
410
411
Game.prototype.remove = function( entity ) {
412
var index = this.entities.indexOf( entity );
413
if ( index !== -1 ) {
414
this.entities.splice( index, 1 );
415
entity.game = null;
416
}
417
};
418
419
Game.prototype.setPlayer = function( player ) {
420
player.game = this;
421
this.player = player;
422
};
423
424
/**
425
* Clear the world before loading the level.
426
*/
427
Game.prototype.clear = function() {
428
this.entities = [];
429
430
var world = this.world;
431
world.ClearForces();
432
433
var body = world.GetBodyList();
434
while ( body ) {
435
if ( !( body.GetUserData() instanceof Player ) ) {
436
world.DestroyBody( body );
437
}
438
439
body = body.GetNext();
440
}
441
};
442
443
Game.prototype.load = function( level ) {
444
level.entities.forEach(function( entity ) {
445
this.add( entity );
446
}.bind( this ));
447
};
448
449
return Game;
450
});
451
452