littlejsengine 1.14.23 → 1.15.2

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 (52) hide show
  1. package/dist/littlejs.d.ts +184 -30
  2. package/dist/littlejs.esm.js +589 -147
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +583 -147
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +546 -147
  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/index.html +2 -2
  11. package/examples/index.html +11 -7
  12. package/examples/platformer/gameCharacter.js +3 -2
  13. package/examples/platformer/gameObjects.js +3 -8
  14. package/examples/shorts/base.html +2 -2
  15. package/examples/shorts/box2d.js +2 -2
  16. package/examples/shorts/box2dCar.js +18 -7
  17. package/examples/shorts/box2dPool.js +108 -0
  18. package/examples/shorts/debugDraw.js +2 -3
  19. package/examples/shorts/flappyGame.js +1 -0
  20. package/examples/shorts/fps.js +1 -1
  21. package/examples/shorts/hillGlideGame.js +0 -2
  22. package/examples/shorts/input.js +59 -0
  23. package/examples/shorts/landerGame.js +1 -3
  24. package/examples/shorts/medals.js +15 -9
  25. package/examples/shorts/music.js +15 -17
  26. package/examples/shorts/musicPlayer.js +24 -24
  27. package/examples/shorts/platformer.js +0 -2
  28. package/examples/shorts/slidingPuzzle.js +1 -1
  29. package/examples/shorts/song.mp3 +0 -0
  30. package/examples/shorts/spaceGame.js +0 -2
  31. package/examples/shorts/spriteAtlas.js +0 -2
  32. package/examples/shorts/tiltedView.js +0 -3
  33. package/examples/shorts/timers.js +1 -2
  34. package/examples/shorts/topDown.js +0 -2
  35. package/examples/shorts/video.webm +0 -0
  36. package/examples/shorts/videoPlayer.js +33 -0
  37. package/examples/starter/index.html +3 -3
  38. package/package.json +1 -1
  39. package/plugins/box2d.js +170 -50
  40. package/plugins/pluginExport.js +3 -0
  41. package/plugins/uiSystem.js +229 -27
  42. package/src/engine.js +21 -18
  43. package/src/engineAudio.js +14 -2
  44. package/src/engineDebug.js +37 -0
  45. package/src/engineDraw.js +21 -13
  46. package/src/engineExport.js +3 -0
  47. package/src/engineInput.js +24 -12
  48. package/src/engineMedals.js +2 -2
  49. package/src/engineObject.js +24 -4
  50. package/src/engineParticles.js +4 -6
  51. package/src/engineTileLayer.js +2 -0
  52. package/src/engineUtilities.js +35 -13
@@ -38,7 +38,7 @@ export function spawnCircle(pos, diameter=1, color=LJS.WHITE, type=LJS.box2d.bod
38
38
  export function spawnRandomPoly(pos, diameter=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, angle=0)
39
39
  {
40
40
  const o = new LJS.Box2dObject(pos, vec2(), 0, angle, color, type);
41
- o.addRandomPoly(diameter, vec2(), 0, density, friction, restitution);
41
+ o.addRandomPoly(diameter, density, friction, restitution);
42
42
  return o;
43
43
  }
44
44
 
@@ -77,7 +77,7 @@ export function spawnRandomEdges()
77
77
  for (let i=40, y=0; i--;)
78
78
  edgePoints.push(vec2(i, y=LJS.clamp(y+LJS.rand(-2,2),0,5)));
79
79
  edgePoints.push(vec2(0,0));
80
- const o = new LJS.Box2dObject(vec2(), vec2(), 0, 0, LJS.BLACK, LJS.box2d.bodyTypeStatic);
80
+ const o = new LJS.Box2dStaticObject;
81
81
  o.addEdgeList(edgePoints);
82
82
  }
83
83
 
@@ -147,8 +147,6 @@ export class CarObject extends LJS.Box2dObject
147
147
  }
148
148
  update()
149
149
  {
150
- super.update();
151
-
152
150
  // car controls
153
151
  const maxSpeed = 40;
154
152
  const input = LJS.keyDirection().x;
@@ -166,11 +164,11 @@ export class CarObject extends LJS.Box2dObject
166
164
  ///////////////////////////////////////////////////////////////////////////////
167
165
 
168
166
  // changes objects color when touched
169
- export class ContactTester extends LJS.Box2dObject
167
+ export class ContactTester extends LJS.Box2dStaticObject
170
168
  {
171
169
  constructor(pos, size, color, contactColor, isCircle=true, isSensor=true)
172
170
  {
173
- super(pos, size, 0, 0, color, LJS.box2d.bodyTypeStatic);
171
+ super(pos, size, 0, 0, color);
174
172
  isCircle ? this.addCircle(size.x) : this.addBox(size);
175
173
  this.setSensor(isSensor);
176
174
  this.contactColor = contactColor;
@@ -325,11 +323,11 @@ export class SoftBodyObject extends LJS.Box2dObject
325
323
  ///////////////////////////////////////////////////////////////////////////////
326
324
 
327
325
  // cloth sim using grid of rope joints
328
- export class ClothObject extends LJS.Box2dObject
326
+ export class ClothObject extends LJS.Box2dStaticObject
329
327
  {
330
328
  constructor(pos, scale, sizeCount, color, maxJointStress=10)
331
329
  {
332
- super(pos, vec2(), 0, 0, color, LJS.box2d.bodyTypeStatic);
330
+ super(pos, vec2(), 0, 0, color);
333
331
  const nodeSize = sizeCount.subtract(vec2(1));
334
332
  const spacing = scale.divide(nodeSize);
335
333
  const objectDiameter = LJS.min(spacing.x, spacing.y);
@@ -393,8 +391,6 @@ export class ClothObject extends LJS.Box2dObject
393
391
  }
394
392
  update()
395
393
  {
396
- super.update();
397
-
398
394
  for (let y=this.sizeCount.y; y--;)
399
395
  for (let x=this.sizeCount.x; x--;)
400
396
  {
@@ -137,14 +137,14 @@ export function loadScene(_scene)
137
137
  }
138
138
  {
139
139
  // distance joint
140
- const o1 = new LJS.Box2dObject(vec2(30,11), vec2(4), Game.spriteAtlas.circleOutline, 0, LJS.randColor(), LJS.box2d.bodyTypeStatic);
140
+ const o1 = new LJS.Box2dStaticObject(vec2(30,11), vec2(4), Game.spriteAtlas.circleOutline, 0, LJS.randColor());
141
141
  o1.renderOrder = -2;
142
142
  const o2 = GameObjects.spawnCircle(vec2(30,8), 2, LJS.randColor());
143
143
  new LJS.Box2dDistanceJoint(o1, o2);
144
144
  }
145
145
  {
146
146
  // motor joint
147
- const o = new LJS.Box2dObject(vec2(10,8), vec2(4), Game.spriteAtlas.circleOutline, 0, LJS.randColor(), LJS.box2d.bodyTypeStatic);
147
+ const o = new LJS.Box2dStaticObject(vec2(10,8), vec2(4), Game.spriteAtlas.circleOutline, 0, LJS.randColor());
148
148
  o.renderOrder = -2;
149
149
  new GameObjects.MotorJointObject(vec2(10,8), vec2(2), LJS.randColor(), o);
150
150
  }
@@ -137,7 +137,7 @@ export class Ball extends PhysicsObject
137
137
  this.velocity.y = LJS.max(-this.velocity.y, .2);
138
138
 
139
139
  // speed up
140
- const speed = LJS.min(1.04*this.velocity.length(), .5);
140
+ const speed = LJS.min(1.04*this.getSpeed(), .5);
141
141
  this.velocity = this.velocity.normalize(speed);
142
142
  sound_bounce.play(this.pos, 1, speed*2);
143
143
 
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?1.14.24></script>
10
+ <script src=../../dist/littlejs.js?1.15.2></script>
11
11
 
12
12
  <!-- Add your game scripts here -->
13
- <script src=game.js?1.14.24></script>
13
+ <script src=game.js?1.15.2></script>
@@ -84,32 +84,35 @@ class ExampleInfo
84
84
 
85
85
  const exampleList =
86
86
  [
87
- new ExampleInfo('--- SHORT EXAMPLES ---'),
87
+ new ExampleInfo('--- BASIC ---'),
88
88
  new ExampleInfo('Hello World', 'helloWorld.js', 'Simple starter example', false, 'beginner, gradient, text, tiles'),
89
89
  new ExampleInfo('Empty', 'empty.js', 'Empty example template', false, 'beginner, text'),
90
90
  new ExampleInfo('Texture', 'texture.js', 'Texture display and manipulation', false, 'sprites, loading, tiles'),
91
91
  new ExampleInfo('Animation', 'animation.js', 'Sprite animation system', false, 'frames, loop, tiles, sprites'),
92
92
  new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives', false, 'circle, ellipse, rectangle, polygon, lines'),
93
93
  new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL', false, 'hue, saturation, blending, rectangle'),
94
- new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth, rectangle'),
95
94
  new ExampleInfo('Sprite Atlas', 'spriteAtlas.js', 'Sprite atlas and tile rendering', false, 'sheet, frames, tiles'),
96
95
  new ExampleInfo('Blending', 'blending.js', 'Additive blending and transparency', false, 'alpha, color, tiles, smooth'),
97
96
  new ExampleInfo('Tile Layer', 'tileLayer.js', 'Tile layer rendering system', false, 'level, map, grid, particles'),
98
97
  new ExampleInfo('Particles', 'particles.js', 'Particle system', false, 'effects, emitter, physics, fire, smoke'),
98
+ new ExampleInfo('Input', 'input.js', 'Input system demo for keyboard, mouse, touch, and gamepad.', false, 'input, control'),
99
99
  new ExampleInfo('Timers', 'timers.js', 'Timer objects and UI', false, 'delay, interval, slider'),
100
100
  new ExampleInfo('Sound Effects', 'sound.js', 'ZzFX sound effect generator', false, 'audio, volume, ui'),
101
- new ExampleInfo('Music', 'music.js', 'Basic music load, play, pause, and stop', false, 'music, sound, audio, streaming, volume, ui'),
101
+ new ExampleInfo('Music', 'music.js', 'Basic load, play, pause, and stop', false, 'music, sound, audio, streaming, volume, ui'),
102
+ new ExampleInfo('Video', 'videoPlayer.js', 'Basic video play, pause, and stop', false, 'movie, sound, audio, streaming, volume, ui'),
102
103
  new ExampleInfo('Font Image', 'systemFont.js', 'Bitmap font system with built-in system font', false, 'text, characters'),
103
- new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains', false, 'generative, canvas, background'),
104
- new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation', false, 'generative, level, tiles, map, grid'),
105
104
  new ExampleInfo('Medals', 'medals.js', 'Achievement system', false, 'unlock, progress, newgrounds'),
106
105
  new ExampleInfo('Tile Raycast', 'tileRaycast.js', 'Example of the tile layer raycast collision', false, 'level, map, grid'),
107
- new ExampleInfo('Debug Drawing', 'debugDraw.js', 'Debug drawing system', false, 'debug, circle, line, rectangle'),
108
106
  new ExampleInfo('Camera Mouse Drag', 'cameraDrag.js', 'Example of how to control camera with mose', false, 'ui, input, control'),
107
+ new ExampleInfo('Debug Drawing', 'debugDraw.js', 'Debug drawing system', false, 'debug, circle, line, rectangle'),
108
+ new ExampleInfo('--- ADVANCED ---'),
109
109
  new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangle'),
110
+ new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth, rectangle'),
111
+ new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains', false, 'generative, canvas, background'),
112
+ new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation', false, 'generative, level, tiles, map, grid'),
110
113
  new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, sound, audio, notes, ui, instrument'),
111
114
  new ExampleInfo('Step Sequencer', 'sequencer.js', 'Simple music loop creation tool', false, 'music, sound, audio, notes, ui, instrument'),
112
- new ExampleInfo('Music Player', 'musicPlayer.js', 'Advanced music player with audio seeking and drag and drop', false, 'music, sound, audio, streaming, volume, ui'),
115
+ new ExampleInfo('Music Player', 'musicPlayer.js', 'Music player with audio seeking and drag and drop', false, 'sound, loading, audio, ui'),
113
116
  new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
114
117
  new ExampleInfo('--- MINI GAMES ---'),
115
118
  new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
@@ -125,6 +128,7 @@ const exampleList =
125
128
  new ExampleInfo('--- PLUGINS ---'),
126
129
  new ExampleInfo('Box2d Demo', 'box2d.js', 'Box2D physics plugin', false, 'objects, mouse'),
127
130
  new ExampleInfo('Box2d Car', 'box2dCar.js', 'Drivable car with Box2D physics', false, 'objects, vehicle, suspension, wheels'),
131
+ new ExampleInfo('Box2d Pool', 'box2dPool.js', 'Billiard table pool game with physics', false, 'objects, game'),
128
132
  new ExampleInfo('Post Processing', 'postProcess.js', 'Shader effects and filters', false, 'webgl, visual, effect'),
129
133
  new ExampleInfo('UI System Plugin', 'uiSystem.js', 'Buttons, sliders, and checkboxes', false, 'objects, widgets, interactive'),
130
134
  new ExampleInfo('Nine Slice', 'nineSlice.js', 'Scalable UI panels', false, 'three slice, stretch, corners, text, tiles'),
@@ -34,6 +34,7 @@ export class Character extends GameObjects.GameObject
34
34
  this.deadTimer = new Timer;
35
35
  this.grenadeThrowTimer = new Timer;
36
36
  this.drawSize = vec2(1);
37
+ this.moveInput = vec2();
37
38
  this.color = hsl(LJS.rand(),1,.7);
38
39
  this.renderOrder = 10;
39
40
  this.walkCyclePercent = 0;
@@ -195,11 +196,11 @@ export class Character extends GameObjects.GameObject
195
196
  // track last pos for ladder collision code
196
197
  this.lastPos = this.pos.copy();
197
198
 
198
- // call parent and update physics
199
+ // call parent
199
200
  super.update();
200
201
 
201
202
  // update walk cycle
202
- const speed = this.velocity.length();
203
+ const speed = this.getSpeed();
203
204
  if (this.climbingLadder || this.groundTimer.active() && !this.dodgeTimer.active())
204
205
  {
205
206
  this.walkCyclePercent += speed * .5;
@@ -26,8 +26,6 @@ export class GameObject extends LJS.EngineObject
26
26
 
27
27
  update()
28
28
  {
29
- super.update();
30
-
31
29
  // flash white when damaged
32
30
  let brightness = 0;
33
31
  if (!this.isDead() && this.damageTimer.isSet())
@@ -97,6 +95,7 @@ export class Coin extends LJS.EngineObject
97
95
  {
98
96
  super(pos, vec2(1), Game.spriteAtlas.coin);
99
97
  this.color = hsl(.15,1,.5);
98
+ this.mass = 0;
100
99
  }
101
100
 
102
101
  render()
@@ -155,7 +154,7 @@ export class Enemy extends GameObject
155
154
  this.velocity = vec2(LJS.rand(.1,-.1), LJS.rand(.4,.2));
156
155
 
157
156
  // damage player if touching
158
- if (LJS.isOverlapping(this.pos, this.size, Game.player.pos, Game.player.size))
157
+ if (this.isOverlappingObject(Game.player))
159
158
  Game.player.damage(1, this);
160
159
  }
161
160
 
@@ -261,8 +260,6 @@ export class Weapon extends LJS.EngineObject
261
260
 
262
261
  update()
263
262
  {
264
- super.update();
265
-
266
263
  // update recoil
267
264
  if (this.recoilTimer.active())
268
265
  this.localAngle = LJS.lerp(this.localAngle, 0, this.recoilTimer.getPercent());
@@ -318,11 +315,9 @@ export class Bullet extends LJS.EngineObject
318
315
  if (o.isGameObject)
319
316
  this.collideWithObject(o)
320
317
  });
321
-
322
- super.update();
323
318
 
324
319
  this.angle = this.velocity.angle();
325
- this.range -= this.velocity.length();
320
+ this.range -= this.getSpeed();
326
321
  if (this.range < 0)
327
322
  {
328
323
  new LJS.ParticleEmitter(
@@ -1,8 +1,9 @@
1
1
  <!DOCTYPE html><meta charset=utf-8><body>
2
- <script src=../../dist/littlejs.js?1.14.24></script>
2
+ <script src=../../dist/littlejs.js?1.15.2></script>
3
3
  <script src=../../dist/box2d.wasm.js></script>
4
4
 
5
5
  <!-- LittleJS Engine Source
6
+ <script src=../../src/engine.js></script>
6
7
  <script src=../../src/engineDebug.js></script>
7
8
  <script src=../../src/engineUtilities.js></script>
8
9
  <script src=../../src/engineSettings.js></script>
@@ -14,7 +15,6 @@
14
15
  <script src=../../src/engineParticles.js></script>
15
16
  <script src=../../src/engineMedals.js></script>
16
17
  <script src=../../src/engineWebGL.js></script>
17
- <script src=../../src/engine.js></script>
18
18
  <script src=../../plugins/box2d.js></script>
19
19
  <script src=../../plugins/box2d.wasm.js></script>
20
20
  <script src=../../plugins/drawUtilities.js></script>
@@ -7,8 +7,8 @@ async function gameInit()
7
7
  canvasClearColor = hsl(0,0,.9);
8
8
 
9
9
  // create ground object
10
- groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
11
- GRAY, box2d.bodyTypeStatic);
10
+ groundObject = new Box2dStaticObject(vec2(-8));
11
+ groundObject.color = GRAY;
12
12
  groundObject.addBox(vec2(100,2));
13
13
 
14
14
  // add some random objects
@@ -3,9 +3,19 @@ async function gameInit()
3
3
  // setup box2d and create the objects
4
4
  await box2dInit();
5
5
  gravity.y = -20;
6
- groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
7
- GRAY, box2d.bodyTypeStatic);
8
- groundObject.addBox(vec2(100,6));
6
+
7
+ // create edge list for ground
8
+ const edgePoints = [];
9
+ for (let i=0, y=0, s=0; i<1e3; ++i)
10
+ {
11
+ y = clamp(y+rand(-1,1),0,5);
12
+ edgePoints.push(vec2(i*5-15, y-8));
13
+ }
14
+ const ground = new Box2dStaticObject;
15
+ ground.lineWidth = 1;
16
+ ground.addEdgeList(edgePoints);
17
+
18
+ // make a car
9
19
  new CarObject(vec2(0,-2));
10
20
  canvasClearColor = hsl(0,0,.9);
11
21
  }
@@ -14,9 +24,10 @@ class CarObject extends Box2dObject
14
24
  {
15
25
  constructor(pos)
16
26
  {
17
- super(pos, vec2(), 0, 0, RED);
27
+ super(pos);
18
28
 
19
29
  // create car with wheels
30
+ this.color = RED;
20
31
  this.addBox(vec2(7,2));
21
32
  const frequency = 4, maxTorque = 250;
22
33
  this.wheels = [];
@@ -28,15 +39,14 @@ class CarObject extends Box2dObject
28
39
  joint.setSpringFrequencyHz(frequency);
29
40
  joint.setMaxMotorTorque(maxTorque);
30
41
  joint.enableMotor(!i);
31
- wheel.addCircle(2, vec2(), 1, 1);
42
+ const friction = 1;
43
+ wheel.addCircle(2, vec2(), 1, friction);
32
44
  wheel.motorJoint = joint;
33
45
  this.wheels[i] = wheel;
34
46
  }
35
47
  }
36
48
  update()
37
49
  {
38
- super.update();
39
-
40
50
  // car controls - use mouse, arrow keys, or A/D to drive
41
51
  const maxSpeed = 40;
42
52
  const input = mouseIsDown(0) ? 1 :
@@ -44,5 +54,6 @@ class CarObject extends Box2dObject
44
54
  let s = this.wheels[0].motorJoint.getMotorSpeed();
45
55
  s = input ? clamp(s - input, -maxSpeed, maxSpeed) : 0;
46
56
  this.wheels[0].motorJoint.setMotorSpeed(s);
57
+ cameraPos.x = this.pos.x;
47
58
  }
48
59
  }
@@ -0,0 +1,108 @@
1
+ const hitSound = new Sound([,,2e3,,,.01]);
2
+ const maxHitDistance = 6;
3
+
4
+ class Ball extends Box2dObject
5
+ {
6
+ constructor(position, number=0)
7
+ {
8
+ const color = hsl(number/9, 1, number? .5 : 1);
9
+ super(position, vec2(), 0, 0, color);
10
+ this.number = number;
11
+
12
+ // setup pool ball physics
13
+ const friction = 0, restitution = .95;
14
+ this.addCircle(1, vec2(), 1, friction, restitution);
15
+ this.setLinearDamping(.4);
16
+ this.setBullet(true);
17
+ this.setFixedRotation(true);
18
+ }
19
+ beginContact()
20
+ {
21
+ const volume = clamp(this.getSpeed()/20);
22
+ hitSound.play(this.pos, clamp(this.getSpeed()/20));
23
+ }
24
+ canHit() { return this == cueBall && this.getSpeed() < 1; }
25
+ getHitOffset()
26
+ {
27
+ // hit from cue ball to mouse position
28
+ const deltaPos = mousePos.subtract(this.pos);
29
+ const length = min(deltaPos.length(), maxHitDistance);
30
+ return deltaPos.normalize(length);
31
+ }
32
+ update()
33
+ {
34
+ if (this.canHit() && mouseWasPressed(0))
35
+ {
36
+ // hit the cue ball
37
+ const accel = this.getHitOffset().scale(8);
38
+ this.applyAcceleration(accel);
39
+ hitSound.play(cueBall.pos);
40
+ }
41
+ if (this.pocketed)
42
+ this.destroy();
43
+ }
44
+ render()
45
+ {
46
+ super.render();
47
+
48
+ // draw white circle and ball number
49
+ drawCircle(this.pos, .6, WHITE);
50
+ const textPos = this.pos.add(vec2(0,-.06));
51
+ if (this.number)
52
+ drawTextOverlay(this.number, textPos, .5, BLACK);
53
+ if (this.canHit())
54
+ {
55
+ // draw the aim line
56
+ const offset = this.getHitOffset();
57
+ const endPos = this.pos.add(offset);
58
+ const width = offset.length()/maxHitDistance;
59
+ drawLine(this.pos, endPos, width, hsl(0,1,.5,.5),
60
+ vec2(), 0, false, false, overlayContext);
61
+ }
62
+ }
63
+ }
64
+
65
+ class Pocket extends Box2dStaticObject
66
+ {
67
+ constructor(pos, size)
68
+ {
69
+ super(pos, size, 0, 0, BLACK);
70
+
71
+ // create a sensor circle for pocket
72
+ this.addCircle(size.x);
73
+ this.setSensor(true);
74
+ }
75
+ render()
76
+ {
77
+ // add ball size to pocket size for drawing
78
+ drawCircle(this.pos, this.size.x + 1, BLACK);
79
+ }
80
+ beginContact(other) { other.pocketed = 1; }
81
+ }
82
+
83
+ async function gameInit()
84
+ {
85
+ // setup box2d
86
+ await box2dInit();
87
+ canvasClearColor = hsl(.4,.5,.5);
88
+
89
+ // create table walls
90
+ const groundObject = new Box2dStaticObject;
91
+ groundObject.color = hsl(.1,1,.2);
92
+ groundObject.addBox(vec2(100,3), vec2( 0, 8.5));
93
+ groundObject.addBox(vec2(100,3), vec2( 0,-8.5));
94
+ groundObject.addBox(vec2(3,100), vec2( 15,0));
95
+ groundObject.addBox(vec2(3,100), vec2(-15,0));
96
+
97
+ // create pockets
98
+ for (let j=0; j<2; ++j)
99
+ for (let i=0; i<3; ++i)
100
+ new Pocket(vec2(i-1, j-.5).scale(13), vec2(.5));
101
+
102
+ // create balls
103
+ let number = 1;
104
+ for (let i=5; i--;)
105
+ for (let j=i+1; j--;)
106
+ new Ball(vec2(6+i*.9, j-i/2), number++);
107
+ cueBall = new Ball(vec2(-6, 0));
108
+ }
@@ -8,12 +8,11 @@ class BounceObject extends EngineObject
8
8
 
9
9
  update()
10
10
  {
11
- super.update();
12
-
13
11
  // show debug info
14
12
  debugText('Debug Text', this.pos.add(vec2(0,3)), 1, WHITE);
15
13
  debugRect(this.pos, this.size, RED);
16
- debugPoly(mousePos, [vec2(-2,-1), vec2(0,2), vec2(2,-1)], YELLOW);
14
+ const trianglePoints = [vec2(-2,-1), vec2(0,2), vec2(2,-1)];
15
+ debugPoly(mousePos, trianglePoints, YELLOW);
17
16
  debugLine(this.pos, mousePos, BLUE);
18
17
 
19
18
  // bounce off screen edges
@@ -4,6 +4,7 @@ class Wall extends EngineObject
4
4
  {
5
5
  super(pos, size, 0, 0, hsl(.3,.5,.3));
6
6
  this.setCollision(); // make object collide
7
+ this.mass = 0;
7
8
  }
8
9
  update()
9
10
  {
@@ -12,7 +12,7 @@ function gameUpdate()
12
12
  if (keyWasPressed('Escape'))
13
13
  pointerLockExit()
14
14
  if (pointerLockIsActive() || isTouchDevice)
15
- playerAngle += mouseDelta.x * .003;
15
+ playerAngle += mouseDelta.x * .03;
16
16
 
17
17
  // update player movement, prevent walking through walls
18
18
  const velocity = keyDirection().rotate(playerAngle).scale(.05);
@@ -9,8 +9,6 @@ class Player extends EngineObject
9
9
 
10
10
  update()
11
11
  {
12
- super.update();
13
-
14
12
  // check ground height
15
13
  const h = getGroundHeight(this.pos.x);
16
14
  if (this.pos.y < h + this.size.y/2)
@@ -0,0 +1,59 @@
1
+ function gameUpdate()
2
+ {
3
+ if (isUsingGamepad)
4
+ {
5
+ debugText('Gamepad Mode', vec2(0,4));
6
+
7
+ // analog sticks
8
+ for (let i=2; i--;)
9
+ {
10
+ const stick = gamepadStick(i);
11
+ const pos = vec2(i?2:-2, 1);
12
+ debugCircle(pos, 2, WHITE);
13
+ debugLine(pos, pos.add(stick), GREEN);
14
+ }
15
+
16
+ // buttons
17
+ for (let i=16; i--;)
18
+ {
19
+ const pos = vec2(-1.5 + i%4, -2 - (i/4|0));
20
+ if (gamepadIsDown(i))
21
+ debugCircle(pos, 1, RED, 0, 1);
22
+ debugCircle(pos, 1, WHITE);
23
+ }
24
+ }
25
+ else if (isTouchDevice)
26
+ {
27
+ debugText('Touch Mode', vec2(0,4));
28
+
29
+ // touch input routed to mouse
30
+ if (mouseIsDown(0))
31
+ debugCircle(mousePos, 4, RED, 0, 1);
32
+ debugCircle(mousePos, 4, WHITE);
33
+ }
34
+ else
35
+ {
36
+ debugText('Mouse and Keyboard Mode', vec2(0,4));
37
+
38
+ // keyboard key (space bar)
39
+ debugRect(vec2(), vec2(2), WHITE);
40
+ if (keyIsDown('Space'))
41
+ debugRect(vec2(), vec2(2), RED, 0, 0, 1);
42
+
43
+ // keyboard direction (arrow keys or WASD)
44
+ const inputDirection = keyDirection();
45
+ debugLine(vec2(), inputDirection, GREEN);
46
+
47
+ // mouse pos
48
+ debugPoint(mousePos, mouseIsDown(0) ? RED : YELLOW);
49
+
50
+ // mouse buttons
51
+ for (let i=3; i--;)
52
+ {
53
+ const pos = vec2(-1 + i, -3);
54
+ if (mouseIsDown(i))
55
+ debugCircle(pos, 1, RED, 0, 1);
56
+ debugCircle(pos, 1, WHITE);
57
+ }
58
+ }
59
+ }
@@ -9,12 +9,10 @@ class Player extends EngineObject
9
9
 
10
10
  update()
11
11
  {
12
- super.update();
13
-
14
12
  // space ship controls
15
13
  const moveInput = keyDirection();
16
14
  this.applyAngularAcceleration(moveInput.x * .002);
17
- const accel = this.getRight(moveInput.y*.002);
15
+ const accel = this.getUp(moveInput.y*.002);
18
16
  this.applyAcceleration(accel);
19
17
  }
20
18
 
@@ -4,19 +4,25 @@ const medal_leftClick = new Medal(1, 'Lefty', 'Left clicked!', '🐁');
4
4
  const medal_rightClick = new Medal(2, 'Righty', 'Right clicked!', '🐭');
5
5
  const medal_spacePressed = new Medal(3, 'Space', 'Pressed spacebar!', '🚀');
6
6
 
7
- // setup medals
8
- const saveName = 'Medals Example';
9
- medalsInit(saveName);
7
+ function gameInit()
8
+ {
9
+ // setup medals
10
+ const saveName = 'Medals Example';
11
+ medalsInit(saveName);
12
+
13
+ // clear unlocked medals for testing
14
+ medalsForEach(medal=> medal.unlocked = false);
10
15
 
11
- // clear medals for testing
12
- medalsForEach(medal=> medal.unlocked = false);
13
- medal_openedExample.unlock();
16
+ // unlock the example medal
17
+ medal_openedExample.unlock();
14
18
 
15
- // set background color
16
- canvasClearColor = hsl(.5,.3,.2);
19
+ // set background color
20
+ canvasClearColor = hsl(.5,.3,.2);
21
+ }
17
22
 
18
23
  function gameUpdate()
19
24
  {
25
+ // unlock example medals based on input
20
26
  if (mouseWasPressed(0))
21
27
  medal_leftClick.unlock();
22
28
  if (mouseWasPressed(2))
@@ -25,7 +31,7 @@ function gameUpdate()
25
31
  medal_spacePressed.unlock();
26
32
  }
27
33
 
28
- function gameRender()
34
+ function gameRenderPost()
29
35
  {
30
36
  const size = 80;
31
37
  let pos = mainCanvasSize.scale(.5).subtract(vec2(0,40));
@@ -1,7 +1,5 @@
1
- let musicPlayer, playButton, stopButton, infoText;
2
- let musicSound = new SoundWave('song.mp3');
3
- let musicVolume = 1;
4
- let music;
1
+ const musicSound = new SoundWave('song.mp3');
2
+ let musicVolume = 1, musicInstance;
5
3
 
6
4
  function gameInit()
7
5
  {
@@ -13,7 +11,8 @@ function gameInit()
13
11
  canvasClearColor = hsl(.9,.3,.2);
14
12
 
15
13
  // setup music player UI
16
- musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 220));
14
+ const center = mainCanvasSize.scale(.5);
15
+ musicPlayer = new UIObject(center, vec2(500, 220));
17
16
 
18
17
  // infomation text
19
18
  infoText = new UIText(vec2(0, -70), vec2(400, 50));
@@ -26,8 +25,7 @@ function gameInit()
26
25
  volumeSlider.onChange = () =>
27
26
  {
28
27
  musicVolume = volumeSlider.value;
29
- if (music)
30
- music.setVolume(musicVolume);
28
+ musicInstance?.setVolume(musicVolume);
31
29
  };
32
30
 
33
31
  // play button
@@ -39,17 +37,17 @@ function gameInit()
39
37
  return;
40
38
 
41
39
  // handle play/pause toggle
42
- if (!music)
43
- music = musicSound.playMusic(musicVolume);
44
- else if (music.isPaused())
45
- music.resume();
40
+ if (!musicInstance)
41
+ musicInstance = musicSound.playMusic(musicVolume);
42
+ else if (musicInstance.isPaused())
43
+ musicInstance.resume();
46
44
  else
47
- music.pause();
45
+ musicInstance.pause();
48
46
  };
49
47
 
50
48
  // stop button
51
49
  stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
52
- stopButton.onClick = ()=> music && music.stop();
50
+ stopButton.onClick = ()=> musicInstance?.stop();
53
51
  musicPlayer.addChild(stopButton);
54
52
  }
55
53
 
@@ -69,10 +67,10 @@ function gameUpdate()
69
67
  else
70
68
  {
71
69
  // update ui text
72
- const isPlaying = music && music.isPlaying();
70
+ const isPlaying = musicInstance?.isPlaying();
73
71
  playButton.text = isPlaying ? 'Pause' : 'Play';
74
- const current = music ? music.getCurrentTime() : 0;
75
- const duration = musicSound.getDuration();
76
- infoText.text = formatTime(current) +' / '+ formatTime(duration);
72
+ const current = formatTime(musicInstance?.getCurrentTime());
73
+ const duration = formatTime(musicSound.getDuration());
74
+ infoText.text = current + ' / ' + duration;
77
75
  }
78
76
  }