Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
FogNetwork
GitHub Repository: FogNetwork/Tsunami
Path: blob/main/public/games/files/algaes-escapade/js/lib/world.js
1036 views
1
/**
2
* Represents the game world, containing the game logic and sprites that
3
* require rendering
4
*
5
* @author David North
6
*/
7
include_once(['lib/camera.js','lib/player.js', 'lib/scorecard.js',
8
'lib/lever.js', 'lib/door.js', 'lib/gates/andGate.js',
9
'lib/gates/orGate.js', 'lib/gates/notGate.js', 'lib/block.js',
10
'lib/goal.js', 'lib/tooltip.js', 'lib/platform.js']);
11
function world()
12
{
13
//The maximum X velocity a player can trvel (heading right)
14
const MAX_X_VELOCITY = 200;
15
16
//The maximum Y velocity a player can trvel (heading down)
17
const MAX_Y_VELOCITY = 400;
18
19
//The minimum X velocity a player can trvel (heading left)
20
const MIN_X_VELOCITY = -250;
21
22
//The minimum Y velocity a player can trvel (heading up)
23
const MIN_Y_VELOCITY = -350;
24
25
/**
26
* @var boolean Whether the world has fully loaded
27
*/
28
var _hasLoaded;
29
30
var _levelComplete;
31
32
var _gameTime;
33
34
var _scorecard;
35
36
/**
37
* @var camera The camera to use
38
*/
39
var _camera;
40
41
/**
42
* @var gamejs.sprite.Sprite Represents the bounding box (and background)
43
* of a level
44
*/
45
var _levelSprite;
46
47
var _levelRect;
48
49
/**
50
* @var player Represents the player
51
*/
52
var _p;
53
54
/**
55
* @var gamejs.sprite.Group Represents all objects a player can
56
* interact with
57
*/
58
var _objects;
59
60
var _goals;
61
62
_levelSpriteCollission = function(playable){
63
var rightEdge = [
64
[this.rect.right, this.rect.top],
65
[this.rect.right, this.rect.bottom]
66
];
67
68
var leftEdge = [
69
[this.rect.left, this.rect.top],
70
[this.rect.left, this.rect.bottom]
71
];
72
73
var topEdge = [
74
[this.rect.left, this.rect.top],
75
[this.rect.right, this.rect.top]
76
];
77
78
var bottomEdge = [
79
[this.rect.left, this.rect.bottom],
80
[this.rect.right, this.rect.bottom]
81
];
82
83
//Test the left and right edges, setting as appropriate
84
if ( playable.rect.collideLine(rightEdge[0], rightEdge[1]) )
85
{
86
playable.rect.right = this.rect.right;
87
}
88
else if ( playable.rect.collideLine(leftEdge[0], leftEdge[1]) )
89
{
90
playable.rect.left = this.rect.left;
91
}
92
93
//Test the top and bottom edges, setting as appropriate
94
if ( playable.rect.collideLine( topEdge[0], topEdge[1]) )
95
{
96
playable.rect.top = this.rect.top;
97
}
98
else if ( playable.rect.collideLine(bottomEdge[0], bottomEdge[1]) )
99
{
100
playable.rect.bottom = this.rect.bottom;
101
}
102
}
103
104
/**
105
* Main initiation method. Must be called before using the object
106
*
107
* @param object mainSurface the surface that everything will be drawn to
108
*
109
* @return world
110
*/
111
this.init = function( levelNum, mainSurface )
112
{
113
this.clear();
114
115
_levelSprite.image = gamejs.image.load('img/bg.png');
116
117
var _size = _levelSprite.image.getSize();
118
_levelSprite.rect = new gamejs.Rect([0, 0], [_size[0], _size[1]]);
119
_levelRect = new gamejs.Rect([0, 0], [_size[0], _size[1]]);
120
121
_objects.add(_levelSprite);
122
123
_camera.setWidth( mainSurface.getSize()[0] );
124
_camera.setHeight( mainSurface.getSize()[1] );
125
126
$.ajax({
127
"url": "js/lib/levels/level_"+levelNum+".js",
128
"dataType": "json",
129
"success": function(data){
130
_loadLevel(data);
131
_camera.focusOn(_p.getCurrentPlayable().rect, true);
132
_hasLoaded = true;
133
},
134
"error": function(jqXHR, textStatus, errorThrown){
135
throw errorThrown;
136
}
137
});
138
139
return this;
140
}
141
142
this.clear = function(){
143
if ( _objects instanceof gamejs.sprite.Group )
144
{
145
while( _objects.sprites().length )
146
{
147
var sprite = _objects.sprites()[0];
148
149
if ( typeof(sprite.hide) == 'function' )
150
{
151
sprite.hide();
152
}
153
154
sprite.kill();
155
sprite.remove(_objects);
156
};
157
}
158
159
if ( _scorecard instanceof scorecard )
160
{
161
_scorecard.hide();
162
}
163
164
_hasLoaded = false;
165
_levelComplete = false;
166
_gameTime = 0;
167
_scorecard = new scorecard();
168
_camera = new camera( this );
169
_levelSprite = new gamejs.sprite.Sprite();
170
_levelRect = new gamejs.Rect([0,0]);
171
_p = new player();
172
_objects = new gamejs.sprite.Group();
173
_goals = [];
174
175
_levelSprite.handleCollision = _levelSpriteCollission;
176
}
177
178
179
this.getBoundingRect = function()
180
{
181
return _levelRect;
182
}
183
184
this.getObjects = function()
185
{
186
return [ _p.getPlayables(), _objects ]
187
}
188
189
this.getPlayer = function()
190
{
191
return _p;
192
}
193
194
/**
195
* Handles user input and modifies the world objects accordingly
196
*
197
* @return world
198
*/
199
this.handleInput = function()
200
{
201
if ( _hasLoaded && !_camera.isAnimating())
202
{
203
var self = this;
204
205
//Loop through each game event (key presses mouse movements etc)
206
gamejs.event.get().forEach(function(event){
207
if ( !_levelComplete )
208
{
209
var _currentPlayer = _p.getCurrentPlayable();
210
211
_p.handleInput(event);
212
213
if ( _p.getCurrentPlayable() != _currentPlayer )
214
{
215
_camera.focusOn(
216
_p.getCurrentPlayable().rect, true, true
217
);
218
}
219
220
_objects.forEach(function(obj){
221
if ( typeof(obj.handleInput) == 'function' )
222
{
223
obj.handleInput(self, event);
224
}
225
});
226
}
227
});
228
}
229
230
return this;
231
}
232
233
/**
234
* Updates all objects within the world
235
*
236
* @param int msDuration The amount of time since the last update
237
*
238
* @return world
239
*/
240
this.update = function( msDuration )
241
{
242
if ( _hasLoaded && !_levelComplete )
243
{
244
_gameTime += msDuration;
245
246
//Apply the gravitational pull of the world
247
_applyGravity( msDuration );
248
249
//Apply updates to the player and any objects in the world
250
_p.update( msDuration );
251
_objects.update( msDuration );
252
253
var colliders =
254
gamejs.sprite.groupCollide(_p.getPlayables(), _objects);
255
256
for( var i = 0; i < colliders.length; i++ )
257
{
258
if ( typeof(colliders[i].b.handleCollision) == 'function' )
259
{
260
var isCurrentPlayer = false;
261
if ( colliders[i].a === _p.getCurrentPlayable() )
262
{
263
isCurrentPlayer = true;
264
}
265
266
colliders[i].b.handleCollision(
267
colliders[i].a, isCurrentPlayer
268
);
269
}
270
}
271
272
//Modify the camera position
273
_camera.update ( msDuration );
274
275
_levelComplete = true;
276
for( var i = 0; i < _goals.length; i++ )
277
{
278
if ( !_goals[i].isActive() )
279
{
280
_levelComplete = false;
281
break;
282
}
283
}
284
285
if ( _levelComplete )
286
{
287
for( var i = 0; i < _objects.sprites().length; i++ )
288
{
289
var obj = _objects.sprites()[i];
290
if ( obj instanceof tooltip )
291
{
292
obj.hide(false);
293
}
294
}
295
296
_scorecard.setTimeTaken(_gameTime / 1000);
297
_scorecard.setClonesUsed(_p.getNumClones());
298
_scorecard.show();
299
}
300
}
301
302
return this;
303
}
304
305
/**
306
* Draws all objects within the world
307
*
308
* @return this
309
*/
310
this.draw = function ( mainSurface )
311
{
312
if ( _hasLoaded )
313
{
314
//Draw the level, collidables and non collidables, as these need
315
//to be behind the player
316
_objects.draw( mainSurface );
317
318
//Draw the player at the forefront of the level
319
_p.draw( mainSurface );
320
}
321
322
return this;
323
}
324
325
/**
326
* Loads the level data from an array, filling the worls with collidables
327
* and ensuring it's playable
328
*/
329
var _loadLevel = function( data, input, output )
330
{
331
var _hasPlayer = false;
332
for ( var i = 0; i < data.length; i ++)
333
{
334
if ( data[i]['type'] == 'stats' )
335
{
336
_scorecard.setParForClones(data[i]['clonePar']);
337
_scorecard.setParForTime(data[i]['timePar']);
338
339
if ( typeof(data[i]['lastLevel']) == 'boolean' )
340
{
341
_scorecard.setLastLevel(data[i]['lastLevel']);
342
}
343
else
344
{
345
_scorecard.setLastLevel(false);
346
}
347
}
348
else
349
{
350
var xAmount = 1;
351
var yAmount = 1;
352
353
if ( typeof(data[i]['repeat-x']) != 'undefined')
354
{
355
xAmount = data[i]['repeat-x'];
356
}
357
358
if ( typeof(data[i]['repeat-y']) != 'undefined')
359
{
360
yAmount = data[i]['repeat-y'];
361
}
362
363
for ( var x = 0; x < xAmount; x++ )
364
{
365
for ( var y = 0; y < yAmount; y++ )
366
{
367
_addObjectToWorld(data[i], x, y, input, output);
368
}
369
}
370
}
371
}
372
}
373
374
var _addObjectToWorld = function( data, x, y, input, output ){
375
var obj = null;
376
377
if ( 'tooltip' == data['type'] )
378
{
379
obj = new tooltip();
380
obj.setText(data['text']);
381
_objects.add( obj );
382
}
383
else
384
{
385
switch ( data['type'] )
386
{
387
case 'block':
388
case 'wall':
389
data['type'] = 'block';
390
case 'andGate':
391
case 'orGate':
392
case 'notGate':
393
case 'lever':
394
case 'door':
395
case 'goal':
396
case 'platform':
397
var type = data['type'];
398
obj = new window[type]();
399
_objects.add( obj );
400
401
if ( 'goal' === type )
402
{
403
_goals.push( obj );
404
}
405
break;
406
407
case 'player':
408
obj = _p.getCurrentPlayable();
409
}
410
}
411
412
if ( null != obj )
413
{
414
if ( obj instanceof io )
415
{
416
if ( typeof(data['outputs']) !== 'undefined' )
417
{
418
_loadLevel(data['outputs'], obj);
419
}
420
421
if ( typeof(data['inputs']) !== 'undefined' )
422
{
423
_loadLevel(data['inputs'], null, obj)
424
}
425
426
if ( typeof(input) !== 'undefined' && input != null )
427
{
428
obj.addInput(input);
429
}
430
431
if ( typeof(output) !== 'undefined' && output != null )
432
{
433
obj.addOutput(output);
434
}
435
}
436
437
if ( typeof(obj.setDimensions) != 'undefined' )
438
{
439
if ( typeof(data['width']) != 'undefined'
440
&& typeof(data['height']) != 'undefined' )
441
{
442
obj.setDimensions(data['width'], data['height']);
443
}
444
}
445
446
var width = obj.rect.width;
447
var height = obj.rect.height;
448
449
var xPos = (data['x'] + (width * x));
450
var yPos = (data['y'] + (height * y));
451
452
obj.setPosition( xPos, yPos );
453
}
454
}
455
456
/**
457
* Applies the gravitational pull of the world on all playables
458
*/
459
var _applyGravity = function( msDuration )
460
{
461
//Loop through each player and increase the Y velocity downward.
462
//If the player is jumping, this has the affect of slowing the
463
//player down. Otherwise the player is falling.
464
_p.getPlayables().forEach(function(obj){
465
var newVelocityY = obj.getVelocity().y
466
newVelocityY += Math.round(0.3 * msDuration);
467
468
obj.setVelocity( obj.getVelocity().x, newVelocityY )
469
470
//the velocity cannot exceed the maximums, so ensuer that the player
471
//is not falling too fast
472
_sanatiseVelocity(obj);
473
});
474
}
475
476
/**
477
* Ensures that the player is not travelling too fast ion any direction
478
*/
479
var _sanatiseVelocity = function(obj)
480
{
481
//Get the current Velocity
482
var velocity = obj.getVelocity();
483
484
//Make sure that the X velocity is not too slow or fast
485
velocity.x = Math.max( MIN_X_VELOCITY, velocity.x );
486
velocity.x = Math.min( MAX_X_VELOCITY, velocity.x );
487
488
//Make sure that the Y velocity is not too slow or fast
489
velocity.y = Math.max( MIN_Y_VELOCITY, velocity.y );
490
velocity.y = Math.min( MAX_Y_VELOCITY, velocity.y );
491
492
//Update the players velocity
493
obj.setVelocity( velocity.x, velocity.y );
494
}
495
}
496