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.
- package/dist/littlejs.d.ts +173 -50
- package/dist/littlejs.esm.js +892 -419
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +879 -419
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +854 -420
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/electron/game.js +1 -41
- package/examples/electron/index.html +2 -2
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +69 -55
- package/examples/module/game.js +6 -8
- package/examples/particles/index.html +6 -9
- package/examples/platformer/gameCharacter.js +1 -1
- package/examples/platformer/gameEffects.js +8 -3
- package/examples/platformer/gameObjects.js +3 -3
- package/examples/shorts/animation.js +2 -2
- package/examples/shorts/base.html +4 -1
- package/examples/shorts/cameraDrag.js +22 -0
- package/examples/shorts/debugDraw.js +38 -0
- package/examples/shorts/fps.js +90 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +1 -1
- package/examples/shorts/landerGame.js +1 -1
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/postProcess.js +1 -1
- package/examples/shorts/sequencer.js +5 -5
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/spaceGame.js +1 -1
- package/examples/shorts/spriteAtlas.js +6 -6
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/tileLayer.js +1 -1
- package/examples/shorts/tileRaycast.js +39 -0
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +14 -6
- package/examples/shorts/topDown.js +1 -1
- package/examples/starter/game.js +6 -8
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +5 -4
- package/examples/typescript/game.ts +5 -7
- package/examples/uiSystem/game.js +3 -2
- package/package.json +1 -1
- package/plugins/postProcess.js +71 -51
- package/plugins/uiSystem.js +76 -23
- package/src/engine.js +30 -16
- package/src/engineAudio.js +33 -23
- package/src/engineDebug.js +27 -0
- package/src/engineDraw.js +103 -49
- package/src/engineExport.js +13 -0
- package/src/engineInput.js +14 -16
- package/src/engineObject.js +31 -6
- package/src/engineParticles.js +37 -16
- package/src/engineRelease.js +2 -1
- package/src/engineSettings.js +20 -1
- package/src/engineTileLayer.js +89 -94
- package/src/engineUtilities.js +206 -58
- package/src/engineWebGL.js +145 -69
- package/examples/shorts/raycasting.js +0 -79
package/examples/box2d/game.js
CHANGED
|
@@ -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,
|
|
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
|
|
package/examples/box2d/tiles.png
CHANGED
|
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
|
-
|
|
107
|
+
|
|
108
|
+
font.drawTextOverlay('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
|
|
108
109
|
if (!brickCount)
|
|
109
|
-
font.
|
|
110
|
+
font.drawTextOverlay('You Win!', LJS.cameraPos.add(vec2(0,-5)), .2, true);
|
|
110
111
|
else if (!ball)
|
|
111
|
-
font.
|
|
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
|
-
|
|
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?
|
|
10
|
+
<script src=../../dist/littlejs.js?1.14.24></script>
|
|
11
11
|
|
|
12
12
|
<!-- Add your game scripts here -->
|
|
13
|
-
<script src=game.js?
|
|
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*
|
|
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
|
}
|
package/examples/index.html
CHANGED
|
@@ -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,
|
|
83
|
-
new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL', false, 'hue, saturation, blending,
|
|
84
|
-
new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield', false, 'space, movement, depth,
|
|
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('
|
|
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('
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
///////////////////////////////////////////////////////////////////////////////
|
package/examples/module/game.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
77
|
-
.99, 1, 1,
|
|
78
|
-
.05, .5, true, true
|
|
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;
|
|
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
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
|
|
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]
|
|
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*
|
|
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
|
-
|
|
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(
|
|
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*
|
|
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*
|
|
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 =
|
|
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(
|
|
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 =
|
|
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?
|
|
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
|
+
}
|