littlejsengine 1.14.19 → 1.14.28

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.
Files changed (70) hide show
  1. package/dist/littlejs.d.ts +217 -38
  2. package/dist/littlejs.esm.js +879 -324
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +861 -324
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +799 -325
  7. package/examples/box2d/gameObjects.js +6 -10
  8. package/examples/box2d/scenes.js +2 -2
  9. package/examples/breakout/gameObjects.js +1 -1
  10. package/examples/electron/game.js +1 -41
  11. package/examples/electron/index.html +2 -2
  12. package/examples/htmlMenu/game.js +1 -1
  13. package/examples/index.html +19 -10
  14. package/examples/module/game.js +5 -7
  15. package/examples/particles/index.html +6 -9
  16. package/examples/platformer/gameCharacter.js +4 -3
  17. package/examples/platformer/gameEffects.js +7 -2
  18. package/examples/platformer/gameObjects.js +6 -11
  19. package/examples/shorts/animation.js +2 -2
  20. package/examples/shorts/base.html +4 -1
  21. package/examples/shorts/box2d.js +2 -2
  22. package/examples/shorts/box2dCar.js +18 -7
  23. package/examples/shorts/box2dPool.js +108 -0
  24. package/examples/shorts/cameraDrag.js +22 -0
  25. package/examples/shorts/debugDraw.js +37 -0
  26. package/examples/shorts/flappyGame.js +1 -0
  27. package/examples/shorts/fps.js +90 -0
  28. package/examples/shorts/helloWorld.js +1 -1
  29. package/examples/shorts/hillGlideGame.js +1 -3
  30. package/examples/shorts/input.js +59 -0
  31. package/examples/shorts/landerGame.js +1 -3
  32. package/examples/shorts/medals.js +15 -9
  33. package/examples/shorts/music.js +15 -17
  34. package/examples/shorts/musicPlayer.js +24 -24
  35. package/examples/shorts/platformer.js +0 -2
  36. package/examples/shorts/postProcess.js +1 -1
  37. package/examples/shorts/sequencer.js +3 -3
  38. package/examples/shorts/slidingPuzzle.js +1 -1
  39. package/examples/shorts/spaceGame.js +1 -3
  40. package/examples/shorts/spriteAtlas.js +6 -8
  41. package/examples/shorts/starfield.js +1 -1
  42. package/examples/shorts/tileRaycast.js +39 -0
  43. package/examples/shorts/tiles.png +0 -0
  44. package/examples/shorts/tiltedView.js +1 -4
  45. package/examples/shorts/timers.js +1 -2
  46. package/examples/shorts/topDown.js +0 -2
  47. package/examples/starter/game.js +5 -7
  48. package/examples/starter/index.html +2 -2
  49. package/examples/typescript/game.js +3 -2
  50. package/examples/typescript/game.ts +5 -7
  51. package/examples/uiSystem/game.js +2 -2
  52. package/package.json +1 -1
  53. package/plugins/box2d.js +170 -50
  54. package/plugins/pluginExport.js +2 -0
  55. package/plugins/uiSystem.js +55 -27
  56. package/src/engine.js +19 -16
  57. package/src/engineAudio.js +27 -15
  58. package/src/engineDebug.js +64 -0
  59. package/src/engineDraw.js +88 -32
  60. package/src/engineExport.js +16 -0
  61. package/src/engineInput.js +35 -25
  62. package/src/engineMedals.js +2 -2
  63. package/src/engineObject.js +55 -10
  64. package/src/engineParticles.js +36 -20
  65. package/src/engineRelease.js +2 -1
  66. package/src/engineSettings.js +20 -1
  67. package/src/engineTileLayer.js +64 -59
  68. package/src/engineUtilities.js +213 -59
  69. package/src/engineWebGL.js +13 -8
  70. package/examples/shorts/raycasting.js +0 -79
@@ -10,7 +10,7 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- /** A shortcut to get Math.PI
13
+ /** The value of PI
14
14
  * @type {number}
15
15
  * @default Math.PI
16
16
  * @memberof Utilities */
@@ -20,25 +20,80 @@ const PI = Math.PI;
20
20
  * @param {number} value
21
21
  * @return {number}
22
22
  * @memberof Utilities */
23
- function abs(value) { return Math.abs(value); }
23
+ const abs = Math.abs;
24
+
25
+ /** Returns floored value of value passed in
26
+ * @param {number} value
27
+ * @return {number}
28
+ * @memberof Utilities */
29
+ const floor = Math.floor;
30
+
31
+ /** Returns ceiled value of value passed in
32
+ * @param {number} value
33
+ * @return {number}
34
+ * @memberof Utilities */
35
+ const ceil = Math.ceil;
36
+
37
+ /** Returns rounded value passed in
38
+ * @param {number} value
39
+ * @return {number}
40
+ * @memberof Utilities */
41
+ const round = Math.round;
24
42
 
25
43
  /** Returns lowest value passed in
26
44
  * @param {...number} values
27
45
  * @return {number}
28
46
  * @memberof Utilities */
29
- function min(...values) { return Math.min(...values); }
47
+ const min = Math.min;
30
48
 
31
49
  /** Returns highest value passed in
32
50
  * @param {...number} values
33
51
  * @return {number}
34
52
  * @memberof Utilities */
35
- function max(...values) { return Math.max(...values); }
53
+ const max = Math.max;
36
54
 
37
55
  /** Returns the sign of value passed in
38
56
  * @param {number} value
39
57
  * @return {number}
40
58
  * @memberof Utilities */
41
- function sign(value) { return Math.sign(value); }
59
+ const sign = Math.sign;
60
+
61
+ /** Returns hypotenuse of values passed in
62
+ * @param {...number} values
63
+ * @return {number}
64
+ * @memberof Utilities */
65
+ const hypot = Math.hypot;
66
+
67
+ /** Returns log2 of value passed in
68
+ * @param {number} value
69
+ * @return {number}
70
+ * @memberof Utilities */
71
+ const log2 = Math.log2;
72
+
73
+ /** Returns sin of value passed in
74
+ * @param {number} value
75
+ * @return {number}
76
+ * @memberof Utilities */
77
+ const sin = Math.sin;
78
+
79
+ /** Returns cos of value passed in
80
+ * @param {number} value
81
+ * @return {number}
82
+ * @memberof Utilities */
83
+ const cos = Math.cos;
84
+
85
+ /** Returns tan of value passed in
86
+ * @param {number} value
87
+ * @return {number}
88
+ * @memberof Utilities */
89
+ const tan = Math.tan;
90
+
91
+ /** Returns atan2 of values passed in
92
+ * @param {number} y
93
+ * @param {number} x
94
+ * @return {number}
95
+ * @memberof Utilities */
96
+ const atan2 = Math.atan2;
42
97
 
43
98
  /** Returns first parm modulo the second param, but adjusted so negative numbers work as expected
44
99
  * @param {number} dividend
@@ -143,7 +198,7 @@ function isPowerOfTwo(value) { return !(value & (value - 1)); }
143
198
  * @param {number} value
144
199
  * @return {number}
145
200
  * @memberof Utilities */
146
- function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
201
+ function nearestPowerOfTwo(value) { return 2**ceil(log2(value)); }
147
202
 
148
203
  /** Returns true if two axis aligned bounding boxes are overlapping
149
204
  * this can be used for simple collision detection between objects
@@ -211,7 +266,7 @@ function isIntersecting(start, end, pos, size)
211
266
  * @return {number} - Value waving between 0 and amplitude
212
267
  * @memberof Utilities */
213
268
  function wave(frequency=1, amplitude=1, t=time, offset=0)
214
- { return amplitude/2 * (1 - Math.cos(offset + t*frequency*2*PI)); }
269
+ { return amplitude/2 * (1 - cos(offset + t*frequency*2*PI)); }
215
270
 
216
271
  /** Formats seconds to mm:ss style for display purposes
217
272
  * @param {number} t - time in seconds
@@ -250,6 +305,103 @@ function isNumber(n) { return typeof n === 'number' && !isNaN(n); }
250
305
  * @memberof Utilities */
251
306
  function isString(s) { return s !== undefined && s !== null && typeof s.toString() === 'string'; }
252
307
 
308
+ /**
309
+ * Check if object is an array
310
+ * @param {any} a
311
+ * @return {boolean}
312
+ * @memberof Utilities */
313
+ function isArray(a) { return Array.isArray(a); }
314
+
315
+ /**
316
+ * @callback LineTestFunction - Checks if a position is colliding
317
+ * @param {Vector2} pos
318
+ * @memberof Draw
319
+ */
320
+
321
+ /**
322
+ * Casts a ray and returns position of the first collision found, or undefined if none are found
323
+ * @param {Vector2} posStart
324
+ * @param {Vector2} posEnd
325
+ * @param {LineTestFunction} testFunction - Check if colliding
326
+ * @param {Vector2} [normal] - Optional vector to store the normal
327
+ * @return {Vector2|undefined} - Position of the collision or undefined if none found
328
+ * @memberof Utilities */
329
+ function lineTest(posStart, posEnd, testFunction, normal)
330
+ {
331
+ ASSERT(isVector2(posStart), 'posStart must be a vec2');
332
+ ASSERT(isVector2(posEnd), 'posEnd must be a vec2');
333
+ ASSERT(typeof testFunction === 'function', 'testFunction must be a function');
334
+ ASSERT(!normal || isVector2(normal), 'normal must be a vec2');
335
+
336
+ // get ray direction and length
337
+ const dx = posEnd.x - posStart.x;
338
+ const dy = posEnd.y - posStart.y;
339
+ const totalLength = hypot(dx, dy);
340
+ if (!totalLength)
341
+ return;
342
+
343
+ // current integer cell we are in
344
+ const pos = posStart.floor();
345
+
346
+ // normalize ray direction
347
+ const dirX = dx / totalLength;
348
+ const dirY = dy / totalLength;
349
+
350
+ // step direction in grid
351
+ const stepX = sign(dirX);
352
+ const stepY = sign(dirY);
353
+
354
+ // distance along the ray to cross one full cell in X or Y
355
+ const tDeltaX = dirX ? abs(1 / dirX) : Infinity;
356
+ const tDeltaY = dirY ? abs(1 / dirY) : Infinity;
357
+
358
+ // distance along the ray from start to the first grid boundary
359
+ const nextGridX = stepX > 0 ? pos.x + 1 : pos.x;
360
+ const nextGridY = stepY > 0 ? pos.y + 1 : pos.y;
361
+ const tMaxX = dirX ? (nextGridX - posStart.x) / dirX : Infinity;
362
+ const tMaxY = dirY ? (nextGridY - posStart.y) / dirY : Infinity;
363
+
364
+ // use line drawing algorithm to test for collisions
365
+ let t = 0, tX = tMaxX, tY = tMaxY, wasX = tDeltaX < tDeltaY;
366
+ while (t < totalLength)
367
+ {
368
+ if (testFunction(pos))
369
+ {
370
+ // set hit point
371
+ const hitPos = vec2(posStart.x + dirX*t, posStart.y + dirY*t);
372
+
373
+ // move inside of tile if on positive edge
374
+ const e = 1e-9;
375
+ if (wasX)
376
+ {
377
+ if (stepX < 0)
378
+ hitPos.x -= e;
379
+ }
380
+ if (stepY < 0)
381
+ hitPos.y -= e;
382
+
383
+ // set normal
384
+ if (normal)
385
+ wasX ? normal.set(-stepX,0) : normal.set(0,-stepY);
386
+ return hitPos;
387
+ }
388
+
389
+ // advance to the next grid boundary
390
+ if (wasX = tX < tY)
391
+ {
392
+ pos.x += stepX;
393
+ t = tX;
394
+ tX += tDeltaX;
395
+ }
396
+ else
397
+ {
398
+ pos.y += stepY;
399
+ t = tY;
400
+ tY += tDeltaY;
401
+ }
402
+ }
403
+ }
404
+
253
405
  ///////////////////////////////////////////////////////////////////////////////
254
406
 
255
407
  /** Random global functions
@@ -268,7 +420,7 @@ function rand(valueA=1, valueB=0) { return valueB + Math.random() * (valueA-valu
268
420
  * @param {number} [valueB]
269
421
  * @return {number}
270
422
  * @memberof Random */
271
- function randInt(valueA, valueB=0) { return Math.floor(rand(valueA,valueB)); }
423
+ function randInt(valueA, valueB=0) { return floor(rand(valueA,valueB)); }
272
424
 
273
425
  /** Randomly returns true or false given the chance of true passed in
274
426
  * @param {number} [chance]
@@ -347,7 +499,7 @@ class RandomGenerator
347
499
  * @param {number} valueA
348
500
  * @param {number} [valueB]
349
501
  * @return {number} */
350
- int(valueA, valueB=0) { return Math.floor(this.float(valueA, valueB)); }
502
+ int(valueA, valueB=0) { return floor(this.float(valueA, valueB)); }
351
503
 
352
504
  /** Randomly returns true or false given the chance of true passed in
353
505
  * @param {number} [chance]
@@ -374,6 +526,39 @@ class RandomGenerator
374
526
  * @return {Vector2} */
375
527
  vec2(valueA=1, valueB=0)
376
528
  { return vec2(this.float(valueA, valueB), this.float(valueA, valueB)); }
529
+
530
+ /** Returns a random color between the two passed in colors, combine components if linear
531
+ * @param {Color} [colorA=(1,1,1,1)]
532
+ * @param {Color} [colorB=(0,0,0,1)]
533
+ * @param {boolean} [linear]
534
+ * @return {Color} */
535
+ randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear=false)
536
+ {
537
+ return linear ? colorA.lerp(colorB, this.float()) :
538
+ new Color(
539
+ this.float(colorA.r,colorB.r),
540
+ this.float(colorA.g,colorB.g),
541
+ this.float(colorA.b,colorB.b),
542
+ this.float(colorA.a,colorB.a));
543
+ }
544
+
545
+ /** Returns a new color that has each component randomly adjusted
546
+ * @param {Color} color
547
+ * @param {number} [amount]
548
+ * @param {number} [alphaAmount]
549
+ * @return {Color} */
550
+ mutateColor(color, amount=.05, alphaAmount=0)
551
+ {
552
+ ASSERT_NUMBER_VALID(amount);
553
+ ASSERT_NUMBER_VALID(alphaAmount);
554
+ return new Color
555
+ (
556
+ color.r + this.float(amount, -amount),
557
+ color.g + this.float(amount, -amount),
558
+ color.b + this.float(amount, -amount),
559
+ color.a + this.float(alphaAmount, -alphaAmount)
560
+ ).clamp();
561
+ }
377
562
  }
378
563
 
379
564
  ///////////////////////////////////////////////////////////////////////////////
@@ -525,7 +710,7 @@ class Vector2
525
710
 
526
711
  /** Returns the clockwise angle of this vector, up is angle 0
527
712
  * @return {number} */
528
- angle() { return Math.atan2(this.x, this.y); }
713
+ angle() { return atan2(this.x, this.y); }
529
714
 
530
715
  /** Sets this vector with clockwise angle and length passed in
531
716
  * @param {number} [angle]
@@ -535,8 +720,8 @@ class Vector2
535
720
  {
536
721
  ASSERT_NUMBER_VALID(angle);
537
722
  ASSERT_NUMBER_VALID(length);
538
- this.x = length*Math.sin(angle);
539
- this.y = length*Math.cos(angle);
723
+ this.x = length*sin(angle);
724
+ this.y = length*cos(angle);
540
725
  return this;
541
726
  }
542
727
 
@@ -546,7 +731,7 @@ class Vector2
546
731
  rotate(angle)
547
732
  {
548
733
  ASSERT_NUMBER_VALID(angle);
549
- const c = Math.cos(-angle), s = Math.sin(-angle);
734
+ const c = cos(-angle), s = sin(-angle);
550
735
  return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
551
736
  }
552
737
 
@@ -578,7 +763,7 @@ class Vector2
578
763
 
579
764
  /** Returns a copy of this vector with each axis floored
580
765
  * @return {Vector2} */
581
- floor() { return new Vector2(Math.floor(this.x), Math.floor(this.y)); }
766
+ floor() { return new Vector2(floor(this.x), floor(this.y)); }
582
767
 
583
768
  /** Returns new vec2 with modded values
584
769
  * @param {number} [divisor]
@@ -826,7 +1011,6 @@ class Color
826
1011
  * @return {string} */
827
1012
  toString(useAlpha = true)
828
1013
  {
829
- ASSERT(typeof useAlpha === 'boolean', 'Use alpha boolean is invalid.', useAlpha);
830
1014
  if (debug && !this.isValid())
831
1015
  return `#000`;
832
1016
  const toHex = (c)=> ((c=clamp(c)*255|0)<16 ? '0' : '') + c.toString(16);
@@ -886,67 +1070,67 @@ class Color
886
1070
  /** Color - White #ffffff
887
1071
  * @type {Color}
888
1072
  * @memberof Utilities */
889
- const WHITE = protectEngineConstant(rgb());
1073
+ const WHITE = debugProtectConstant(rgb());
890
1074
 
891
1075
  /** Color - Clear White #757474ff with 0 alpha
892
1076
  * @type {Color}
893
1077
  * @memberof Utilities */
894
- const CLEAR_WHITE = protectEngineConstant(rgb(1,1,1,0));
1078
+ const CLEAR_WHITE = debugProtectConstant(rgb(1,1,1,0));
895
1079
 
896
1080
  /** Color - Black #000000
897
1081
  * @type {Color}
898
1082
  * @memberof Utilities */
899
- const BLACK = protectEngineConstant(rgb(0,0,0));
1083
+ const BLACK = debugProtectConstant(rgb(0,0,0));
900
1084
 
901
1085
  /** Color - Clear Black #000000 with 0 alpha
902
1086
  * @type {Color}
903
1087
  * @memberof Utilities */
904
- const CLEAR_BLACK = protectEngineConstant(rgb(0,0,0,0));
1088
+ const CLEAR_BLACK = debugProtectConstant(rgb(0,0,0,0));
905
1089
 
906
1090
  /** Color - Gray #808080
907
1091
  * @type {Color}
908
1092
  * @memberof Utilities */
909
- const GRAY = protectEngineConstant(rgb(.5,.5,.5));
1093
+ const GRAY = debugProtectConstant(rgb(.5,.5,.5));
910
1094
 
911
1095
  /** Color - Red #ff0000
912
1096
  * @type {Color}
913
1097
  * @memberof Utilities */
914
- const RED = protectEngineConstant(rgb(1,0,0));
1098
+ const RED = debugProtectConstant(rgb(1,0,0));
915
1099
 
916
1100
  /** Color - Orange #ff8000
917
1101
  * @type {Color}
918
1102
  * @memberof Utilities */
919
- const ORANGE = protectEngineConstant(rgb(1,.5,0));
1103
+ const ORANGE = debugProtectConstant(rgb(1,.5,0));
920
1104
 
921
1105
  /** Color - Yellow #ffff00
922
1106
  * @type {Color}
923
1107
  * @memberof Utilities */
924
- const YELLOW = protectEngineConstant(rgb(1,1,0));
1108
+ const YELLOW = debugProtectConstant(rgb(1,1,0));
925
1109
 
926
1110
  /** Color - Green #00ff00
927
1111
  * @type {Color}
928
1112
  * @memberof Utilities */
929
- const GREEN = protectEngineConstant(rgb(0,1,0));
1113
+ const GREEN = debugProtectConstant(rgb(0,1,0));
930
1114
 
931
1115
  /** Color - Cyan #00ffff
932
1116
  * @type {Color}
933
1117
  * @memberof Utilities */
934
- const CYAN = protectEngineConstant(rgb(0,1,1));
1118
+ const CYAN = debugProtectConstant(rgb(0,1,1));
935
1119
 
936
1120
  /** Color - Blue #0000ff
937
1121
  * @type {Color}
938
1122
  * @memberof Utilities */
939
- const BLUE = protectEngineConstant(rgb(0,0,1));
1123
+ const BLUE = debugProtectConstant(rgb(0,0,1));
940
1124
 
941
1125
  /** Color - Purple #8000ff
942
1126
  * @type {Color}
943
1127
  * @memberof Utilities */
944
- const PURPLE = protectEngineConstant(rgb(.5,0,1));
1128
+ const PURPLE = debugProtectConstant(rgb(.5,0,1));
945
1129
 
946
1130
  /** Color - Magenta #ff00ff
947
1131
  * @type {Color}
948
1132
  * @memberof Utilities */
949
- const MAGENTA = protectEngineConstant(rgb(1,0,1));
1133
+ const MAGENTA = debugProtectConstant(rgb(1,0,1));
950
1134
 
951
1135
  ///////////////////////////////////////////////////////////////////////////////
952
1136
 
@@ -1009,39 +1193,9 @@ class Timer
1009
1193
 
1010
1194
  /** Returns this timer expressed as a string
1011
1195
  * @return {string} */
1012
- toString() { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }
1196
+ toString() { return this.isSet() ? abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }
1013
1197
 
1014
1198
  /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
1015
1199
  * @return {number} */
1016
1200
  valueOf() { return this.get(); }
1017
- }
1018
-
1019
- ///////////////////////////////////////////////////////////////////////////////
1020
- // Helper functions used by the engine
1021
-
1022
- // make color constants immutable with debug assertions
1023
- function protectEngineConstant(obj)
1024
- {
1025
- if (debug)
1026
- {
1027
- // get properties and store original values
1028
- const props = Object.keys(obj), values = {};
1029
- props.forEach(prop => values[prop] = obj[prop]);
1030
-
1031
- // replace with getters/setters that assert
1032
- props.forEach(prop =>
1033
- {
1034
- Object.defineProperty(obj, prop, {
1035
- get: () => values[prop],
1036
- set: (value) =>
1037
- {
1038
- ASSERT(false, `Cannot modify engine constant. Attempted to set constant (${obj}) property '${prop}' to '${value}'.`);
1039
- },
1040
- enumerable: true
1041
- });
1042
- });
1043
- }
1044
-
1045
- // freeze the object to prevent adding new properties
1046
- return Object.freeze(obj);
1047
1201
  }
@@ -29,7 +29,7 @@ let glContext;
29
29
  let glAntialias = true;
30
30
 
31
31
  // WebGL internal variables not exposed to documentation
32
- let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount, glTextureInfos;
32
+ let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount, glTextureInfos, glCanBeEnabled = true;
33
33
 
34
34
  // WebGL internal constants
35
35
  const gl_ARRAY_BUFFER_SIZE = 5e5;
@@ -48,7 +48,11 @@ function glInit()
48
48
  // keep set of texture infos so they can be restored if context is lost
49
49
  glTextureInfos = new Set;
50
50
 
51
- if (!glEnable || headlessMode) return;
51
+ if (!glEnable || headlessMode)
52
+ {
53
+ glCanBeEnabled = false;
54
+ return;
55
+ }
52
56
 
53
57
  // create the canvas and textures
54
58
  glCanvas = document.createElement('canvas');
@@ -59,10 +63,11 @@ function glInit()
59
63
  console.warn('WebGL2 not supported, falling back to 2D canvas rendering!');
60
64
  glCanvas = glContext = undefined;
61
65
  glEnable = false;
66
+ glCanBeEnabled = false;
62
67
  return;
63
68
  }
64
69
 
65
- // create the WebGL canvas
70
+ // attach the WebGL canvas
66
71
  const rootElement = mainCanvas.parentElement;
67
72
  rootElement.appendChild(glCanvas);
68
73
 
@@ -85,7 +90,7 @@ function glInit()
85
90
  });
86
91
  glCanvas.addEventListener('webglcontextrestored', ()=>
87
92
  {
88
- glEnable = true; // disable WebGL rendering
93
+ glEnable = true; // re-enable WebGL rendering
89
94
  glCanvas.style.display = ''; // show the gl canvas
90
95
  LOG('WebGL context restored, reinitializing...');
91
96
 
@@ -237,8 +242,8 @@ function glPreRender()
237
242
  const s = vec2(2*cameraScale).divide(mainCanvasSize);
238
243
  const rotatedCam = cameraPos.rotate(-cameraAngle);
239
244
  const p = vec2(-1).subtract(rotatedCam.multiply(s));
240
- const ca = Math.cos(cameraAngle);
241
- const sa = Math.sin(cameraAngle);
245
+ const ca = cos(cameraAngle);
246
+ const sa = sin(cameraAngle);
242
247
  const transform = [
243
248
  s.x * ca, s.y * sa, 0, 0,
244
249
  -s.x * sa, s.y * ca, 0, 0,
@@ -543,8 +548,8 @@ function glDrawPointsTransform(points, rgba, x, y, sx, sy, angle, tristrip=true)
543
548
  // transform the point
544
549
  const px = p.x*sx;
545
550
  const py = p.y*sy;
546
- const sa = Math.sin(-angle);
547
- const ca = Math.cos(-angle);
551
+ const sa = sin(-angle);
552
+ const ca = cos(-angle);
548
553
  pointsOut.push(vec2(x + ca*px - sa*py, y + sa*px + ca*py));
549
554
  }
550
555
  const drawPoints = tristrip ? glPolyStrip(pointsOut) : pointsOut;
@@ -1,79 +0,0 @@
1
- let playerPos = vec2(), playerAngle = 0;
2
-
3
- // a simple function to generate a level
4
- const levelTest = (X,Y)=> ((X|0)**3&(Y|0)**2)%30>5;
5
-
6
- // cast a ray and return the distance to the first wall hit (0-1)
7
- function raycast(pos, angle)
8
- {
9
- const maxDistance = 40, delta = .05;
10
- const rayX = delta*Math.sin(angle);
11
- const rayY = delta*Math.cos(angle);
12
- let posX = pos.x, posY = pos.y;
13
- for (let distance = 0; distance < maxDistance; distance += delta)
14
- {
15
- if (levelTest(posX, posY))
16
- return distance/maxDistance;
17
- posX += rayX;
18
- posY += rayY;
19
- }
20
- return 1;
21
- }
22
-
23
- function gameUpdate()
24
- {
25
- // update camera angle with mouse pointer lock
26
- if (mouseWasPressed(0))
27
- pointerLockRequest();
28
- if (keyWasPressed('Escape'))
29
- pointerLockExit()
30
- if (pointerLockIsActive() || isTouchDevice)
31
- playerAngle += mouseDelta.x * .003;
32
-
33
- // update player movement, prevent walking through walls
34
- let velocity = keyDirection();
35
- if (velocity.y && mouseIsDown(0))
36
- velocity.y = 1; // forward movement with mouse
37
- velocity = velocity.rotate(playerAngle).scale(.1);
38
- const newPos = playerPos.add(velocity);
39
- if (!levelTest(newPos.x, newPos.y))
40
- playerPos = newPos;
41
- }
42
-
43
- function gameRender()
44
- {
45
- {
46
- // draw horizontal slizes to create floor and ceiling
47
- const h = 9;
48
- let pos = vec2(), size = vec2(39, .15), color = rgb();
49
- for (let y=-h; y<h; y+=.1)
50
- {
51
- const p = 1.01-abs(y/h)
52
- pos.y = y;
53
- color.setHSLA(.1, y>0?0:.5, .7-p*.7);
54
- drawRect(pos, size, color);
55
- }
56
- }
57
- {
58
- // draw vertical slices to create the walls
59
- const w = 20;
60
- const pos = vec2(), size = vec2(.15), color = rgb();
61
- for (let x=-w; x<w; x+=.1)
62
- {
63
- const p = raycast(playerPos, playerAngle + x/w);
64
- pos.x = x;
65
- size.y = .4/p;
66
- color.setHSLA(.6, .5, .7-p*.7);
67
- drawRect(pos, size, color);
68
- }
69
- }
70
- // draw instructions and pointer lock status
71
- const instructions = pointerLockIsActive() ?
72
- 'Mouse Control Active - ESC To Exit' :
73
- 'Click To Enable Mouse Control';
74
- const textPos = vec2(mainCanvasSize.x/2, 50);
75
- const textSize = 24;
76
- const textColor = pointerLockIsActive() ? GREEN : WHITE;
77
- if (!isTouchDevice)
78
- drawTextScreen(instructions, textPos, textSize, textColor);
79
- }