git @ Cat's Eye Technologies The-New-Gamerly-Realism / 866a96e
Absolute gamerly creation. Chris Pressey 7 years ago
2 changed file(s) with 556 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 <!DOCTYPE html>
1 <head>
2 <meta charset="utf-8">
3 <title>The New Gamerly Realism</title>
4 <style>
5 #container {
6 text-align: center;
7 }
8 </style>
9 </head>
10 <body>
11
12 <h1>The New Gamerly Realism</h1>
13
14 <div id="container">
15 </div>
16
17 </body>
18 <script src="../src/the-new-gamerly-realism.js"></script>
19 <script>
20 launch('', 'container');
21 </script>
0 if (window.yoob === undefined) yoob = {};
1
2 function launch(scriptRoot, containerId) {
3 var container = document.getElementById(containerId);
4
5 var canvas = document.createElement('canvas');
6 canvas.width = 400;
7 canvas.height = canvas.width;
8 container.appendChild(canvas);
9
10 var game = /* The */ new GamerlyRealism();
11 game.init(canvas);
12 game.reset();
13 canvas.onclick = function() {
14 if (game.lives === 0) {
15 game.reset();
16 }
17 };
18 }
19
20 yoob.Sprite = function() {
21
22 /*
23 * x and y always represent the CENTRE of the Sprite().
24 * Chainable.
25 */
26 this.init = function(cfg) {
27 this.x = cfg.x;
28 this.y = cfg.y;
29 this.width = cfg.width;
30 this.height = cfg.height;
31 this.dx = cfg.dx || 0;
32 this.dy = cfg.dy || 0;
33 this.isDraggable = cfg.isDraggable || false;
34 this.isClickable = cfg.isClickable || false;
35 this.fillStyle = cfg.fillStyle || "green";
36 this.visible = (cfg.visible === undefined ? true : (!!cfg.visible));
37 this._isBeingDragged = false;
38 return this;
39 };
40
41 this.getX = function() {
42 return this.x;
43 };
44
45 this.getLeftX = function() {
46 return this.x - this.width / 2;
47 };
48
49 this.getRightX = function() {
50 return this.x + this.width / 2;
51 };
52
53 this.getY = function() {
54 return this.y;
55 };
56
57 this.getTopY = function() {
58 return this.y - this.height / 2;
59 };
60
61 this.getBottomY = function() {
62 return this.y + this.height / 2;
63 };
64
65 this.getWidth = function() {
66 return this.width;
67 };
68
69 this.getHeight = function() {
70 return this.height;
71 };
72
73 this.isBeingDragged = function() {
74 return this._isBeingDragged;
75 };
76
77 /*
78 * Chainable.
79 */
80 this.setPosition = function(x, y) {
81 this.x = x;
82 this.y = y;
83 return this;
84 };
85
86 /*
87 * Chainable.
88 */
89 this.setDimensions = function(width, height) {
90 this.width = width;
91 this.height = height;
92 return this;
93 };
94
95 /*
96 * Chainable.
97 */
98 this.setVelocity = function(dx, dy) {
99 this.dx = dx;
100 this.dy = dy;
101 return this;
102 };
103
104 /*
105 * Chainable.
106 */
107 this.setDestination = function(x, y, ticks) {
108 this.destX = x;
109 this.destY = y;
110 this.setVelocity((this.destX - this.getX()) / ticks, (this.destY - this.getY()) / ticks);
111 this.destCounter = ticks;
112 return this;
113 };
114
115 this.move = function(x, y) {
116 this.x += this.dx;
117 this.y += this.dy;
118 this.onmove();
119 if (this.destCounter !== undefined) {
120 this.destCounter--;
121 if (this.destCounter <= 0) {
122 this.destCounter = undefined;
123 this.setPosition(this.destX, this.destY).setVelocity(0, 0);
124 this.onreachdestination();
125 }
126 }
127 };
128
129 // override this if your shape is not a rectangle
130 this.containsPoint = function(x, y) {
131 return (x >= this.getLeftX() && x <= this.getRightX() &&
132 y >= this.getTopY() && y <= this.getBottomY());
133 };
134
135 // you may need to override this in a sophisticated way if you
136 // expect it to detect sprites of different shapes intersecting
137 // assumes given sprite is LARGER THAN or EQUAL IN SIZE TO this.
138 this.intersects = function(sprite) {
139 var x1 = this.getLeftX();
140 var x2 = this.getRightX();
141 var y1 = this.getTopY();
142 var y2 = this.getBottomY();
143 return (sprite.containsPoint(x1, y1) || sprite.containsPoint(x2, y1) ||
144 sprite.containsPoint(x1, y2) || sprite.containsPoint(x2, y2));
145 };
146
147 // you will probably want to override this
148 // if you do, it's up to you to honour this.visible.
149 this.draw = function(ctx) {
150 if (!this.visible) return;
151 ctx.fillStyle = this.fillStyle || "green";
152 ctx.fillRect(this.getLeftX(), this.getTopY(), this.getWidth(), this.getHeight());
153 };
154
155 // event handlers. override to detect these events.
156 this.ongrab = function() {
157 };
158 this.ondrag = function() {
159 };
160 this.ondrop = function() {
161 };
162 this.onclick = function() {
163 };
164 this.onmove = function() {
165 };
166 this.onreachdestination = function() {
167 };
168
169 };
170
171 /*
172 * This still has a few shortcomings at the moment.
173 */
174 yoob.SpriteManager = function() {
175 /*
176 * Attach this SpriteManager to a canvas.
177 */
178 this.init = function(cfg) {
179 this.canvasX = undefined;
180 this.canvasY = undefined;
181 this.offsetX = undefined;
182 this.offsetY = undefined;
183 this.dragging = undefined;
184 this.sprites = [];
185
186 this.canvas = cfg.canvas;
187
188 return this;
189 };
190
191 this.move = function() {
192 this.foreach(function(sprite) {
193 sprite.move();
194 });
195 };
196
197 this.draw = function(ctx) {
198 if (ctx === undefined) {
199 ctx = this.canvas.getContext('2d');
200 }
201 this.foreach(function(sprite) {
202 sprite.draw(ctx);
203 });
204 };
205
206 this.addSprite = function(sprite) {
207 this.sprites.push(sprite);
208 };
209
210 this.removeSprite = function(sprite) {
211 var index = undefined;
212 for (var i = 0; i < this.sprites.length; i++) {
213 if (this.sprites[i] === sprite) {
214 index = i;
215 break;
216 }
217 }
218 if (index !== undefined) {
219 this.sprites.splice(index, 1);
220 }
221 };
222
223 this.clearSprites = function() {
224 this.sprites = [];
225 };
226
227 this.moveToFront = function(sprite) {
228 this.removeSprite(sprite);
229 this.sprites.push(sprite);
230 };
231
232 this.moveToBack = function(sprite) {
233 this.removeSprite(sprite);
234 this.sprites.unshift(sprite);
235 };
236
237 this.getSpriteAt = function(x, y) {
238 for (var i = this.sprites.length-1; i >= 0; i--) {
239 var sprite = this.sprites[i];
240 if (sprite.containsPoint(x, y)) {
241 return sprite;
242 }
243 }
244 return undefined;
245 };
246
247 this.foreach = function(fun) {
248 for (var i = this.sprites.length-1; i >= 0; i--) {
249 var sprite = this.sprites[i];
250 var result = fun(sprite);
251 if (result === 'remove') {
252 this.removeSprite(sprite);
253 }
254 if (result === 'return') {
255 return sprite;
256 }
257 }
258 };
259
260 };
261
262 yoob.Joystick = function() {
263 this.init = function() {
264 this.dx = 0;
265 this.dy = 0;
266 this.leftPressed = false;
267 this.rightPressed = false;
268 this.upPressed = false;
269 this.downPressed = false;
270 this.buttonPressed = false;
271 this.keyMap = {
272 17: this.fire,
273 37: this.left,
274 38: this.up,
275 39: this.right,
276 40: this.down
277 };
278 this.onchange = undefined;
279 return this;
280 };
281
282 this.fire = function(obj, pressed) {
283 if (obj.buttonPressed === pressed) return;
284 obj.buttonPressed = pressed;
285 if (obj.onchange !== undefined) obj.onchange();
286 };
287
288 this.left = function(obj, pressed) {
289 if (obj.leftPressed === pressed) return;
290 obj.leftPressed = pressed;
291 obj.dx = (obj.leftPressed ? -1 : 0) + (obj.rightPressed ? 1 : 0);
292 if (obj.onchange !== undefined) obj.onchange();
293 };
294
295 this.up = function(obj, pressed) {
296 if (obj.upPressed === pressed) return;
297 obj.upPressed = pressed;
298 obj.dy = (obj.upPressed ? -1 : 0) + (obj.downPressed ? 1 : 0);
299 if (obj.onchange !== undefined) obj.onchange();
300 };
301
302 this.right = function(obj, pressed) {
303 if (obj.rightPressed === pressed) return;
304 obj.rightPressed = pressed;
305 obj.dx = (obj.leftPressed ? -1 : 0) + (obj.rightPressed ? 1 : 0);
306 if (obj.onchange !== undefined) obj.onchange();
307 };
308
309 this.down = function(obj, pressed) {
310 if (obj.downPressed === pressed) return;
311 obj.downPressed = pressed;
312 obj.dy = (obj.upPressed ? -1 : 0) + (obj.downPressed ? 1 : 0);
313 if (obj.onchange !== undefined) obj.onchange();
314 };
315
316 this.attach = function(element) {
317 var $this = this;
318 element.addEventListener('keydown', function(e) {
319 var u = $this.keyMap[e.keyCode];
320 if (u !== undefined) {
321 u($this, true);
322 e.cancelBubble = true;
323 e.preventDefault();
324 }
325 }, true);
326 element.addEventListener('keyup', function(e) {
327 var u = $this.keyMap[e.keyCode];
328 if (u !== undefined) {
329 u($this, false);
330 e.cancelBubble = true;
331 e.preventDefault();
332 }
333 }, true);
334 };
335 };
336
337
338 var HERO_COLOR = 'black';
339 var TREASURE_COLOR = 'black';
340 var PIT_COLOR = 'black';
341 var BACKGROUND_COLOR = 'black';
342 var SCORE_COLOR = 'black';
343
344
345 var GamerlyRealism = function() {
346 this.init = function(canvas) {
347 this.canvas = canvas;
348
349 this.manager = (new yoob.SpriteManager()).init({ canvas: this.canvas });
350
351 this.joystick = (new yoob.Joystick()).init();
352 this.joystick.attach(document.documentElement);
353
354 return this;
355 };
356
357 this.reset = function() {
358 if (this.intervalId) {
359 clearInterval(this.intervalId);
360 }
361 this.manager.clearSprites();
362
363 this.numTreasures = 0;
364
365 this.hero = this.makeHero();
366 for (var i = 0; i < 10; i++) {
367 this.makePit();
368 }
369 this.makeTreasures();
370
371 this.score = 0;
372 this.lives = 3;
373
374 this.paused = false;
375 var $this = this;
376 this.intervalId = setInterval(function() {
377 $this.update();
378 $this.draw();
379 }, 1000 / 50);
380 };
381
382 this.makeHero = function() {
383 var d;
384 var done = false;
385 while (!done) {
386 d = new yoob.Sprite();
387 d.init({
388 x: Math.floor(Math.random() * this.canvas.width),
389 y: Math.floor(Math.random() * this.canvas.height),
390 width: 32,
391 height: 32
392 });
393 var cols = this.getCollisions(d);
394 if (cols.length === 0) {
395 done = true;
396 }
397 }
398 d.type = 'hero';
399 d.draw = function(ctx) {
400 ctx.fillStyle = HERO_COLOR;
401 ctx.fillRect(this.getLeftX(), this.getTopY(), this.getWidth(), this.getHeight());
402 };
403 this.manager.addSprite(d);
404 return d;
405 };
406
407 this.makePit = function() {
408 var d;
409 var done = false;
410 while (!done) {
411 d = new yoob.Sprite();
412 d.init({
413 x: Math.floor(Math.random() * this.canvas.width),
414 y: Math.floor(Math.random() * this.canvas.height),
415 width: 32,
416 height: 32
417 });
418 var cols = this.getCollisions(d);
419 if (cols.length === 0) {
420 done = true;
421 }
422 }
423 d.type = 'pit';
424 d.draw = function(ctx) {
425 ctx.fillStyle = PIT_COLOR;
426 ctx.fillRect(this.getLeftX(), this.getTopY(), this.getWidth(), this.getHeight());
427 };
428 this.manager.addSprite(d);
429 return d;
430 };
431
432 this.makeTreasure = function() {
433 var d;
434 var done = false;
435 while (!done) {
436 d = new yoob.Sprite();
437 d.init({
438 x: Math.floor(Math.random() * this.canvas.width),
439 y: Math.floor(Math.random() * this.canvas.height),
440 width: 16,
441 height: 16
442 });
443 var cols = this.getCollisionsSmaller(d);
444 if (cols.length === 0) {
445 done = true;
446 }
447 }
448 d.type = 'treasure';
449 d.draw = function(ctx) {
450 ctx.fillStyle = TREASURE_COLOR;
451 ctx.fillRect(this.getLeftX(), this.getTopY(), this.getWidth(), this.getHeight());
452 };
453 this.manager.addSprite(d);
454 this.numTreasures += 1;
455 return d;
456 };
457
458 this.makeTreasures = function() {
459 for (var i = 0; i < 10; i++) {
460 this.makeTreasure();
461 }
462 };
463
464 this.draw = function() {
465 var ctx = this.canvas.getContext('2d');
466 ctx.fillStyle = BACKGROUND_COLOR;
467 ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
468 this.manager.draw();
469
470 ctx.textBaseline = "top";
471 ctx.font = "32px Arial,Sans-serif";
472 ctx.fillStyle = SCORE_COLOR;
473 ctx.fillText('' + this.score, 0, 0);
474
475 ctx.textBaseline = "bottom";
476 var s = '';
477 for (var i = 0; i < this.lives; i++) {
478 s += 'O';
479 }
480 ctx.fillStyle = SCORE_COLOR;
481 ctx.fillText(s, 0, this.canvas.height);
482
483 };
484
485 // assumes target is LARGER than all sprites
486 this.getCollisions = function(target) {
487 var collisions = [];
488 this.manager.foreach(function(sprite) {
489 if (sprite !== target && sprite.intersects(target)) {
490 collisions.push(sprite);
491 }
492 });
493 return collisions;
494 };
495
496 // assumes target is SMALLER than all sprites
497 this.getCollisionsSmaller = function(target) {
498 var collisions = [];
499 this.manager.foreach(function(sprite) {
500 if (sprite !== target && target.intersects(sprite)) {
501 collisions.push(sprite);
502 }
503 });
504 return collisions;
505 };
506
507 this.update = function() {
508 if (this.paused || this.lives === 0) return;
509 this.hero.dx = this.joystick.dx;
510 this.hero.dy = this.joystick.dy;
511 this.manager.move();
512
513 var collisions = this.getCollisions(this.hero);
514 for (var i = 0; i < collisions.length; i++) {
515 var collided = collisions[i];
516 if (collided.type === 'treasure') {
517 this.manager.removeSprite(collided);
518 this.numTreasures -= 1;
519 this.score += 10;
520 if (this.numTreasures === 0) {
521 this.makeTreasures();
522 }
523 } else if (collided.type === 'pit') {
524 this.manager.removeSprite(collided);
525 this.manager.removeSprite(this.hero);
526 this.lives -= 1;
527 if (this.lives > 0) {
528 this.hero = this.makeHero();
529 }
530 }
531 }
532 };
533 };