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
@@ -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
 
@@ -16,13 +16,6 @@ setTileFixBleedScale(.5);
16
16
  // sound effects
17
17
  const sound_click = new Sound([1,.5]);
18
18
 
19
- // medals
20
- const medal_example = new Medal(0, 'Example Medal', 'Welcome to LittleJS!');
21
- medalsInit('Hello World');
22
-
23
- // game variables
24
- let particleEmitter;
25
-
26
19
  ///////////////////////////////////////////////////////////////////////////////
27
20
  function gameInit()
28
21
  {
@@ -58,23 +51,6 @@ function gameInit()
58
51
  // setup camera
59
52
  setCameraPos(vec2(16,8));
60
53
  setCameraScale(32);
61
-
62
- // enable gravity
63
- setGravity(vec2(0,-.01));
64
-
65
- // create particle emitter
66
- particleEmitter = new ParticleEmitter(
67
- vec2(16,9), 0, // emitPos, emitAngle
68
- 0, 0, 500, PI, // emitSize, emitTime, rate, cone
69
- tile(0, 16), // tileIndex, tileSize
70
- hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
71
- hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
72
- 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
73
- .99, 1, 1, PI, // damping, angleDamping, gravityScale, cone
74
- .05, .5, true, true // fadeRate, randomness, collide, additive
75
- );
76
- particleEmitter.restitution = .3; // bounce when it collides
77
- particleEmitter.trailScale = 2; // stretch as it moves
78
54
  }
79
55
 
80
56
  ///////////////////////////////////////////////////////////////////////////////
@@ -84,15 +60,6 @@ function gameUpdate()
84
60
  {
85
61
  // play sound when mouse is pressed
86
62
  sound_click.play(mousePos);
87
-
88
- // change particle color and set to fade out
89
- particleEmitter.colorStartA = randColor();
90
- particleEmitter.colorStartB = randColor();
91
- particleEmitter.colorEndA = particleEmitter.colorStartA.scale(1,0);
92
- particleEmitter.colorEndB = particleEmitter.colorStartB.scale(1,0);
93
-
94
- // unlock medals
95
- medal_example.unlock();
96
63
  }
97
64
 
98
65
  if (mouseWheel)
@@ -101,13 +68,6 @@ function gameUpdate()
101
68
  cameraScale -= sign(mouseWheel)*cameraScale/5;
102
69
  cameraScale = clamp(cameraScale, 10, 300);
103
70
  }
104
-
105
- // move particles to mouse location if on screen
106
- if (mousePosScreen.x)
107
- {
108
- particleEmitter.pos = mousePos;
109
- particleEmitter.velocity = mouseDelta.scale(.3*timeDelta);
110
- }
111
71
  }
112
72
 
113
73
  ///////////////////////////////////////////////////////////////////////////////
@@ -130,7 +90,7 @@ function gameRender()
130
90
  function gameRenderPost()
131
91
  {
132
92
  // draw to overlay canvas for hud rendering
133
- drawTextScreen('LittleJS Demo',
93
+ drawTextScreen('LittleJS Electron Demo',
134
94
  vec2(mainCanvasSize.x/2, 70), 80, // position, size
135
95
  hsl(0,0,1), 6, hsl(0,0,0)); // color, outline size and color
136
96
  }
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?11417></script>
10
+ <script src=../../dist/littlejs.js?1.15.0></script>
11
11
 
12
12
  <!-- Add your game scripts here -->
13
- <script src=game.js?11417></script>
13
+ <script src=game.js?1.15.0></script>
@@ -64,7 +64,7 @@ function gameRender()
64
64
  for (let i=0; i<1e3; ++i)
65
65
  {
66
66
  const time = LJS.time;
67
- const pos = vec2(30*Math.sin(i+time/9),20*Math.sin(i*i+time/9));
67
+ const pos = vec2(30*LJS.sin(i+time/9),20*LJS.sin(i*i+time/9));
68
68
  LJS.drawTile(pos, vec2(2), tile(3,128), hsl(i/9,1,.4), time+i, !(i%2), hsl(i/9,1,.1,0));
69
69
  }
70
70
  }
@@ -84,29 +84,34 @@ 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
- new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives', false, 'circle, ellipses, rectangles, polygon, lines'),
93
- new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL', false, 'hue, saturation, blending, rectangles'),
94
- new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth, rectangles'),
92
+ new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives', false, 'circle, ellipse, rectangle, polygon, lines'),
93
+ new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL', false, 'hue, saturation, blending, 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
102
  new ExampleInfo('Font Image', 'systemFont.js', 'Bitmap font system with built-in system font', false, 'text, characters'),
103
+ new ExampleInfo('Medals', 'medals.js', 'Achievement system', false, 'unlock, progress, newgrounds'),
104
+ new ExampleInfo('Tile Raycast', 'tileRaycast.js', 'Example of the tile layer raycast collision', false, 'level, map, grid'),
105
+ new ExampleInfo('Camera Mouse Drag', 'cameraDrag.js', 'Example of how to control camera with mose', false, 'ui, input, control'),
106
+ new ExampleInfo('Debug Drawing', 'debugDraw.js', 'Debug drawing system', false, 'debug, circle, line, rectangle'),
107
+ new ExampleInfo('--- ADVANCED ---'),
108
+ new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangle'),
109
+ new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth, rectangle'),
103
110
  new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains', false, 'generative, canvas, background'),
104
111
  new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation', false, 'generative, level, tiles, map, grid'),
105
- new ExampleInfo('Medals', 'medals.js', 'Achievement system', false, 'unlock, progress, newgrounds'),
106
- new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangles'),
107
112
  new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, sound, audio, notes, ui, instrument'),
108
113
  new ExampleInfo('Step Sequencer', 'sequencer.js', 'Simple music loop creation tool', false, 'music, sound, audio, notes, ui, instrument'),
109
- new ExampleInfo('Music Player', 'musicPlayer.js', 'Advanced music player with audio seeking and drag and drop', false, 'music, sound, audio, streaming, volume, ui'),
114
+ new ExampleInfo('Music Player', 'musicPlayer.js', 'Music player with audio seeking and drag and drop', false, 'sound, loading, audio, ui'),
110
115
  new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
111
116
  new ExampleInfo('--- MINI GAMES ---'),
112
117
  new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
@@ -118,10 +123,11 @@ const exampleList =
118
123
  new ExampleInfo('Hill Glide Game', 'hillGlideGame.js', 'Tiny wings style sliding game', false, 'objects, physics, speed'),
119
124
  new ExampleInfo('Sliding Puzzle', 'slidingPuzzle.js', '15 tile sliding puzzle', false, 'objects, numbers, ui'),
120
125
  new ExampleInfo('Space Game', 'spaceGame.js', 'Spaceship shooter with parallax', false, 'objects, weapons, stars, camera, rotation'),
121
- new ExampleInfo('Raycasting 3D Game', 'raycasting.js', 'Pseudo 3D raycasting demo', false, '3D, maze, camera'),
126
+ new ExampleInfo('3D FPS Game', 'fps.js', 'Pseudo 3D raycasting demo', false, '3D, FPS, maze, camera'),
122
127
  new ExampleInfo('--- PLUGINS ---'),
123
128
  new ExampleInfo('Box2d Demo', 'box2d.js', 'Box2D physics plugin', false, 'objects, mouse'),
124
129
  new ExampleInfo('Box2d Car', 'box2dCar.js', 'Drivable car with Box2D physics', false, 'objects, vehicle, suspension, wheels'),
130
+ new ExampleInfo('Box2d Pool', 'box2dPool.js', 'Billiard table pool game with physics', false, 'objects, game'),
125
131
  new ExampleInfo('Post Processing', 'postProcess.js', 'Shader effects and filters', false, 'webgl, visual, effect'),
126
132
  new ExampleInfo('UI System Plugin', 'uiSystem.js', 'Buttons, sliders, and checkboxes', false, 'objects, widgets, interactive'),
127
133
  new ExampleInfo('Nine Slice', 'nineSlice.js', 'Scalable UI panels', false, 'three slice, stretch, corners, text, tiles'),
@@ -551,7 +557,10 @@ function setCode(code, filename)
551
557
  {
552
558
  // setup frame controls
553
559
  setFrameControlsEnabled();
554
- iframeContent.setGLEnable(checkboxWebGL.checked);
560
+ if (iframeContent.glCanEnable())
561
+ iframeContent.setGLEnable(checkboxWebGL.checked);
562
+ else
563
+ checkboxWebGL.disabled = true;
555
564
  checkboxWebGL.onchange = ()=> iframeContent.setGLEnable(checkboxWebGL.checked);
556
565
  })
557
566
  }
@@ -69,16 +69,17 @@ function gameInit()
69
69
  // create particle emitter
70
70
  particleEmitter = new LJS.ParticleEmitter(
71
71
  vec2(16,9), 0, // emitPos, emitAngle
72
- 1, 0, 500, Math.PI, // emitSize, emitTime, rate, cone
72
+ 0, 0, 500, 3.14, // emitSize, emitTime, rate, cone
73
73
  tile(0, 16), // tileIndex, tileSize
74
74
  hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
75
75
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
76
- 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
77
- .99, 1, 1, Math.PI, // damping, angleDamping, gravityScale, cone
78
- .05, .5, true, true // fadeRate, randomness, collide, additive
76
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
77
+ .99, 1, 1, 3.14, // damping, angleDamping, gravityScale, cone
78
+ .05, .5, true, true // fadeRate, randomness, collide, additive
79
79
  );
80
80
  particleEmitter.restitution = .3; // bounce when it collides
81
81
  particleEmitter.trailScale = 2; // stretch as it moves
82
+ particleEmitter.velocityInheritance = .3; // inherit emitter velocity
82
83
  }
83
84
 
84
85
  ///////////////////////////////////////////////////////////////////////////////
@@ -101,10 +102,7 @@ function gameUpdate()
101
102
 
102
103
  // move particles to mouse location if on screen
103
104
  if (LJS.mousePosScreen.x)
104
- {
105
105
  particleEmitter.pos = LJS.mousePos;
106
- particleEmitter.velocity = LJS.mouseDelta.scale(.3*LJS.timeDelta);
107
- }
108
106
  }
109
107
 
110
108
  ///////////////////////////////////////////////////////////////////////////////
@@ -298,12 +298,10 @@ function getCode()
298
298
  {
299
299
  const expand = inputExpand.checked;
300
300
  let code = '';
301
-
302
- // https://www.codingem.com/javascript-how-to-limit-decimal-places/
303
- Number.prototype.round = function(n) {
304
- const d = Math.pow(10, n);
305
- return Math.round((this + Number.EPSILON) * d) / d;
306
- }
301
+
302
+ // limit float precision to prevent long strings
303
+ const trimFloat = (n, decimals=3)=>
304
+ Number(Number(n).toFixed(decimals));
307
305
 
308
306
  code = 'new ParticleEmitter(';
309
307
  if (expand)
@@ -325,13 +323,12 @@ function getCode()
325
323
  else if (type == 'color')
326
324
  {
327
325
  const c = particleSystem[name];
328
- const p = 3;
329
- value = `new Color(${c.r.round(p)}, ${c.g.round(p)}, ${c.b.round(p)}, ${c.a.round(p)})`;
326
+ value = `new Color(${trimFloat(c.r)}, ${trimFloat(c.g)}, ${trimFloat(c.b)}, ${trimFloat(c.a)})`;
330
327
  }
331
328
  else if (type == 'checkbox')
332
329
  value = particleSystem[name] ? 1 : 0;
333
330
  else
334
- value = particleSystem[name].round(3);
331
+ value = trimFloat(particleSystem[name]);
335
332
  if (expand)
336
333
  code += ' ';
337
334
  code += value;
@@ -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;
@@ -238,7 +239,7 @@ export class Character extends GameObjects.GameObject
238
239
  if (!this.isDead())
239
240
  {
240
241
  // bounce pos with walk cycle
241
- bodyPos = bodyPos.add(vec2(0,.05*Math.sin(this.walkCyclePercent*LJS.PI)));
242
+ bodyPos = bodyPos.add(vec2(0,.05*LJS.sin(this.walkCyclePercent*LJS.PI)));
242
243
 
243
244
  // make bottom flush
244
245
  bodyPos = bodyPos.add(vec2(0,(this.drawSize.y-this.size.y)/2));
@@ -15,6 +15,9 @@ import * as LJS from '../../dist/littlejs.esm.js';
15
15
  import * as GameLevel from './gameLevel.js';
16
16
  const {vec2, hsl, rgb} = LJS;
17
17
 
18
+ // use low graphics mode on mobile devices
19
+ const lowGraphicsMode = LJS.isTouchDevice;
20
+
18
21
  ///////////////////////////////////////////////////////////////////////////////
19
22
  // sound effects
20
23
 
@@ -33,7 +36,9 @@ export const sound_score = new LJS.Sound([,,783,,.03,.02,1,2,,,940,.03,,,
33
36
 
34
37
  export const persistentParticleDestroyCallback = (particle)=>
35
38
  {
36
- // copy particle to tile layer on death
39
+ if (lowGraphicsMode) return;
40
+
41
+ // draw particle to tile layer on death
37
42
  LJS.ASSERT(!particle.tileInfo, 'quick draw to tile layer uses canvas 2d so must be untextured');
38
43
  if (particle.groundObject)
39
44
  {
@@ -193,7 +198,7 @@ export class Sky extends LJS.EngineObject
193
198
  // draw stars
194
199
  LJS.setBlendMode(true);
195
200
  const random = new LJS.RandomGenerator(this.seed);
196
- for (let i=1e3; i--;)
201
+ for (let i= lowGraphicsMode ? 500 : 1e3; i--;)
197
202
  {
198
203
  const size = random.float(.5,2)**2;
199
204
  const speed = random.float() < .9 ? random.float(5) : random.float(9,99);
@@ -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()
@@ -106,7 +105,7 @@ export class Coin extends LJS.EngineObject
106
105
 
107
106
  // make it appear to spin
108
107
  const t = LJS.time+this.pos.x/4+this.pos.y/4;
109
- const spinSize = vec2(.5+.5*Math.sin(t*2*LJS.PI), 1);
108
+ const spinSize = vec2(.5+.5*LJS.sin(t*2*LJS.PI), 1);
110
109
  if (spinSize.x > .1)
111
110
  LJS.drawTile(this.pos, spinSize, this.tileInfo, this.color);
112
111
  }
@@ -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
 
@@ -174,7 +173,7 @@ export class Enemy extends GameObject
174
173
  {
175
174
  // bounce by changing size
176
175
  const bounceTime = this.bounceTime*6;
177
- this.drawSize = vec2(1-.1*Math.sin(bounceTime), 1+.1*Math.sin(bounceTime));
176
+ this.drawSize = vec2(1-.1*LJS.sin(bounceTime), 1+.1*LJS.sin(bounceTime));
178
177
 
179
178
  // make bottom flush
180
179
  let bodyPos = this.pos;
@@ -221,7 +220,7 @@ export class Grenade extends GameObject
221
220
 
222
221
  // draw additive flash exploding
223
222
  LJS.setBlendMode(true);
224
- const flash = Math.cos(this.getAliveTime()*2*LJS.PI);
223
+ const flash = LJS.cos(this.getAliveTime()*2*LJS.PI);
225
224
  LJS.drawTile(this.pos, vec2(2), Game.spriteAtlas.circle, hsl(0,1,.5,.2-.2*flash));
226
225
  LJS.setBlendMode(false);
227
226
  }
@@ -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(
@@ -4,13 +4,13 @@ function gameRender()
4
4
  {
5
5
  {
6
6
  // animate by changing frames
7
- const pos = vec2(-5, 2*abs(Math.sin(time*2*PI)));
7
+ const pos = vec2(-5, 2*abs(sin(time*2*PI)));
8
8
  const frame = (time*4)%2|0;
9
9
  drawTile(pos, vec2(7), tile(3).frame(frame), RED);
10
10
  }
11
11
  {
12
12
  // animate with stretch and squash
13
- const s = Math.sin(time*9)*.5;
13
+ const s = sin(time*9)*.5;
14
14
  const size = vec2(7-s,7+s);
15
15
  const pos = vec2(5,size.y-7);
16
16
  drawTile(pos, size, tile(5), GREEN);
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html><meta charset=utf-8><body>
2
- <script src=../../dist/littlejs.js?11417></script>
2
+ <script src=../../dist/littlejs.js?1.15.0></script>
3
3
  <script src=../../dist/box2d.wasm.js></script>
4
4
 
5
5
  <!-- LittleJS Engine Source
@@ -44,4 +44,7 @@ function gameUpdatePost() {}
44
44
  function gameRender() {}
45
45
  function gameRenderPost() {}
46
46
 
47
+ // check if WebGL can be enabled
48
+ function glCanEnable() { return glCanBeEnabled; }
49
+
47
50
  </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
  }