littlejsengine 1.1.18 → 1.2.3
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/README.md +17 -11
- package/build.bat +1 -0
- package/engine/engine.all.js +495 -504
- package/engine/engine.all.min.js +1 -1
- package/engine/engine.all.release.js +418 -259
- package/engine/engine.js +31 -23
- package/engine/engineAudio.js +21 -7
- package/engine/engineBuild.bat +9 -1
- package/engine/engineBuildSetup.bat +2 -1
- package/engine/engineDebug.js +81 -247
- package/engine/engineDraw.js +109 -21
- package/engine/engineFont.png +0 -0
- package/engine/engineInput.js +103 -50
- package/engine/engineMedals.js +17 -20
- package/engine/engineObject.js +14 -23
- package/engine/engineParticles.js +8 -6
- package/engine/engineRelease.js +3 -1
- package/engine/engineSettings.js +20 -10
- package/engine/engineTileLayer.js +19 -18
- package/engine/engineUtilities.js +14 -12
- package/engine/engineWebGL.js +59 -68
- package/engine/index.d.ts +1617 -0
- package/examples/breakout/game.js +9 -7
- package/examples/breakout/gameObjects.js +3 -3
- package/examples/breakout/index.html +6 -4
- package/examples/platformer/game.js +5 -5
- package/examples/platformer/gameEffects.js +11 -14
- package/examples/platformer/gameLevel.js +14 -7
- package/examples/platformer/gameObjects.js +3 -3
- package/examples/platformer/gamePlayer.js +13 -8
- package/examples/platformer/index.html +9 -7
- package/examples/platformer/tiles.png +0 -0
- package/examples/puzzle/game.js +2 -2
- package/examples/puzzle/index.html +5 -3
- package/examples/screenshot.jpg +0 -0
- package/examples/stress/index.html +7 -5
- package/game.js +9 -8
- package/index.html +16 -14
- package/package.json +1 -1
package/engine/engine.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
const engineName = 'LittleJS';
|
|
23
23
|
|
|
24
24
|
/** Version of engine */
|
|
25
|
-
const engineVersion = '1.
|
|
25
|
+
const engineVersion = '1.2.3';
|
|
26
26
|
|
|
27
27
|
/** Frames per second to update objects
|
|
28
28
|
* @default */
|
|
@@ -35,7 +35,7 @@ const timeDelta = 1/frameRate;
|
|
|
35
35
|
/** Array containing all engine objects */
|
|
36
36
|
let engineObjects = [];
|
|
37
37
|
|
|
38
|
-
/** Array containing only objects that are set to collide with other objects (for optimization) */
|
|
38
|
+
/** Array containing only objects that are set to collide with other objects this frame (for optimization) */
|
|
39
39
|
let engineObjectsCollide = [];
|
|
40
40
|
|
|
41
41
|
/** Current update frame, used to calculate time */
|
|
@@ -51,8 +51,15 @@ let timeReal = 0;
|
|
|
51
51
|
let paused = 0;
|
|
52
52
|
|
|
53
53
|
// Engine internal variables not exposed to documentation
|
|
54
|
-
let frameTimeLastMS = 0, frameTimeBufferMS = 0,
|
|
55
|
-
|
|
54
|
+
let frameTimeLastMS = 0, frameTimeBufferMS = 0, tileImageSize, tileImageFixBleed;
|
|
55
|
+
|
|
56
|
+
// Engine stat tracking, if showWatermark is true
|
|
57
|
+
let averageFPS, drawCount;
|
|
58
|
+
|
|
59
|
+
// css text used for elements created by engine
|
|
60
|
+
const styleBody = 'margin:0;overflow:hidden;background:#000' +
|
|
61
|
+
';touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none';
|
|
62
|
+
const styleCanvas = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)';
|
|
56
63
|
|
|
57
64
|
///////////////////////////////////////////////////////////////////////////////
|
|
58
65
|
|
|
@@ -70,17 +77,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
70
77
|
tileImage.onerror = tileImage.onload = ()=>
|
|
71
78
|
{
|
|
72
79
|
// save tile image info
|
|
73
|
-
|
|
80
|
+
tileImageFixBleed = vec2(tileFixBleedScale).divide(tileImageSize = vec2(tileImage.width, tileImage.height));
|
|
74
81
|
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
75
|
-
shrinkTilesX = tileBleedShrinkFix/tileImageSize.x;
|
|
76
|
-
shrinkTilesY = tileBleedShrinkFix/tileImageSize.y;
|
|
77
82
|
|
|
78
83
|
// setup html
|
|
84
|
+
document.body.style = styleBody;
|
|
79
85
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
80
|
-
document.body.style = 'margin:0;overflow:hidden;background:#000' +
|
|
81
|
-
(touchMouseEnable?';touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none':'');
|
|
82
|
-
mainCanvas.style = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)';
|
|
83
86
|
mainContext = mainCanvas.getContext('2d');
|
|
87
|
+
mainCanvas.style = styleCanvas;
|
|
84
88
|
|
|
85
89
|
// init stuff and start engine
|
|
86
90
|
debugInit();
|
|
@@ -88,8 +92,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
88
92
|
|
|
89
93
|
// create overlay canvas for hud to appear above gl canvas
|
|
90
94
|
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
91
|
-
overlayCanvas.style = mainCanvas.style.cssText;
|
|
92
95
|
overlayContext = overlayCanvas.getContext('2d');
|
|
96
|
+
overlayCanvas.style = styleCanvas;
|
|
93
97
|
|
|
94
98
|
gameInit();
|
|
95
99
|
touchGamepadCreate();
|
|
@@ -105,7 +109,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
105
109
|
let frameTimeDeltaMS = frameTimeMS - frameTimeLastMS;
|
|
106
110
|
frameTimeLastMS = frameTimeMS;
|
|
107
111
|
if (debug || showWatermark)
|
|
108
|
-
|
|
112
|
+
averageFPS = lerp(.05, averageFPS || 0, 1e3/(frameTimeDeltaMS||1));
|
|
109
113
|
if (debug)
|
|
110
114
|
frameTimeDeltaMS *= keyIsDown(107) ? 5 : keyIsDown(109) ? .2 : 1; // +/- to speed/slow time
|
|
111
115
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
@@ -192,7 +196,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
192
196
|
overlayContext.font = '1em monospace';
|
|
193
197
|
overlayContext.fillStyle = '#000';
|
|
194
198
|
const text = engineName + ' ' + 'v' + engineVersion + ' / '
|
|
195
|
-
+ drawCount + ' / ' + engineObjects.length + ' / ' +
|
|
199
|
+
+ drawCount + ' / ' + engineObjects.length + ' / ' + averageFPS.toFixed(1)
|
|
200
|
+
+ ' ' + (glEnable ? 'GL' : '2D') ;
|
|
196
201
|
overlayContext.fillText(text, mainCanvas.width-3, 3);
|
|
197
202
|
overlayContext.fillStyle = '#fff';
|
|
198
203
|
overlayContext.fillText(text, mainCanvas.width-2, 2);
|
|
@@ -209,7 +214,11 @@ function enginePreRender()
|
|
|
209
214
|
{
|
|
210
215
|
// save canvas size and clear canvases
|
|
211
216
|
mainCanvasSize = vec2(overlayCanvas.width = mainCanvas.width, overlayCanvas.height = mainCanvas.height);
|
|
212
|
-
|
|
217
|
+
|
|
218
|
+
// disable smoothing for pixel art
|
|
219
|
+
mainContext.imageSmoothingEnabled = !cavasPixelated;
|
|
220
|
+
|
|
221
|
+
// setup gl rendering if enabled
|
|
213
222
|
glPreRender(mainCanvas.width, mainCanvas.height, cameraPos.x, cameraPos.y, cameraScale);
|
|
214
223
|
}
|
|
215
224
|
|
|
@@ -218,6 +227,9 @@ function enginePreRender()
|
|
|
218
227
|
/** Calls update on each engine object (recursively if child), removes destroyed objects, and updated time */
|
|
219
228
|
function engineObjectsUpdate()
|
|
220
229
|
{
|
|
230
|
+
// get list of solid objects for physics optimzation
|
|
231
|
+
engineObjectsCollide = engineObjects.filter(o=>o.collideSolidObjects);
|
|
232
|
+
|
|
221
233
|
// recursive object update
|
|
222
234
|
const updateObject = (o)=>
|
|
223
235
|
{
|
|
@@ -233,17 +245,16 @@ function engineObjectsUpdate()
|
|
|
233
245
|
|
|
234
246
|
// remove destroyed objects
|
|
235
247
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
236
|
-
engineObjectsCollide = engineObjectsCollide.filter(o=>!o.destroyed);
|
|
237
248
|
|
|
238
249
|
// increment frame and update time
|
|
239
250
|
time = ++frame / frameRate;
|
|
240
251
|
}
|
|
241
252
|
|
|
242
|
-
/**
|
|
253
|
+
/** Destroy and remove all objects */
|
|
243
254
|
function engineObjectsDestroy()
|
|
244
255
|
{
|
|
245
256
|
for (const o of engineObjects)
|
|
246
|
-
o.
|
|
257
|
+
o.parent || o.destroy();
|
|
247
258
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
248
259
|
}
|
|
249
260
|
|
|
@@ -254,21 +265,18 @@ function engineObjectsDestroy()
|
|
|
254
265
|
* @param {Array} [objects=engineObjects] - List of objects to check */
|
|
255
266
|
function engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
|
256
267
|
{
|
|
257
|
-
if (!pos)
|
|
268
|
+
if (!pos) // all objects
|
|
258
269
|
{
|
|
259
|
-
// all objects
|
|
260
270
|
for (const o of objects)
|
|
261
271
|
callbackFunction(o);
|
|
262
272
|
}
|
|
263
|
-
else if (size.x != undefined)
|
|
273
|
+
else if (size.x != undefined) // bounding box test
|
|
264
274
|
{
|
|
265
|
-
// aabb test
|
|
266
275
|
for (const o of objects)
|
|
267
276
|
isOverlapping(pos, size, o.pos, o.size) && callbackFunction(o);
|
|
268
277
|
}
|
|
269
|
-
else
|
|
278
|
+
else // circle test
|
|
270
279
|
{
|
|
271
|
-
// circle test
|
|
272
280
|
const sizeSquared = size*size;
|
|
273
281
|
for (const o of objects)
|
|
274
282
|
pos.distanceSquared(o.pos) < sizeSquared && callbackFunction(o);
|
package/engine/engineAudio.js
CHANGED
|
@@ -69,7 +69,7 @@ class Sound
|
|
|
69
69
|
return; // out of range
|
|
70
70
|
|
|
71
71
|
// attenuate volume by distance
|
|
72
|
-
volume *= percent(lengthSquared**.5, range*this.taper
|
|
72
|
+
volume *= percent(lengthSquared**.5, range, range*this.taper);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// get pan from screen space coords
|
|
@@ -195,7 +195,7 @@ function speak(text, language='', volume=1, rate=1, pitch=1)
|
|
|
195
195
|
|
|
196
196
|
/** Stop all queued speech
|
|
197
197
|
* @memberof Audio */
|
|
198
|
-
const
|
|
198
|
+
const speakStop = ()=> speechSynthesis && speechSynthesis.cancel();
|
|
199
199
|
|
|
200
200
|
/** Get frequency of a note on a musical scale
|
|
201
201
|
* @param {Number} semitoneOffset - How many semitones away from the root note
|
|
@@ -226,6 +226,13 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
|
226
226
|
if (!audioContext)
|
|
227
227
|
audioContext = new (window.AudioContext||webkitAudioContext);
|
|
228
228
|
|
|
229
|
+
// fix stalled audio
|
|
230
|
+
audioContext.resume();
|
|
231
|
+
|
|
232
|
+
// prevent sounds from building up if they can't be played
|
|
233
|
+
if (audioContext.state != 'running')
|
|
234
|
+
return;
|
|
235
|
+
|
|
229
236
|
// create buffer and source
|
|
230
237
|
const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length, zzfxR),
|
|
231
238
|
source = audioContext.createBufferSource();
|
|
@@ -236,11 +243,18 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
|
236
243
|
source.playbackRate.value = rate;
|
|
237
244
|
source.loop = loop;
|
|
238
245
|
|
|
239
|
-
// create
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
// create and connect gain node (createGain is more widley spported then GainNode construtor)
|
|
247
|
+
const gainNode = audioContext.createGain();
|
|
248
|
+
gainNode.gain.value = soundVolume*volume;
|
|
249
|
+
gainNode.connect(audioContext.destination);
|
|
250
|
+
|
|
251
|
+
// connect source to gain
|
|
252
|
+
(
|
|
253
|
+
window.StereoPannerNode ? // create pan node if possible
|
|
254
|
+
source.connect(new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)}))
|
|
255
|
+
: source
|
|
256
|
+
)
|
|
257
|
+
.connect(gainNode);
|
|
244
258
|
|
|
245
259
|
// play and return sound
|
|
246
260
|
source.start();
|
package/engine/engineBuild.bat
CHANGED
|
@@ -87,7 +87,15 @@ if %ERRORLEVEL% NEQ 0 (
|
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
rem lightly minify with uglify
|
|
90
|
-
call uglifyjs -o
|
|
90
|
+
call uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
|
|
91
|
+
if %ERRORLEVEL% NEQ 0 (
|
|
92
|
+
pause
|
|
93
|
+
exit /b %ERRORLEVEL%
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
rem --- BUILD TYPESCRIPT DEFINITIONS ---
|
|
97
|
+
|
|
98
|
+
call tsc engine.all.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
|
|
91
99
|
if %ERRORLEVEL% NEQ 0 (
|
|
92
100
|
pause
|
|
93
101
|
exit /b %ERRORLEVEL%
|
package/engine/engineDebug.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LittleJS - Debug Build
|
|
3
|
+
MIT License - Copyright 2021 Frank Force
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* LittleJS Debug System
|
|
3
|
-
* <br> -
|
|
8
|
+
* <br> - Press ~ to show debug overlay with mouse pick
|
|
9
|
+
* <br> - Number keys toggle debug functions
|
|
10
|
+
* <br> - +/- apply time scale
|
|
4
11
|
* <br> - Debug primitive rendering
|
|
5
|
-
* <br> - Save
|
|
12
|
+
* <br> - Save a 2d canvas as an image
|
|
6
13
|
* @namespace Debug
|
|
7
14
|
*/
|
|
8
15
|
|
|
@@ -34,7 +41,7 @@ let showWatermark = 1;
|
|
|
34
41
|
let godMode = 0;
|
|
35
42
|
|
|
36
43
|
// Engine internal variables not exposed to documentation
|
|
37
|
-
let debugPrimitives = [], debugOverlay = 0, debugPhysics = 0, debugRaycast = 0,
|
|
44
|
+
let debugPrimitives = [], debugOverlay = 0, debugPhysics = 0, debugRaycast = 0,
|
|
38
45
|
debugParticles = 0, debugGamepads = 0, debugMedals = 0, debugTakeScreenshot, downloadLink;
|
|
39
46
|
|
|
40
47
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -153,25 +160,28 @@ const debugUpdate = ()=>
|
|
|
153
160
|
{
|
|
154
161
|
if (!debug)
|
|
155
162
|
return;
|
|
156
|
-
|
|
163
|
+
|
|
157
164
|
if (keyWasPressed(192)) // ~
|
|
158
165
|
debugOverlay = !debugOverlay;
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
166
|
+
if (debugOverlay)
|
|
167
|
+
{
|
|
168
|
+
if (keyWasPressed(48)) // 0
|
|
169
|
+
showWatermark = !showWatermark;
|
|
170
|
+
if (keyWasPressed(49)) // 1
|
|
171
|
+
debugPhysics = !debugPhysics, debugParticles = 0;
|
|
172
|
+
if (keyWasPressed(50)) // 2
|
|
173
|
+
debugParticles = !debugParticles, debugPhysics = 0;
|
|
174
|
+
if (keyWasPressed(51)) // 3
|
|
175
|
+
debugGamepads = !debugGamepads;
|
|
176
|
+
if (keyWasPressed(52)) // 4
|
|
177
|
+
godMode = !godMode;
|
|
178
|
+
if (keyWasPressed(53)) // 5
|
|
179
|
+
debugTakeScreenshot = 1;
|
|
180
|
+
//if (keyWasPressed(54)) // 6
|
|
181
|
+
//if (keyWasPressed(55)) // 7
|
|
182
|
+
//if (keyWasPressed(56)) // 8
|
|
183
|
+
//if (keyWasPressed(57)) // 9
|
|
184
|
+
}
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
const debugRender = ()=>
|
|
@@ -191,21 +201,20 @@ const debugRender = ()=>
|
|
|
191
201
|
|
|
192
202
|
if (debugGamepads && gamepadsEnable && navigator.getGamepads)
|
|
193
203
|
{
|
|
194
|
-
//
|
|
204
|
+
// gamepad debug display
|
|
195
205
|
const gamepads = navigator.getGamepads();
|
|
196
206
|
for (let i = gamepads.length; i--;)
|
|
197
207
|
{
|
|
198
208
|
const gamepad = gamepads[i];
|
|
199
209
|
if (gamepad)
|
|
200
210
|
{
|
|
201
|
-
// gamepad debug display
|
|
202
211
|
const stickScale = 1;
|
|
203
212
|
const buttonScale = .2;
|
|
204
213
|
const centerPos = cameraPos;
|
|
205
214
|
const sticks = stickData[i];
|
|
206
215
|
for (let j = sticks.length; j--;)
|
|
207
216
|
{
|
|
208
|
-
const drawPos = centerPos.add(vec2(j*stickScale*2,i*stickScale*3));
|
|
217
|
+
const drawPos = centerPos.add(vec2(j*stickScale*2, i*stickScale*3));
|
|
209
218
|
const stickPos = drawPos.add(sticks[j].scale(stickScale));
|
|
210
219
|
debugCircle(drawPos, stickScale, '#fff7',0,1);
|
|
211
220
|
debugLine(drawPos, stickPos, '#f00');
|
|
@@ -224,38 +233,36 @@ const debugRender = ()=>
|
|
|
224
233
|
|
|
225
234
|
if (debugOverlay)
|
|
226
235
|
{
|
|
236
|
+
// mouse pick
|
|
237
|
+
let bestDistance = Infinity, bestObject;
|
|
227
238
|
for (const o of engineObjects)
|
|
228
239
|
{
|
|
229
|
-
if (o.canvas)
|
|
240
|
+
if (o.canvas || o.destroyed)
|
|
230
241
|
continue; // skip tile layers
|
|
231
242
|
|
|
232
243
|
const size = o.size.copy();
|
|
233
|
-
size.x
|
|
234
|
-
|
|
244
|
+
if (!size.x || !size.y)
|
|
245
|
+
continue;
|
|
235
246
|
|
|
247
|
+
const distance = mousePos.distanceSquared(o.pos);
|
|
248
|
+
if (distance < bestDistance)
|
|
249
|
+
{
|
|
250
|
+
bestDistance = distance;
|
|
251
|
+
bestObject = o
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// show object info
|
|
236
255
|
const color = new Color(
|
|
237
256
|
o.collideTiles?1:0,
|
|
238
257
|
o.collideSolidObjects?1:0,
|
|
239
258
|
o.isSolid?1:0,
|
|
240
259
|
o.parent ? .2 : .5);
|
|
241
|
-
|
|
242
|
-
|
|
260
|
+
size.x = max(size.x, .2);
|
|
261
|
+
size.y = max(size.y, .2);
|
|
243
262
|
drawRect(o.pos, size, color);
|
|
244
263
|
drawRect(o.pos, size.scale(.8), o.parent ? new Color(1,1,1,.5) : new Color(0,0,0,.8));
|
|
245
264
|
o.parent && drawLine(o.pos, o.parent.pos, .1, new Color(0,0,1,.5));
|
|
246
265
|
}
|
|
247
|
-
|
|
248
|
-
// mouse pick
|
|
249
|
-
let bestDistance = Infinity, bestObject;
|
|
250
|
-
for (const o of engineObjects)
|
|
251
|
-
{
|
|
252
|
-
const distance = mousePos.distanceSquared(o.pos);
|
|
253
|
-
if (distance < bestDistance)
|
|
254
|
-
{
|
|
255
|
-
bestDistance = distance;
|
|
256
|
-
bestObject = o
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
266
|
|
|
260
267
|
if (bestObject)
|
|
261
268
|
{
|
|
@@ -275,7 +282,8 @@ const debugRender = ()=>
|
|
|
275
282
|
pos = pos.add(height), ...args);
|
|
276
283
|
drawText('vel = ' + printVec2(bestObject.velocity), pos = pos.add(height), ...args);
|
|
277
284
|
drawText('size = ' + printVec2(bestObject.size), pos = pos.add(height), ...args);
|
|
278
|
-
drawText('
|
|
285
|
+
drawText('type = ' + ( bestObject.constructor.name), pos = mousePos.subtract(height), ...args);
|
|
286
|
+
drawText('collision = ' + getTileCollisionData(mousePos), pos = mousePos.subtract(height.scale(2)), ...args);
|
|
279
287
|
mainContext = saveContext;
|
|
280
288
|
}
|
|
281
289
|
|
|
@@ -283,16 +291,15 @@ const debugRender = ()=>
|
|
|
283
291
|
}
|
|
284
292
|
|
|
285
293
|
{
|
|
286
|
-
//
|
|
287
|
-
overlayContext.
|
|
294
|
+
// draw debug primitives
|
|
295
|
+
overlayContext.save();
|
|
296
|
+
overlayContext.lineWidth = 2;
|
|
288
297
|
const pointSize = debugPointSize * cameraScale;
|
|
289
298
|
debugPrimitives.forEach(p=>
|
|
290
299
|
{
|
|
291
300
|
// create canvas transform from world space to screen space
|
|
292
301
|
const pos = worldToScreen(p.pos);
|
|
293
302
|
|
|
294
|
-
overlayContext.save();
|
|
295
|
-
overlayContext.lineWidth = 2;
|
|
296
303
|
overlayContext.translate(pos.x|0, pos.y|0);
|
|
297
304
|
overlayContext.rotate(p.angle);
|
|
298
305
|
overlayContext.fillStyle = overlayContext.strokeStyle = p.color;
|
|
@@ -325,15 +332,17 @@ const debugRender = ()=>
|
|
|
325
332
|
p.fill && overlayContext.fill();
|
|
326
333
|
overlayContext.stroke();
|
|
327
334
|
}
|
|
328
|
-
|
|
329
|
-
overlayContext.restore();
|
|
330
335
|
});
|
|
331
336
|
|
|
332
|
-
|
|
337
|
+
// remove expired pritives
|
|
338
|
+
debugPrimitives = debugPrimitives.filter(r=>r.time.get()<0);
|
|
339
|
+
|
|
340
|
+
overlayContext.restore();
|
|
333
341
|
}
|
|
334
342
|
|
|
335
343
|
{
|
|
336
|
-
|
|
344
|
+
// draw debug overlay
|
|
345
|
+
overlayContext.save();
|
|
337
346
|
overlayContext.fillStyle = '#fff';
|
|
338
347
|
overlayContext.textAlign = 'left';
|
|
339
348
|
overlayContext.textBaseline = 'top';
|
|
@@ -341,6 +350,7 @@ const debugRender = ()=>
|
|
|
341
350
|
overlayContext.shadowColor = '#000';
|
|
342
351
|
overlayContext.shadowBlur = 9;
|
|
343
352
|
|
|
353
|
+
let x = 9, y = -20, h = 30;
|
|
344
354
|
if (debugOverlay)
|
|
345
355
|
{
|
|
346
356
|
overlayContext.fillText(engineName, x, y += h);
|
|
@@ -353,214 +363,38 @@ const debugRender = ()=>
|
|
|
353
363
|
overlayContext.fillText('1: Debug Physics', x, y += h);
|
|
354
364
|
overlayContext.fillStyle = debugParticles ? '#f00' : '#fff';
|
|
355
365
|
overlayContext.fillText('2: Debug Particles', x, y += h);
|
|
366
|
+
overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
|
|
367
|
+
overlayContext.fillText('3: Debug Gamepads', x, y += h);
|
|
356
368
|
overlayContext.fillStyle = godMode ? '#f00' : '#fff';
|
|
357
|
-
overlayContext.fillText('
|
|
369
|
+
overlayContext.fillText('4: God Mode', x, y += h);
|
|
358
370
|
overlayContext.fillStyle = '#fff';
|
|
359
371
|
overlayContext.fillText('5: Save Screenshot', x, y += h);
|
|
360
|
-
//overlayContext.fillStyle = debugParticleEditor ? '#f00' : '#fff';
|
|
361
|
-
//overlayContext.fillText('6: Particle Editor', x, y += h);
|
|
362
|
-
overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
|
|
363
|
-
overlayContext.fillText('7: Debug Gamepads', x, y += h);
|
|
364
|
-
}
|
|
365
|
-
else
|
|
366
|
-
{
|
|
367
|
-
overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
|
|
368
|
-
overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
|
|
369
|
-
overlayContext.fillText(godMode ? 'God Mode' : '', x, y += h);
|
|
370
|
-
overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
overlayContext.shadowBlur = 0;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
debugPrimitives = debugPrimitives.filter(r=>r.time.get()<0);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
380
|
-
// particle system editor (work in progress)
|
|
381
|
-
let debugParticleEditor = 0, debugParticleSystem, debugParticleSystemDiv, particleSystemCode;
|
|
382
|
-
|
|
383
|
-
const debugToggleParticleEditor = ()=>
|
|
384
|
-
{
|
|
385
|
-
debugParticleEditor = !debugParticleEditor;
|
|
386
372
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (!debugParticleSystem || debugParticleSystem.destroyed)
|
|
390
|
-
debugParticleSystem = new ParticleEmitter(cameraPos);
|
|
391
|
-
}
|
|
392
|
-
else if (debugParticleSystem && !debugParticleSystem.destroyed)
|
|
393
|
-
debugParticleSystem.destroy();
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const colorToHex = (color)=>
|
|
397
|
-
{
|
|
398
|
-
const componentToHex = (c)=>
|
|
399
|
-
{
|
|
400
|
-
const hex = (c*255|0).toString(16);
|
|
401
|
-
return hex.length == 1 ? '0' + hex : hex;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return '#' + componentToHex(color.r) + componentToHex(color.g) + componentToHex(color.b);
|
|
405
|
-
}
|
|
406
|
-
const hexToColor = (hex)=>
|
|
407
|
-
{
|
|
408
|
-
return new Color(
|
|
409
|
-
parseInt(hex.substr(1,2), 16)/255,
|
|
410
|
-
parseInt(hex.substr(3,2), 16)/255,
|
|
411
|
-
parseInt(hex.substr(5,2), 16)/255)
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (!debugParticleSystemDiv)
|
|
415
|
-
{
|
|
416
|
-
const div = debugParticleSystemDiv = document.createElement('div');
|
|
417
|
-
div.innerHTML = '<big><b>Particle Editor';
|
|
418
|
-
div.style = 'position:absolute;top:10;left:10;color:#fff';
|
|
419
|
-
document.body.appendChild(div);
|
|
420
|
-
|
|
421
|
-
for ( const setting of debugParticleSettings)
|
|
422
|
-
{
|
|
423
|
-
const input = setting[2] = document.createElement('input');
|
|
424
|
-
const name = setting[0];
|
|
425
|
-
const type = setting[1];
|
|
426
|
-
if (type)
|
|
373
|
+
let keysPressed = '';
|
|
374
|
+
for(const i in inputData[0])
|
|
427
375
|
{
|
|
428
|
-
if (
|
|
429
|
-
|
|
430
|
-
input.type = type;
|
|
431
|
-
const color = debugParticleSystem[name];
|
|
432
|
-
input.value = colorToHex(color);
|
|
433
|
-
}
|
|
434
|
-
else if (type == 'alpha' && name == 'colorStartAlpha')
|
|
435
|
-
input.value = debugParticleSystem.colorStartA.a;
|
|
436
|
-
else if (type == 'alpha' && name == 'colorEndAlpha')
|
|
437
|
-
input.value = debugParticleSystem.colorEndA.a;
|
|
438
|
-
else if (name == 'tileSizeX')
|
|
439
|
-
input.value = debugParticleSystem.tileSize.x;
|
|
440
|
-
else if (name == 'tileSizeY')
|
|
441
|
-
input.value = debugParticleSystem.tileSize.y;
|
|
376
|
+
if (i && keyIsDown(i, 0))
|
|
377
|
+
keysPressed += i + ' ' ;
|
|
442
378
|
}
|
|
443
|
-
|
|
444
|
-
input.value = debugParticleSystem[name] || '0';
|
|
379
|
+
keysPressed && overlayContext.fillText('Keys Down: ' + keysPressed, x, y += h);
|
|
445
380
|
|
|
446
|
-
|
|
381
|
+
let buttonsPressed = '';
|
|
382
|
+
if (inputData[1])
|
|
383
|
+
for(const i in inputData[1])
|
|
447
384
|
{
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
{
|
|
451
|
-
if (type == 'color')
|
|
452
|
-
{
|
|
453
|
-
const color = hexToColor(input.value);
|
|
454
|
-
debugParticleSystem[name].r = color.r;
|
|
455
|
-
debugParticleSystem[name].g = color.g;
|
|
456
|
-
debugParticleSystem[name].b = color.b;
|
|
457
|
-
}
|
|
458
|
-
else if (type == 'alpha' && name == 'colorStartAlpha')
|
|
459
|
-
{
|
|
460
|
-
debugParticleSystem.colorStartA.a = clamp(inputFloat);
|
|
461
|
-
debugParticleSystem.colorStartB.a = clamp(inputFloat);
|
|
462
|
-
}
|
|
463
|
-
else if (type == 'alpha' && name == 'colorEndAlpha')
|
|
464
|
-
{
|
|
465
|
-
debugParticleSystem.colorEndA.a = clamp(inputFloat);
|
|
466
|
-
debugParticleSystem.colorEndB.a = clamp(inputFloat);
|
|
467
|
-
}
|
|
468
|
-
else if (name == 'tileSizeX')
|
|
469
|
-
{
|
|
470
|
-
debugParticleSystem.tileSize = vec2(parseInt(input.value), debugParticleSystem.tileSize.y);
|
|
471
|
-
}
|
|
472
|
-
else if (name == 'tileSizeY')
|
|
473
|
-
{
|
|
474
|
-
debugParticleSystem.tileSize.y = vec2(debugParticleSystem.tileSize.x, parseInt(input.value));
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
else
|
|
478
|
-
debugParticleSystem[name] = inputFloat;
|
|
479
|
-
|
|
480
|
-
updateCode();
|
|
385
|
+
if (i && keyIsDown(i, 1))
|
|
386
|
+
buttonsPressed += i + ' ' ;
|
|
481
387
|
}
|
|
482
|
-
|
|
483
|
-
div.appendChild(input);
|
|
484
|
-
div.appendChild(document.createTextNode(' ' + name));
|
|
388
|
+
buttonsPressed && overlayContext.fillText('Gamepad: ' + buttonsPressed, x, y += h);
|
|
485
389
|
}
|
|
486
|
-
|
|
487
|
-
div.appendChild(document.createElement('br'));
|
|
488
|
-
div.appendChild(document.createElement('br'));
|
|
489
|
-
div.appendChild(particleSystemCode = document.createElement('input'));
|
|
490
|
-
particleSystemCode.disabled = true;
|
|
491
|
-
div.appendChild(document.createTextNode(' code'));
|
|
492
|
-
|
|
493
|
-
div.appendChild(document.createElement('br'));
|
|
494
|
-
const button = document.createElement('button')
|
|
495
|
-
div.appendChild(button);
|
|
496
|
-
button.innerHTML = 'Copy To Clipboard';
|
|
497
|
-
|
|
498
|
-
button.onclick = (e)=> navigator.clipboard.writeText(particleSystemCode.value);
|
|
499
|
-
|
|
500
|
-
const updateCode = ()=>
|
|
390
|
+
else
|
|
501
391
|
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
const name = setting[0];
|
|
507
|
-
const type = setting[1];
|
|
508
|
-
let value;
|
|
509
|
-
if (name == 'tileSizeX' || type == 'alpha')
|
|
510
|
-
continue;
|
|
511
|
-
|
|
512
|
-
if (count++)
|
|
513
|
-
code += ', ';
|
|
514
|
-
|
|
515
|
-
if (name == 'tileSizeY')
|
|
516
|
-
{
|
|
517
|
-
value = `vec2(${debugParticleSystem.tileSize.x},${debugParticleSystem.tileSize.y})`;
|
|
518
|
-
}
|
|
519
|
-
else if (type == 'color')
|
|
520
|
-
{
|
|
521
|
-
const c = debugParticleSystem[name];
|
|
522
|
-
value = `new Color(${c.r},${c.g},${c.b},${c.a})`;
|
|
523
|
-
}
|
|
524
|
-
else
|
|
525
|
-
value = debugParticleSystem[name];
|
|
526
|
-
code += value;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
particleSystemCode.value = '...[' + code + ']';
|
|
392
|
+
overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
|
|
393
|
+
overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
|
|
394
|
+
overlayContext.fillText(godMode ? 'God Mode' : '', x, y += h);
|
|
395
|
+
overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
|
|
530
396
|
}
|
|
531
|
-
|
|
397
|
+
|
|
398
|
+
overlayContext.restore();
|
|
532
399
|
}
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const debugParticleSettings =
|
|
537
|
-
[
|
|
538
|
-
['emitSize'],
|
|
539
|
-
['emitTime'],
|
|
540
|
-
['emitRate'],
|
|
541
|
-
['emitConeAngle'],
|
|
542
|
-
['tileIndex'],
|
|
543
|
-
['tileSizeX', 'tileSize'],
|
|
544
|
-
['tileSizeY', 'tileSize'],
|
|
545
|
-
['colorStartA', 'color'],
|
|
546
|
-
['colorStartB', 'color'],
|
|
547
|
-
['colorStartAlpha', 'alpha'],
|
|
548
|
-
['colorEndA', 'color'],
|
|
549
|
-
['colorEndB', 'color'],
|
|
550
|
-
['colorEndAlpha', 'alpha'],
|
|
551
|
-
['particleTime'],
|
|
552
|
-
['sizeStart'],
|
|
553
|
-
['sizeEnd'],
|
|
554
|
-
['speed'],
|
|
555
|
-
['angleSpeed'],
|
|
556
|
-
['damping'],
|
|
557
|
-
['angleDamping'],
|
|
558
|
-
['gravityScale'],
|
|
559
|
-
['particleConeAngle'],
|
|
560
|
-
['fadeRate'],
|
|
561
|
-
['randomness'],
|
|
562
|
-
['collideTiles'],
|
|
563
|
-
['additive'],
|
|
564
|
-
['randomColorComponents'],
|
|
565
|
-
['renderOrder'],
|
|
566
|
-
];
|
|
400
|
+
}
|