littlejsengine 1.14.16 → 1.14.23

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 (62) hide show
  1. package/dist/littlejs.d.ts +173 -50
  2. package/dist/littlejs.esm.js +892 -419
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +879 -419
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +854 -420
  7. package/examples/box2d/game.js +3 -2
  8. package/examples/box2d/tiles.png +0 -0
  9. package/examples/breakout/game.js +5 -5
  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 +69 -55
  14. package/examples/module/game.js +6 -8
  15. package/examples/particles/index.html +6 -9
  16. package/examples/platformer/gameCharacter.js +1 -1
  17. package/examples/platformer/gameEffects.js +8 -3
  18. package/examples/platformer/gameObjects.js +3 -3
  19. package/examples/shorts/animation.js +2 -2
  20. package/examples/shorts/base.html +4 -1
  21. package/examples/shorts/cameraDrag.js +22 -0
  22. package/examples/shorts/debugDraw.js +38 -0
  23. package/examples/shorts/fps.js +90 -0
  24. package/examples/shorts/helloWorld.js +1 -1
  25. package/examples/shorts/hillGlideGame.js +1 -1
  26. package/examples/shorts/landerGame.js +1 -1
  27. package/examples/shorts/musicPlayer.js +1 -0
  28. package/examples/shorts/parallax.js +1 -1
  29. package/examples/shorts/postProcess.js +1 -1
  30. package/examples/shorts/sequencer.js +5 -5
  31. package/examples/shorts/shader.js +29 -0
  32. package/examples/shorts/spaceGame.js +1 -1
  33. package/examples/shorts/spriteAtlas.js +6 -6
  34. package/examples/shorts/starfield.js +1 -1
  35. package/examples/shorts/tileLayer.js +1 -1
  36. package/examples/shorts/tileRaycast.js +39 -0
  37. package/examples/shorts/tiles.png +0 -0
  38. package/examples/shorts/tiltedView.js +14 -6
  39. package/examples/shorts/topDown.js +1 -1
  40. package/examples/starter/game.js +6 -8
  41. package/examples/starter/index.html +2 -2
  42. package/examples/style.css +1 -0
  43. package/examples/typescript/game.js +5 -4
  44. package/examples/typescript/game.ts +5 -7
  45. package/examples/uiSystem/game.js +3 -2
  46. package/package.json +1 -1
  47. package/plugins/postProcess.js +71 -51
  48. package/plugins/uiSystem.js +76 -23
  49. package/src/engine.js +30 -16
  50. package/src/engineAudio.js +33 -23
  51. package/src/engineDebug.js +27 -0
  52. package/src/engineDraw.js +103 -49
  53. package/src/engineExport.js +13 -0
  54. package/src/engineInput.js +14 -16
  55. package/src/engineObject.js +31 -6
  56. package/src/engineParticles.js +37 -16
  57. package/src/engineRelease.js +2 -1
  58. package/src/engineSettings.js +20 -1
  59. package/src/engineTileLayer.js +89 -94
  60. package/src/engineUtilities.js +206 -58
  61. package/src/engineWebGL.js +145 -69
  62. package/examples/shorts/raycasting.js +0 -79
@@ -56,10 +56,9 @@ async function gameInit()
56
56
  // start up LittleJS Box2D plugin
57
57
  await LJS.box2dInit();
58
58
  //LJS.box2dSetDebug(true); // enable box2d debug draw
59
- LJS.setCanvasClearColor(hsl(0,0,.8));
60
59
 
61
60
  // create a table of all sprites
62
- const gameTile = (i)=> LJS.tile(i, 496, 0, 8);
61
+ const gameTile = (i)=> LJS.tile(i, 124, 0, 2);
63
62
  spriteAtlas =
64
63
  {
65
64
  circle: gameTile(0),
@@ -71,6 +70,8 @@ async function gameInit()
71
70
  squareOutline2: gameTile(6),
72
71
  };
73
72
 
73
+ // startup the demo
74
+ LJS.setCanvasClearColor(hsl(0,0,.8));
74
75
  setScene(startScene);
75
76
  }
76
77
 
Binary file
@@ -104,11 +104,12 @@ function gameRenderPost()
104
104
  {
105
105
  // use built in image font for text
106
106
  const font = new LJS.FontImage;
107
- font.drawText('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
107
+
108
+ font.drawTextOverlay('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
108
109
  if (!brickCount)
109
- font.drawText('You Win!', LJS.cameraPos.add(vec2(0,-5)), .2, true);
110
+ font.drawTextOverlay('You Win!', LJS.cameraPos.add(vec2(0,-5)), .2, true);
110
111
  else if (!ball)
111
- font.drawText('Click to Play', LJS.cameraPos.add(vec2(0,-5)), .2, true);
112
+ font.drawTextOverlay('Click to Play', LJS.cameraPos.add(vec2(0,-5)), .2, true);
112
113
  }
113
114
 
114
115
  ///////////////////////////////////////////////////////////////////////////////
@@ -167,8 +168,7 @@ function setupPostProcess()
167
168
  c *= 1.-pow((dx*dx + dy*dy)/vignette, vignettePow);
168
169
  }`;
169
170
 
170
- const includeOverlay = true;
171
- new LJS.PostProcessPlugin(televisionShader, includeOverlay);
171
+ new LJS.PostProcessPlugin(televisionShader);
172
172
  }
173
173
 
174
174
  ///////////////////////////////////////////////////////////////////////////////
@@ -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
- 2, .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?11416></script>
10
+ <script src=../../dist/littlejs.js?1.14.24></script>
11
11
 
12
12
  <!-- Add your game scripts here -->
13
- <script src=game.js?11416></script>
13
+ <script src=game.js?1.14.24></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
  }
@@ -4,6 +4,17 @@
4
4
  <link rel=stylesheet href=style.css?9>
5
5
  <meta charset=utf-8>
6
6
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
7
+ <!-- meta tags for social media -->
8
+ <meta name='twitter:title' content='LittleJS Example Browser'>
9
+ <meta property='og:title' content='LittleJS Example Browser'>
10
+ <meta name='description' content='Tiny fast HTML5 game engine!'>
11
+ <meta name='twitter:description' content='Tiny fast HTML5 game engine!'>
12
+ <meta property='og:description' content='Tiny fast HTML5 game engine!'>
13
+ <meta name='twitter:image' content='https://3d2k.com/images/LittleJSExamples.png'>
14
+ <meta property='og:image' content='https://3d2k.com/images/LittleJSExamples.png'>
15
+ <meta name='keywords' content='JavaScript, HTML5, Game, Engine'>
16
+ <meta name='twitter:creator' content='@KilledByAPixel'>
17
+ <meta name='twitter:card' content='summary_large_image'>
7
18
  </head><body>
8
19
  <div id=container1>
9
20
  <div id=container3>
@@ -21,8 +32,7 @@ Theme:
21
32
  <option value=20px>L</option>
22
33
  <option value=24px>XL</option>
23
34
  </select>
24
- <span class=nowrap><input type=checkbox id=checkboxLiveEdit checked>Live Edit</span>
25
- <span class=nowrap><input type=checkbox id=checkboxJumpToErrors>Jump to Errors</span>
35
+ <span class=nowrap><input type=checkbox id=checkboxLiveEdit onchange=writeSaveData() checked>Live Edit</span>
26
36
  </div>
27
37
  <div id=divTextareas>
28
38
  <textarea id=textareaCode oninput=codeInput() spellcheck=false></textarea>
@@ -79,9 +89,9 @@ const exampleList =
79
89
  new ExampleInfo('Empty', 'empty.js', 'Empty example template', false, 'beginner, text'),
80
90
  new ExampleInfo('Texture', 'texture.js', 'Texture display and manipulation', false, 'sprites, loading, tiles'),
81
91
  new ExampleInfo('Animation', 'animation.js', 'Sprite animation system', false, 'frames, loop, tiles, sprites'),
82
- new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives', false, 'circle, ellipses, rectangles, polygon, lines'),
83
- new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL', false, 'hue, saturation, blending, rectangles'),
84
- 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'),
94
+ new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth, rectangle'),
85
95
  new ExampleInfo('Sprite Atlas', 'spriteAtlas.js', 'Sprite atlas and tile rendering', false, 'sheet, frames, tiles'),
86
96
  new ExampleInfo('Blending', 'blending.js', 'Additive blending and transparency', false, 'alpha, color, tiles, smooth'),
87
97
  new ExampleInfo('Tile Layer', 'tileLayer.js', 'Tile layer rendering system', false, 'level, map, grid, particles'),
@@ -93,10 +103,14 @@ const exampleList =
93
103
  new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains', false, 'generative, canvas, background'),
94
104
  new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation', false, 'generative, level, tiles, map, grid'),
95
105
  new ExampleInfo('Medals', 'medals.js', 'Achievement system', false, 'unlock, progress, newgrounds'),
96
- new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangles'),
106
+ 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
+ new ExampleInfo('Camera Mouse Drag', 'cameraDrag.js', 'Example of how to control camera with mose', false, 'ui, input, control'),
109
+ new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangle'),
97
110
  new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, sound, audio, notes, ui, instrument'),
98
111
  new ExampleInfo('Step Sequencer', 'sequencer.js', 'Simple music loop creation tool', false, 'music, sound, audio, notes, ui, instrument'),
99
112
  new ExampleInfo('Music Player', 'musicPlayer.js', 'Advanced music player with audio seeking and drag and drop', false, 'music, sound, audio, streaming, volume, ui'),
113
+ new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
100
114
  new ExampleInfo('--- MINI GAMES ---'),
101
115
  new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
102
116
  new ExampleInfo('Platformer Game', 'platformer.js', 'Jump and run side view', false, 'objects, gravity, level, tiles, camera'),
@@ -107,7 +121,7 @@ const exampleList =
107
121
  new ExampleInfo('Hill Glide Game', 'hillGlideGame.js', 'Tiny wings style sliding game', false, 'objects, physics, speed'),
108
122
  new ExampleInfo('Sliding Puzzle', 'slidingPuzzle.js', '15 tile sliding puzzle', false, 'objects, numbers, ui'),
109
123
  new ExampleInfo('Space Game', 'spaceGame.js', 'Spaceship shooter with parallax', false, 'objects, weapons, stars, camera, rotation'),
110
- new ExampleInfo('Raycasting 3D Game', 'raycasting.js', 'Pseudo 3D raycasting demo', false, '3D, maze, camera'),
124
+ new ExampleInfo('3D FPS Game', 'fps.js', 'Pseudo 3D raycasting demo', false, '3D, FPS, maze, camera'),
111
125
  new ExampleInfo('--- PLUGINS ---'),
112
126
  new ExampleInfo('Box2d Demo', 'box2d.js', 'Box2D physics plugin', false, 'objects, mouse'),
113
127
  new ExampleInfo('Box2d Car', 'box2dCar.js', 'Drivable car with Box2D physics', false, 'objects, vehicle, suspension, wheels'),
@@ -141,7 +155,7 @@ function initExampleBrowser()
141
155
  // set the selected example from the URL parameters
142
156
  const urlParams = new URLSearchParams(window.location.search);
143
157
  const selectedExample = urlParams.get('example') || '';
144
- let exampleIndex = exampleList.findIndex((example) => example.filename === selectedExample);
158
+ let exampleIndex = exampleList.findIndex((example) => example.name === selectedExample);
145
159
  if (exampleIndex < 0)
146
160
  exampleIndex = 1;
147
161
  selectExample.selectedIndex = exampleIndex;
@@ -240,7 +254,7 @@ function setExample()
240
254
 
241
255
  // update URL parameter
242
256
  const url = new URL(window.location);
243
- url.searchParams.set('example', example.filename);
257
+ url.searchParams.set('example', example.name);
244
258
  window.history.replaceState({}, '', url);
245
259
 
246
260
  loadFile(example.filename, example.largeExample);
@@ -540,7 +554,10 @@ function setCode(code, filename)
540
554
  {
541
555
  // setup frame controls
542
556
  setFrameControlsEnabled();
543
- iframeContent.setGLEnable(checkboxWebGL.checked);
557
+ if (iframeContent.glCanEnable())
558
+ iframeContent.setGLEnable(checkboxWebGL.checked);
559
+ else
560
+ checkboxWebGL.disabled = true;
544
561
  checkboxWebGL.onchange = ()=> iframeContent.setGLEnable(checkboxWebGL.checked);
545
562
  })
546
563
  }
@@ -616,35 +633,6 @@ function setErrorLine(lineNumber)
616
633
  clearErrorLine();
617
634
  --lineNumber; // codeMirror uses 0-based line numbers
618
635
  errorLineMarker = codeMirror.getDoc().addLineClass(lineNumber, 'background', 'error-line');
619
- if (checkboxJumpToErrors.checked)
620
- {
621
- codeMirror.scrollIntoView({line: lineNumber, ch: 0});
622
- codeMirror.focus();
623
- }
624
- }
625
- else if (textareaCode && checkboxJumpToErrors.checked)
626
- {
627
- // for textarea, calculate character position and set cursor
628
- const lines = textareaCode.value.split('\n');
629
- let charPos = 0;
630
- for (let i = 0; i < lineNumber - 1 && i < lines.length; i++)
631
- {
632
- charPos += lines[i].length + 1; // +1 for newline character
633
- }
634
- textareaCode.setSelectionRange(charPos, charPos);
635
- if (checkboxJumpToErrors.checked)
636
- {
637
- const line = textareaCode.value.split('\n');
638
- lineNumber = Math.min(Math.max(0, lineNumber-1), lines.length-1);
639
-
640
- // select error line in textarea
641
- let start = 0;
642
- for (let i = 0; i < lineNumber; i++)
643
- start += lines[i].length + 1;
644
- textareaCode.selectionStart = start;
645
- textareaCode.selectionEnd = start + lines[lineNumber].length;
646
- textareaCode.focus();
647
- }
648
636
  }
649
637
  }
650
638
 
@@ -669,13 +657,41 @@ textareaConsole.addEventListener('scroll', onScrollConsole);
669
657
 
670
658
  ///////////////////////////////////////////////////////////////////////////////
671
659
  // load saved preferences from localStorage
672
- const defaultTheme = 'littlejs';
673
- const defaultFontSize = '16px';
674
- const savePrefix = 'LittleJSExamples_';
675
- const savedTheme = localStorage.getItem(savePrefix+'theme') || defaultTheme;
676
- const savedFontSize = localStorage.getItem(savePrefix+'fontSize') || defaultFontSize;
677
- selectFontSize.value = savedFontSize;
678
- textareaCode.style.fontSize = savedFontSize;
660
+ const saveName = 'LittleJSExamples';
661
+ let savedTheme;
662
+
663
+ function readSaveData()
664
+ {
665
+ // load saved preferences
666
+ const defaultTheme = 'littlejs';
667
+ const defaultFontSize = '16px';
668
+ const saveDataJSON = localStorage.getItem(saveName);
669
+ const saveData = saveDataJSON ? JSON.parse(saveDataJSON) : {};
670
+ selectTheme.value = savedTheme = saveData.theme ?? defaultTheme;
671
+ selectFontSize.value = saveData.fontSize ?? defaultFontSize;
672
+ }
673
+ readSaveData();
674
+
675
+ function writeSaveData()
676
+ {
677
+ // Save preferences to localStorage
678
+ const theme = selectTheme.value;
679
+ const fontSize = selectFontSize.value;
680
+ const saveData =
681
+ {
682
+ theme,
683
+ fontSize
684
+ };
685
+ const saveDataJSON = JSON.stringify(saveData);
686
+ localStorage.setItem(saveName, saveDataJSON);
687
+ }
688
+
689
+ function resetDefaults()
690
+ {
691
+ localStorage.removeItem(saveName);
692
+ readSaveData();
693
+ loadTheme();
694
+ }
679
695
 
680
696
  ///////////////////////////////////////////////////////////////////////////////
681
697
  // setup code mirror
@@ -753,20 +769,18 @@ function addCodeMirrorElement(filename, type, rel)
753
769
 
754
770
  function loadTheme()
755
771
  {
756
- const theme = selectTheme.value;
757
- const size = selectFontSize.value;
758
-
759
- // Save preferences to localStorage
760
- localStorage.setItem(savePrefix+'theme', theme);
761
- localStorage.setItem(savePrefix+'fontSize', size);
762
-
763
772
  // Apply the theme and font size
764
- textareaCode.style.fontSize = size;
773
+ const theme = selectTheme.value;
774
+ const fontSize = selectFontSize.value;
775
+ textareaCode.style.fontSize = fontSize;
765
776
  if (codeMirror)
766
777
  {
767
- codeMirror.getWrapperElement().style.fontSize = size;
778
+ codeMirror.getWrapperElement().style.fontSize = fontSize;
768
779
  codeMirror.setOption('theme', theme);
769
780
  }
781
+
782
+ // Save preferences to localStorage
783
+ writeSaveData();
770
784
  }
771
785
 
772
786
  ///////////////////////////////////////////////////////////////////////////////
@@ -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
- 2, .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
- particleEmitter.trailScale = 2; // stretch as it moves
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;
@@ -238,7 +238,7 @@ export class Character extends GameObjects.GameObject
238
238
  if (!this.isDead())
239
239
  {
240
240
  // bounce pos with walk cycle
241
- bodyPos = bodyPos.add(vec2(0,.05*Math.sin(this.walkCyclePercent*LJS.PI)));
241
+ bodyPos = bodyPos.add(vec2(0,.05*LJS.sin(this.walkCyclePercent*LJS.PI)));
242
242
 
243
243
  // make bottom flush
244
244
  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);
@@ -255,7 +260,7 @@ export class ParallaxLayer extends LJS.CanvasLayer
255
260
  this.context.clearRect(0,0,1,h);
256
261
 
257
262
  // make WebGL texture
258
- this.useWebGL(LJS.glEnable);
263
+ this.useWebGL();
259
264
  }
260
265
 
261
266
  render()
@@ -106,7 +106,7 @@ export class Coin extends LJS.EngineObject
106
106
 
107
107
  // make it appear to spin
108
108
  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);
109
+ const spinSize = vec2(.5+.5*LJS.sin(t*2*LJS.PI), 1);
110
110
  if (spinSize.x > .1)
111
111
  LJS.drawTile(this.pos, spinSize, this.tileInfo, this.color);
112
112
  }
@@ -174,7 +174,7 @@ export class Enemy extends GameObject
174
174
  {
175
175
  // bounce by changing size
176
176
  const bounceTime = this.bounceTime*6;
177
- this.drawSize = vec2(1-.1*Math.sin(bounceTime), 1+.1*Math.sin(bounceTime));
177
+ this.drawSize = vec2(1-.1*LJS.sin(bounceTime), 1+.1*LJS.sin(bounceTime));
178
178
 
179
179
  // make bottom flush
180
180
  let bodyPos = this.pos;
@@ -221,7 +221,7 @@ export class Grenade extends GameObject
221
221
 
222
222
  // draw additive flash exploding
223
223
  LJS.setBlendMode(true);
224
- const flash = Math.cos(this.getAliveTime()*2*LJS.PI);
224
+ const flash = LJS.cos(this.getAliveTime()*2*LJS.PI);
225
225
  LJS.drawTile(this.pos, vec2(2), Game.spriteAtlas.circle, hsl(0,1,.5,.2-.2*flash));
226
226
  LJS.setBlendMode(false);
227
227
  }
@@ -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?11416></script>
2
+ <script src=../../dist/littlejs.js?1.14.24></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>
@@ -0,0 +1,22 @@
1
+ function gameInit()
2
+ {
3
+ // create some objects
4
+ for (let i=500; i--;)
5
+ {
6
+ const pos = randInCircle(100);
7
+ const size = vec2(rand(2,9),rand(2,9));
8
+ const color = randColor();
9
+ const angle = rand(PI);
10
+ new EngineObject(pos, size, 0, angle, color);
11
+ }
12
+ }
13
+
14
+ function gameUpdate()
15
+ {
16
+ // drag camera with mouse
17
+ if (mouseIsDown(0))
18
+ cameraPos = cameraPos.subtract(mouseDelta);
19
+
20
+ // zoom camera with mouse wheel
21
+ cameraScale = clamp(cameraScale*(1-mouseWheel/5), 1, 1e3);
22
+ }
@@ -0,0 +1,38 @@
1
+ class BounceObject extends EngineObject
2
+ {
3
+ constructor(pos, size, tile)
4
+ {
5
+ super(pos, size, tile);
6
+ this.velocity = vec2(.1);
7
+ }
8
+
9
+ update()
10
+ {
11
+ super.update();
12
+
13
+ // show debug info
14
+ debugText('Debug Text', this.pos.add(vec2(0,3)), 1, WHITE);
15
+ debugRect(this.pos, this.size, RED);
16
+ debugPoly(mousePos, [vec2(-2,-1), vec2(0,2), vec2(2,-1)], YELLOW);
17
+ debugLine(this.pos, mousePos, BLUE);
18
+
19
+ // bounce off screen edges
20
+ const cameraSize = getCameraSize();
21
+ if (abs(this.pos.x) > cameraSize.x/2)
22
+ {
23
+ debugCircle(this.pos, 3, GREEN, 1);
24
+ this.velocity.x = -this.velocity.x;
25
+ }
26
+ if (abs(this.pos.y) > cameraSize.y/2)
27
+ {
28
+ debugCircle(this.pos, 3, GREEN, 1);
29
+ this.velocity.y = -this.velocity.y;
30
+ }
31
+ }
32
+ }
33
+
34
+ function gameInit()
35
+ {
36
+ canvasClearColor = GRAY;
37
+ new BounceObject(vec2(), vec2(5), tile(3,128));
38
+ }