littlejsengine 1.12.6 → 1.13.4

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 (102) hide show
  1. package/README.md +15 -12
  2. package/dist/littlejs.d.ts +466 -236
  3. package/dist/littlejs.esm.js +6126 -5370
  4. package/dist/littlejs.esm.min.js +4 -1
  5. package/dist/littlejs.js +6093 -5359
  6. package/dist/littlejs.min.js +4 -1
  7. package/dist/littlejs.release.js +5614 -4907
  8. package/examples/box2d/game.js +2 -2
  9. package/examples/box2d/gameObjects.js +8 -7
  10. package/examples/box2d/index.html +1 -1
  11. package/examples/box2d/scenes.js +8 -8
  12. package/examples/breakout/game.js +1 -1
  13. package/examples/breakout/gameObjects.js +2 -2
  14. package/examples/breakout/index.html +1 -1
  15. package/examples/breakoutTutorial/README.md +46 -43
  16. package/examples/breakoutTutorial/game.js +3 -3
  17. package/examples/breakoutTutorial/index.html +1 -1
  18. package/examples/electron/build.bat +7 -0
  19. package/examples/electron/build.js +124 -0
  20. package/examples/electron/electron.js +35 -0
  21. package/examples/electron/game.js +140 -0
  22. package/examples/electron/index.html +13 -0
  23. package/examples/electron/package.json +12 -0
  24. package/examples/electron/tiles.png +0 -0
  25. package/examples/empty/game.js +1 -0
  26. package/examples/empty/index.html +1 -1
  27. package/examples/htmlMenu/game.js +1 -1
  28. package/examples/htmlMenu/index.html +1 -1
  29. package/examples/index.html +486 -182
  30. package/examples/module/game.js +6 -3
  31. package/examples/module/index.html +1 -1
  32. package/examples/particles/index.html +12 -3
  33. package/examples/platformer/game.js +4 -4
  34. package/examples/platformer/gameCharacter.js +6 -6
  35. package/examples/platformer/gameEffects.js +74 -57
  36. package/examples/platformer/gameLevel.js +61 -70
  37. package/examples/platformer/gameObjects.js +4 -4
  38. package/examples/platformer/index.html +1 -1
  39. package/examples/puzzle/index.html +1 -1
  40. package/examples/shorts/base.html +23 -3
  41. package/examples/shorts/blending.js +9 -5
  42. package/examples/shorts/box2d.js +1 -1
  43. package/examples/shorts/box2dCar.js +9 -13
  44. package/examples/shorts/clock.js +1 -1
  45. package/examples/shorts/colors.js +2 -2
  46. package/examples/shorts/flappyGame.js +52 -0
  47. package/examples/shorts/helloWorld.js +6 -3
  48. package/examples/shorts/hillGlideGame.js +56 -0
  49. package/examples/shorts/landerGame.js +32 -0
  50. package/examples/shorts/maze.js +47 -0
  51. package/examples/shorts/medals.js +42 -0
  52. package/examples/shorts/nineSlice.js +21 -0
  53. package/examples/shorts/piano.js +52 -0
  54. package/examples/shorts/platformer.js +24 -20
  55. package/examples/shorts/{pong.js → pongGame.js} +1 -1
  56. package/examples/shorts/raycasting.js +71 -0
  57. package/examples/shorts/shapes.js +9 -9
  58. package/examples/shorts/slidingPuzzle.js +42 -0
  59. package/examples/shorts/spaceGame.js +56 -0
  60. package/examples/shorts/starfield.js +15 -0
  61. package/examples/shorts/systemFont.js +1 -1
  62. package/examples/shorts/tileLayer.js +3 -5
  63. package/examples/shorts/tiles.png +0 -0
  64. package/examples/shorts/tiltedView.js +8 -7
  65. package/examples/shorts/topDown.js +18 -26
  66. package/examples/shorts/uiSystem.js +5 -7
  67. package/examples/starter/build.bat +6 -1
  68. package/examples/starter/build.js +9 -8
  69. package/examples/starter/game.js +7 -4
  70. package/examples/starter/index.html +23 -13
  71. package/examples/stress/index.html +7 -8
  72. package/examples/style.css +139 -0
  73. package/examples/typescript/build.js +2 -3
  74. package/examples/typescript/game.js +4 -4
  75. package/examples/typescript/game.ts +6 -3
  76. package/examples/typescript/index.html +1 -1
  77. package/examples/uiSystem/game.js +10 -25
  78. package/examples/uiSystem/index.html +1 -1
  79. package/package.json +2 -2
  80. package/plugins/box2d.js +22 -97
  81. package/plugins/drawUtilities.js +132 -0
  82. package/plugins/newgrounds.js +1 -1
  83. package/plugins/pluginExport.js +7 -1
  84. package/plugins/postProcess.js +9 -2
  85. package/plugins/uiSystem.js +155 -67
  86. package/plugins/zzfxm.js +1 -1
  87. package/reference.md +10 -10
  88. package/src/engine.js +56 -30
  89. package/src/engineAudio.js +15 -6
  90. package/src/engineBuild.bat +6 -1
  91. package/src/engineBuild.js +20 -5
  92. package/src/engineDebug.js +55 -28
  93. package/src/engineDraw.js +321 -177
  94. package/src/engineExport.js +27 -9
  95. package/src/engineInput.js +110 -38
  96. package/src/engineMedals.js +4 -4
  97. package/src/engineObject.js +71 -70
  98. package/src/engineParticles.js +33 -9
  99. package/src/engineSettings.js +69 -23
  100. package/src/engineTileLayer.js +312 -153
  101. package/src/engineUtilities.js +187 -135
  102. package/src/engineWebGL.js +70 -39
@@ -10,7 +10,7 @@ async function gameInit()
10
10
  groundObject.addBox(vec2(100,2));
11
11
 
12
12
  // add some random objects
13
- for(let i=50; i--;)
13
+ for (let i=50; i--;)
14
14
  {
15
15
  const o = new Box2dObject(randInCircle(5), vec2(), 0, 0, randColor());
16
16
  randInt(2) ? o.addCircle(rand(1,2)) : o.addRandomPoly(rand(1,2));
@@ -14,11 +14,11 @@ class CarObject extends Box2dObject
14
14
  {
15
15
  super(pos, vec2(), 0, 0, RED);
16
16
 
17
- // create a car with wheels
17
+ // create car with wheels
18
18
  this.addBox(vec2(7,2));
19
19
  const frequency = 4, maxTorque = 250;
20
20
  this.wheels = [];
21
- for(let i=2; i--;)
21
+ for (let i=2; i--;)
22
22
  {
23
23
  const wheelPos = pos.add(vec2(i?2:-2, -1));
24
24
  const wheel = new Box2dObject(wheelPos, vec2(2), tile(7));
@@ -26,24 +26,20 @@ class CarObject extends Box2dObject
26
26
  joint.setSpringFrequencyHz(frequency);
27
27
  joint.setMaxMotorTorque(maxTorque);
28
28
  joint.enableMotor(!i);
29
- wheel.addCircle(2);
29
+ wheel.addCircle(2, vec2(), 1, 1);
30
30
  wheel.motorJoint = joint;
31
31
  this.wheels[i] = wheel;
32
32
  }
33
33
  }
34
34
  update()
35
35
  {
36
- // car controls - use arrow keys or A/D to drive
37
- const maxSpeed = 40, brakeAmount = .9;
38
- const input = keyDirection().x;
36
+ super.update();
37
+
38
+ // car controls - use mouse, arrow keys, or A/D to drive
39
+ const maxSpeed = 40;
40
+ const input = keyDirection().x || mouseIsDown(0);
39
41
  let s = this.wheels[0].motorJoint.getMotorSpeed();
40
- s = input ? clamp(s - input, -maxSpeed, maxSpeed) : s * brakeAmount;
42
+ s = input ? clamp(s - input, -maxSpeed, maxSpeed) : 0;
41
43
  this.wheels[0].motorJoint.setMotorSpeed(s);
42
- super.update();
43
- }
44
- destroy()
45
- {
46
- this.wheels.forEach(o=>o.destroy());
47
- super.destroy();
48
44
  }
49
45
  }
@@ -1,7 +1,7 @@
1
1
  function gameRender()
2
2
  {
3
3
  // draw background
4
- for(let i=12; i--;)
4
+ for (let i=12; i--;)
5
5
  {
6
6
  const a = i/6*PI;
7
7
  const pos = vec2(0,7).rotate(a);
@@ -10,12 +10,12 @@ function gameRender()
10
10
  // rgb and hsl color
11
11
  drawRect(vec2(-8, 0), vec2(3), new Color(1,0,0));
12
12
  drawRect(vec2(-4, 0), vec2(3), rgb(0,1,1));
13
- drawRect(vec2(-0, 0), vec2(3), hsl(0,1,.5));
13
+ drawRect(vec2(-0, 0), vec2(3), hsl(0,1,.5, .5));
14
14
  drawRect(vec2( 4, 0), vec2(3), hsl(.6,.5,.5));
15
15
  drawRect(vec2( 8, 0), vec2(3), hsl(0,0,1));
16
16
 
17
17
  // color lerpping
18
- for(let i=5; i--;)
18
+ for (let i=5; i--;)
19
19
  {
20
20
  const color1 = RED;
21
21
  const color2 = YELLOW;
@@ -0,0 +1,52 @@
1
+ class Wall extends EngineObject
2
+ {
3
+ constructor(pos, size)
4
+ {
5
+ super(pos, size, 0, 0, hsl(.4,.5,.4));
6
+ this.setCollision(); // make object collide
7
+ }
8
+ update()
9
+ {
10
+ this.pos.x -= .1; // move walls to the left
11
+ }
12
+ }
13
+
14
+ class Player extends EngineObject
15
+ {
16
+ constructor(pos)
17
+ {
18
+ super(pos, vec2(1), tile(9), 0, YELLOW);
19
+ this.drawSize = vec2(2);
20
+ this.setCollision(); // make object collide
21
+ }
22
+
23
+ update()
24
+ {
25
+ super.update();
26
+
27
+ // flappy movement controls
28
+ if (mouseWasPressed(0) || keyWasPressed('Space'))
29
+ this.velocity = vec2(0,.2);
30
+ this.angle = -this.velocity.y*2;
31
+ }
32
+
33
+ collideWithObject(object)
34
+ {
35
+ // reset game
36
+ engineObjectsDestroy();
37
+ gameInit();
38
+ }
39
+ }
40
+
41
+ function gameInit()
42
+ {
43
+ // setup level
44
+ gravity.y = -.01;
45
+ for (let i=100; i--;)
46
+ {
47
+ const h=50, y=-h/2-6+rand(9), spacing=15, gap=5;
48
+ new Wall(vec2(14 + i*spacing,y+h + gap), vec2(3,h));
49
+ new Wall(vec2(14 + i*spacing,y), vec2(3,h));
50
+ }
51
+ new Player(vec2(-7,6));
52
+ }
@@ -1,8 +1,11 @@
1
1
  function gameRender()
2
2
  {
3
- // draw text
4
- drawText('Hello World', vec2(0,2), 3);
3
+ // draw background rect
4
+ drawRect(cameraPos, vec2(30), hsl(0,0,.2));
5
+
6
+ // draw text to the overlay canvas
7
+ drawTextOverlay('Hello World', vec2(0,3), 3);
5
8
 
6
9
  // draw a tile
7
- drawTile(vec2(0,-2), vec2(7), tile(3,128));
10
+ drawTile(vec2(Math.sin(time)*3,-2), vec2(7), tile(3,128));
8
11
  }
@@ -0,0 +1,56 @@
1
+ class Player extends EngineObject
2
+ {
3
+ constructor(pos)
4
+ {
5
+ super(pos, vec2(2), tile(9), 0, CYAN);
6
+ this.damping = 1; // disable damping
7
+ this.clampSpeed = false; // disable speed clamping
8
+ }
9
+
10
+ update()
11
+ {
12
+ super.update();
13
+
14
+ const h = getGroundHeight(this.pos.x);
15
+ if (this.pos.y < h + this.size.y/2)
16
+ {
17
+ // clamp to ground and reflect velocity
18
+ this.pos.y = h + this.size.y/2;
19
+ const n = vec2((h-getGroundHeight(this.pos.x+.1))/.1, 1).normalize();
20
+ this.velocity = this.velocity.reflect(n,0);
21
+ }
22
+
23
+ // apply movement controls
24
+ if (mouseIsDown(0) || keyIsDown('Space'))
25
+ this.applyAcceleration(vec2(0,-.05));
26
+ this.velocity.x = max(this.velocity.x,.4);
27
+ this.angle = this.velocity.angle() - PI/2;
28
+
29
+ // move camera with player
30
+ cameraPos = vec2(this.pos.x+9,5);
31
+ }
32
+ }
33
+
34
+ function getGroundHeight(x)
35
+ {
36
+ return Math.sin(x/4)*2 + Math.sin(x/17);
37
+ }
38
+
39
+ function gameInit()
40
+ {
41
+ gravity.y = -.01;
42
+ new Player(vec2(0,5));
43
+ }
44
+
45
+ function gameRender()
46
+ {
47
+ const h = 100, w = 20;
48
+ const pos = vec2(), size = vec2(.2,h), color = WHITE;
49
+ for (let x=cameraPos.x-w; x<cameraPos.x+w; x+=.1)
50
+ {
51
+ pos.x = x;
52
+ pos.y = getGroundHeight(x)-h/2;
53
+ color.setHSLA(.2+.2*wave(.2,1,x), .5, .5);
54
+ drawRect(pos, size, color);
55
+ }
56
+ }
@@ -0,0 +1,32 @@
1
+ class Player extends EngineObject
2
+ {
3
+ constructor(pos)
4
+ {
5
+ super(pos, vec2(1,2), tile(8), 0, RED);
6
+ this.setCollision(); // make object collide
7
+ }
8
+
9
+ update()
10
+ {
11
+ super.update();
12
+
13
+ // apply movement controls
14
+ this.applyAcceleration(keyDirection().scale(.002));
15
+ }
16
+ }
17
+
18
+ function gameInit()
19
+ {
20
+ // setup level
21
+ gravity.y = -.001;
22
+ new Player(vec2(0,4));
23
+
24
+ // create ground
25
+ for (let i=0, y=0; i<20; ++i)
26
+ {
27
+ y = (y + rand(1,-1)*4) * .5;
28
+ const o = new EngineObject(vec2(i*2-20, y-54), vec2(2, 99), 0, 0, hsl(0,0,.5+i%.29));
29
+ o.setCollision(); // make object collide
30
+ o.mass = 0; // make object have static physics
31
+ }
32
+ }
@@ -0,0 +1,47 @@
1
+ function generateMaze(size)
2
+ {
3
+ const maze = [], w = size.x, h = size.y;
4
+ maze[1 + w] = 1; // start point
5
+ for (let k=w*h*9|0; k--;)
6
+ {
7
+ // get a random position on odd coordinates
8
+ const jx = randInt(w/2-(w%2?0:2)|0)*2 + 1;
9
+ const jy = randInt(h/2-(h%2?1:2)|0)*2 + 1;
10
+ const j = jx + jy*w;
11
+
12
+ // get a random direction
13
+ const d = randSign() * (randBool() ? 1 : w);
14
+
15
+ // check if we are not the same line or column
16
+ if (j%w != (j+d*2)%w && (j/w|0) != ((j+d*2)/w|0))
17
+ continue;
18
+
19
+ // check if pos is open and the next 2 cells are closed
20
+ if (maze[j] && !maze[j+d] && !maze[j+d*2])
21
+ maze[j+d] = maze[j+d*2] = 1;
22
+ }
23
+ return maze;
24
+ }
25
+
26
+ function gameInit()
27
+ {
28
+ // generate maze data
29
+ const mazeSize = vec2(27,15);
30
+ const maze = generateMaze(mazeSize);
31
+
32
+ // create tile layer
33
+ const pos = vec2();
34
+ const tileLayer = new TileCollisionLayer(pos, mazeSize);
35
+ for (pos.x = tileLayer.size.x; pos.x--;)
36
+ for (pos.y = tileLayer.size.y; pos.y--;)
37
+ {
38
+ // check if tile should be solid
39
+ if (maze[pos.x + pos.y*mazeSize.x])
40
+ continue;
41
+
42
+ // set tile data
43
+ tileLayer.setData(pos, new TileLayerData(1));
44
+ }
45
+ tileLayer.redraw(); // redraw tile layer with new data
46
+ cameraPos = mazeSize.scale(.5); // center camera
47
+ }
@@ -0,0 +1,42 @@
1
+ // create example medals
2
+ const medal_openedExample = new Medal(0, 'Opened Example', 'You opened this example!');
3
+ const medal_leftClick = new Medal(1, 'Left Clicked', 'You left clicked!', '🐁');
4
+ const medal_rightClick = new Medal(2, 'Right Clicked', 'You right clicked!', '🐭');
5
+ const medal_spacePressed = new Medal(3, 'Pressed Spacebar', 'You pressed spacebar!', '🚀');
6
+
7
+ // setup medals
8
+ const saveName = 'Medals Example';
9
+ medalsInit(saveName);
10
+
11
+ // clear medals for testing
12
+ medalsForEach(medal=> medal.unlocked = false);
13
+ medal_openedExample.unlock();
14
+
15
+ function gameUpdate()
16
+ {
17
+ if (mouseWasPressed(0))
18
+ medal_leftClick.unlock();
19
+ if (mouseWasPressed(2))
20
+ medal_rightClick.unlock();
21
+ if (keyWasPressed('Space'))
22
+ medal_spacePressed.unlock();
23
+ }
24
+
25
+ function gameRender()
26
+ {
27
+ const size = 80;
28
+ let pos = mainCanvasSize.scale(.5).subtract(vec2(0,40));
29
+ drawTextScreen('Unlocked Medals', pos, size);
30
+
31
+ // show unlocked medals
32
+ let medalsCount = 0;
33
+ medalsForEach(medal=> medal.unlocked && medalsCount++);
34
+ pos = pos.add(vec2((1-medalsCount)*size/2, 100));
35
+ medalsForEach(medal=>
36
+ {
37
+ if (!medal.unlocked)
38
+ return;
39
+ medal.renderIcon(pos, size);
40
+ pos.x += size + 8;
41
+ });
42
+ }
@@ -0,0 +1,21 @@
1
+ function gameRender()
2
+ {
3
+ const nineSliceTile = tile(16);
4
+ const threeSliceTile = tile(19);
5
+
6
+ // draw nine slice with thin border and color
7
+ drawNineSlice(vec2(-7,4), vec2(11+wave(.5,2), 6), nineSliceTile, hsl(.1,.5,.9), .5);
8
+ drawTextOverlay('Nine Slice\nThin Border', vec2(-7,4), 1, BLACK);
9
+
10
+ // draw nine slice in screen space with thick border and rotation
11
+ drawNineSliceScreen(vec2(700,150), vec2(250), nineSliceTile, 32, 2, time/2);
12
+ drawTextScreen('Nine Slice\nScreen Space', vec2(700,150), 30, BLACK);
13
+
14
+ // draw three slice with variable border and additive color
15
+ drawThreeSlice(vec2(-7,-4), vec2(9, 7), threeSliceTile, WHITE, 2+wave(.2)*2, hsl(time/30,.5,.5));
16
+ drawTextOverlay('Three Slice\nVariable\n Border', vec2(-7,-4), 1, BLACK);
17
+
18
+ // draw three slice in screen space with changing size
19
+ drawThreeSliceScreen(vec2(700,420), vec2(350-wave(.3,90),120+wave(.3,60)), threeSliceTile);
20
+ drawTextScreen('Three Slice\nScreen Space', vec2(700,420), 30, BLACK);
21
+ }
@@ -0,0 +1,52 @@
1
+ const pianoSound = new Sound([,0,220,,9]), keys = [];
2
+
3
+ class PianoKey extends EngineObject
4
+ {
5
+ constructor(pos, size, semitone, isWhite)
6
+ {
7
+ const keySize = 2;
8
+ size = size.scale(keySize);
9
+ pos = pos.scale(keySize).add(vec2(0,4-size.y/2));
10
+ super(pos, size, 0, 0, hsl(0,0,isWhite ? 1 : .3));
11
+ this.drawSize = size.subtract(vec2(.1,0));
12
+ this.semitone = semitone;
13
+ }
14
+ press()
15
+ {
16
+ if (!this.isDown)
17
+ pianoSound.playNote(this.semitone);
18
+ this.isDown = true;
19
+ }
20
+ release()
21
+ {
22
+ if (this.isDown)
23
+ pianoSound.stop(.2);
24
+ this.isDown = false;
25
+ }
26
+ render()
27
+ {
28
+ const color = this.isDown ? RED : this.color;
29
+ drawRect(this.pos, this.drawSize, color);
30
+ }
31
+ }
32
+
33
+ function gameInit()
34
+ {
35
+ // create piano keyboard
36
+ for (let i=15; i--;)
37
+ keys.unshift(new PianoKey(vec2(i-7,0), vec2(1,4), [0,2,4,5,7,9,11][i%7]+(i/7|0)*12, 1));
38
+ for (let i=10; i--;)
39
+ keys.unshift(new PianoKey(vec2([1,2,4,5,6][i%5]+(i/5|0)*7-7.5,0), vec2(1,2), [1,3,6,8,10][i%5]+(i/5|0)*12));
40
+ }
41
+
42
+ function gameUpdate()
43
+ {
44
+ // update state of piano keys
45
+ const pressedKey = keys.find(k=>k.isDown);
46
+ const newPressedKey = mouseIsDown(0) && keys.find(k=>isOverlapping(k.pos, k.size, mousePos));
47
+ if (newPressedKey != pressedKey)
48
+ {
49
+ pressedKey && pressedKey.release();
50
+ newPressedKey && newPressedKey.press();
51
+ }
52
+ }
@@ -1,31 +1,23 @@
1
- class PhysicsObject extends EngineObject
2
- {
3
- constructor(pos, size, color)
4
- {
5
- super(pos, size, 0, 0, color);
6
- this.setCollision(); // make object collide
7
- this.mass = 0; // make object have static physics
8
- }
9
- }
10
-
11
- class Player extends PhysicsObject
1
+ class Player extends EngineObject
12
2
  {
13
3
  constructor(pos)
14
4
  {
15
- super(pos, vec2(2,4), RED);
16
- this.mass = 1; // make object have dynamic physics
5
+ super(pos, vec2(2,4), 0, 0, RED);
6
+ this.setCollision(); // make object collide
17
7
  }
18
8
 
19
9
  update()
20
10
  {
11
+ super.update();
12
+
21
13
  // apply movement controls
22
14
  const moveInput = keyDirection();
23
15
  this.velocity.x += moveInput.x * (this.groundObject ? .1: .01);
24
16
  if (this.groundObject && moveInput.y > 0)
25
17
  this.velocity.y = .9; // jump
26
18
 
27
- super.update(); // call parent update function
28
- cameraPos = vec2(this.pos.x, 9); // move camera with player
19
+ // move camera with player
20
+ cameraPos = vec2(this.pos.x, 9);
29
21
  }
30
22
  }
31
23
 
@@ -33,10 +25,22 @@ function gameInit()
33
25
  {
34
26
  // setup level
35
27
  gravity.y = -.05;
36
- new Player(vec2(0,4));
28
+ new Player(vec2(5,6));
37
29
 
38
- // create random objects
39
- new PhysicsObject(vec2(), vec2(1e3,4), GRAY); // ground
40
- for (let i = 1; i < 500; ++i)
41
- new PhysicsObject(vec2(i*10+randInt(4), 0), vec2(2+randInt(20),4+randInt(8)), GREEN);
30
+ // create tile layer
31
+ const pos = vec2();
32
+ const tileLayer = new TileCollisionLayer(pos, vec2(256));
33
+ for (pos.x = tileLayer.size.x; pos.x--;)
34
+ for (pos.y = tileLayer.size.y; pos.y--;)
35
+ {
36
+ // check if tile should be solid
37
+ const levelHeight = pos.x<9 ? 2 : (pos.x/4|0)**3.1%7;
38
+ if (pos.y > levelHeight)
39
+ continue;
40
+
41
+ // set tile data
42
+ tileLayer.setData(pos, new TileLayerData(1));
43
+ tileLayer.setCollisionData(pos);
44
+ }
45
+ tileLayer.redraw(); // redraw tile layer with new data
42
46
  }
@@ -32,7 +32,7 @@ function gameUpdate()
32
32
  ball && ball.destroy(); // destroy old ball
33
33
  ball = new PhysicsObject(cameraPos); // create a ball
34
34
  ball.velocity = vec2(.2); // give ball some movement
35
- ball.elasticity = 1; // make ball bounce
35
+ ball.restitution = 1; // make ball bounce
36
36
  ball.mass = 1; // make ball have dynamic physics
37
37
  }
38
38
 
@@ -0,0 +1,71 @@
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
+ const velocity = keyDirection().scale(.1).rotate(playerAngle);
35
+ const newPos = playerPos.add(velocity);
36
+ if (!levelTest(newPos.x, newPos.y))
37
+ playerPos = newPos;
38
+ }
39
+
40
+ function gameRender()
41
+ {
42
+ {
43
+ // draw horizontal slizes to create floor and ceiling
44
+ const h = 9;
45
+ let pos = vec2(), size = vec2(39, .15), color = WHITE;
46
+ for (let y=-h; y<h; y+=.1)
47
+ {
48
+ const p = 1.01-abs(y/h)
49
+ pos.y = y;
50
+ color.setHSLA(.1, y>0?0:.5, .7-p*.7);
51
+ drawRect(pos, size, color);
52
+ }
53
+ }
54
+ {
55
+ // draw vertical slices to create the walls
56
+ const w = 20;
57
+ const pos = vec2(), size = vec2(.15), color = WHITE;
58
+ for (let x=-w; x<w; x+=.1)
59
+ {
60
+ const p = raycast(playerPos, playerAngle + x/w);
61
+ pos.x = x;
62
+ size.y = .4/p;
63
+ color.setHSLA(.6, .5, .7-p*.7);
64
+ drawRect(pos, size, color);
65
+ }
66
+ }
67
+ // draw instructions and pointer lock status
68
+ const instructions = pointerLockIsActive() ? 'Mouse Control Active - ESC To Exit' : 'Click To Enable Mouse Control';
69
+ if (!isTouchDevice)
70
+ drawTextScreen(instructions, vec2(mainCanvasSize.x/2, 50), 24, pointerLockIsActive() ? GREEN : WHITE);
71
+ }
@@ -1,24 +1,24 @@
1
1
  function gameRender()
2
2
  {
3
3
  // polygon shapes
4
- for(let j=3; j<7; ++j)
4
+ for (let j=3; j<7; ++j)
5
5
  {
6
6
  let points = [];
7
- for(let i=0; i<j; ++i)
7
+ for (let i=0; i<j; ++i)
8
8
  {
9
9
  let angle = i * Math.PI * 2 / j;
10
- points.push(vec2(j*4-18,0).add(vec2(Math.sin(angle), Math.cos(angle))));
10
+ points.push(vec2(j*4-18,0).add(vec2(0,1).rotate(angle)));
11
11
  }
12
- drawPoly(points, hsl(j/4,1,.5)); // draw a star
12
+ drawPoly(points, hsl(j/4+time/9,1,.5)); // draw a regular polygon
13
13
  }
14
14
 
15
15
  // circles and ellipses
16
- drawCircle(vec2(0,5), 1, hsl(.15,1,.5));
17
- drawEllipse(vec2(-5,5), 2, 1, 0, hsl(0,1,.5));
18
- drawEllipse(vec2(5,5), .5, 2, .5, hsl(.55,1,.5));
16
+ drawCircle(vec2(0,5), 1+wave(.5), hsl(.15,1,.5));
17
+ drawEllipse(vec2(-5,5), vec2(2,1), hsl(0,1,.5));
18
+ drawEllipse(vec2(5,5), vec2(.5,2), hsl(.55,1,.5), .5);
19
19
 
20
20
  // rects and lines
21
- drawRect(vec2(0,-5), vec2(13,2), hsl(.6,1,.5));
22
- drawLine(vec2(-5,-7), vec2(5,-3), 1, hsl(0,0,1));
21
+ drawRect(vec2(0,-5), vec2(4,3), hsl(.6,1,.5), time);
22
+ drawLine(vec2(-5,-7), vec2(5,-3), 1, hsl(0,0,1, .5));
23
23
  drawLine(vec2(-5,-3), vec2(5,-7), .2, hsl(1,1,.5));
24
24
  }
@@ -0,0 +1,42 @@
1
+ const gridSize = vec2(4,3);
2
+ const pieceSize = vec2(5,4);
3
+ let emptyGridPos = vec2();
4
+
5
+ class PuzzlePiece extends EngineObject
6
+ {
7
+ constructor(gridPos, size)
8
+ {
9
+ const color = rgb(gridPos.x/(gridSize.x-1), gridPos.y/(gridSize.y-1), 1);
10
+ super(gridPos.multiply(size), size, 0, 0, color);
11
+ this.gridPos = gridPos;
12
+ this.text = gridPos.x + gridPos.y*gridSize.x;
13
+ }
14
+
15
+ update()
16
+ {
17
+ if (mouseWasPressed(0) && isOverlapping(this.pos, this.size, mousePos))
18
+ if (abs(this.gridPos.x-emptyGridPos.x) + abs(this.gridPos.y-emptyGridPos.y) == 1)
19
+ {
20
+ // swap with empty space when clicked on
21
+ this.pos = emptyGridPos.multiply(this.size);
22
+ [emptyGridPos, this.gridPos] = [this.gridPos, emptyGridPos];
23
+ }
24
+ }
25
+
26
+ render()
27
+ {
28
+ super.render();
29
+ drawTextOverlay(this.text, this.pos, 2.5, BLACK);
30
+ }
31
+ }
32
+
33
+ function gameInit()
34
+ {
35
+ // create puzzle pieces
36
+ for (let x=gridSize.x; x--;)
37
+ for (let y=gridSize.y; y--;)
38
+ (x||y) && new PuzzlePiece(vec2(x,y), pieceSize);
39
+
40
+ // center camera on grid
41
+ cameraPos = gridSize.subtract(vec2(1)).multiply(pieceSize).scale(.5);
42
+ }