littlejsengine 1.1.17 → 1.2.0
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 +13 -3
- package/build.bat +1 -0
- package/engine/engine.all.js +520 -522
- package/engine/engine.all.min.js +1 -1
- package/engine/engine.all.release.js +444 -278
- package/engine/engine.js +68 -33
- package/engine/engineAudio.js +21 -7
- package/engine/engineBuild.bat +9 -1
- package/engine/engineBuildSetup.bat +2 -1
- package/engine/engineDebug.js +80 -246
- package/engine/engineDraw.js +106 -21
- package/engine/engineInput.js +89 -52
- package/engine/engineMedals.js +14 -17
- package/engine/engineObject.js +14 -23
- package/engine/engineParticles.js +3 -3
- package/engine/engineRelease.js +3 -1
- package/engine/engineSettings.js +39 -29
- package/engine/engineTileLayer.js +26 -24
- package/engine/engineUtilities.js +14 -12
- package/engine/engineWebGL.js +47 -56
- package/engine/index.d.ts +1612 -0
- package/examples/breakout/game.js +9 -7
- package/examples/breakout/gameObjects.js +1 -1
- package/examples/breakout/index.html +6 -4
- package/examples/platformer/game.js +2 -2
- package/examples/platformer/gameEffects.js +8 -11
- package/examples/platformer/gameLevel.js +14 -7
- package/examples/platformer/gameObjects.js +1 -1
- 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 +1 -1
- package/examples/puzzle/index.html +5 -3
- package/examples/stress/index.html +6 -4
- package/game.js +5 -4
- package/index.html +16 -14
- package/package.json +1 -1
package/engine/engineInput.js
CHANGED
|
@@ -32,7 +32,7 @@ const keyWasReleased = (key, device=0)=> inputData[device] && inputData[device][
|
|
|
32
32
|
|
|
33
33
|
/** Clears all input
|
|
34
34
|
* @memberof Input */
|
|
35
|
-
const clearInput = ()=> inputData
|
|
35
|
+
const clearInput = ()=> inputData = [[]];
|
|
36
36
|
|
|
37
37
|
/** Returns true if mouse button is down
|
|
38
38
|
* @param {Number} button
|
|
@@ -101,7 +101,9 @@ const gamepadStick = (stick, gamepad=0)=> stickData[gamepad] ? stickData[gamepa
|
|
|
101
101
|
///////////////////////////////////////////////////////////////////////////////
|
|
102
102
|
// Input update called by engine
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
// store input as a bit field for each key: 1 = isDown, 2 = wasPressed, 4 = wasReleased
|
|
105
|
+
// mouse and keyboard are stored together in device 0, gamepads are in devices > 0
|
|
106
|
+
let inputData = [[]];
|
|
105
107
|
|
|
106
108
|
function inputUpdate()
|
|
107
109
|
{
|
|
@@ -127,36 +129,38 @@ function inputUpdatePost()
|
|
|
127
129
|
///////////////////////////////////////////////////////////////////////////////
|
|
128
130
|
// Keyboard event handlers
|
|
129
131
|
|
|
130
|
-
onkeydown = e=>
|
|
132
|
+
onkeydown = (e)=>
|
|
131
133
|
{
|
|
132
134
|
if (debug && e.target != document.body) return;
|
|
133
135
|
e.repeat || (inputData[isUsingGamepad = 0][remapKeyCode(e.keyCode)] = 3);
|
|
134
136
|
debug || e.preventDefault();
|
|
135
137
|
}
|
|
136
|
-
onkeyup = e=>
|
|
138
|
+
onkeyup = (e)=>
|
|
137
139
|
{
|
|
138
140
|
if (debug && e.target != document.body) return;
|
|
139
141
|
inputData[0][remapKeyCode(e.keyCode)] = 4;
|
|
140
142
|
}
|
|
141
|
-
const remapKeyCode = c=> inputWASDEmulateDirection ? c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
|
|
143
|
+
const remapKeyCode = (c)=> inputWASDEmulateDirection ? c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
|
|
142
144
|
|
|
143
145
|
///////////////////////////////////////////////////////////////////////////////
|
|
144
146
|
// Mouse event handlers
|
|
145
147
|
|
|
146
|
-
onmousedown = e=> {inputData[isUsingGamepad = 0][e.button] = 3; onmousemove(e); e.button && e.preventDefault();}
|
|
147
|
-
onmouseup = e=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
|
|
148
|
-
onmousemove = e=>
|
|
148
|
+
onmousedown = (e)=> {inputData[isUsingGamepad = 0][e.button] = 3; onmousemove(e); e.button && e.preventDefault();}
|
|
149
|
+
onmouseup = (e)=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
|
|
150
|
+
onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
|
|
151
|
+
onwheel = (e)=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
|
|
152
|
+
oncontextmenu = (e)=> !1; // prevent right click menu
|
|
153
|
+
|
|
154
|
+
// convert a mouse or touch event position to screen space
|
|
155
|
+
const mouseToScreen = (mousePos)=>
|
|
149
156
|
{
|
|
150
157
|
if (!mainCanvas)
|
|
151
|
-
return; // fix bug that can occur if user clicks before page loads
|
|
158
|
+
return vec2(); // fix bug that can occur if user clicks before page loads
|
|
152
159
|
|
|
153
|
-
// convert mouse pos to canvas space
|
|
154
160
|
const rect = mainCanvas.getBoundingClientRect();
|
|
155
|
-
|
|
156
|
-
vec2(percent(
|
|
161
|
+
return mainCanvasSize.multiply(
|
|
162
|
+
vec2(percent(mousePos.x, rect.left, rect.right), percent(mousePos.y, rect.top, rect.bottom)));
|
|
157
163
|
}
|
|
158
|
-
onwheel = e=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
|
|
159
|
-
oncontextmenu = e=> !1; // prevent right click menu
|
|
160
164
|
|
|
161
165
|
///////////////////////////////////////////////////////////////////////////////
|
|
162
166
|
// Gamepad input
|
|
@@ -164,6 +168,21 @@ oncontextmenu = e=> !1; // prevent right click menu
|
|
|
164
168
|
const stickData = [];
|
|
165
169
|
function gamepadsUpdate()
|
|
166
170
|
{
|
|
171
|
+
if (touchGamepadEnable && touchGamepadTimer.isSet())
|
|
172
|
+
{
|
|
173
|
+
// read virtual analog stick
|
|
174
|
+
const sticks = stickData[0] || (stickData[0] = []);
|
|
175
|
+
sticks[0] = vec2(touchGamepadStick.x, -touchGamepadStick.y); // flip vertical
|
|
176
|
+
|
|
177
|
+
// read virtual gamepad buttons
|
|
178
|
+
const data = inputData[1] || (inputData[1] = []);
|
|
179
|
+
for (let i=10; i--;)
|
|
180
|
+
{
|
|
181
|
+
const j = i == 3 ? 2 : i == 2 ? 3 : i; // fix button locations
|
|
182
|
+
data[j] = touchGamepadButtons[i] ? 1 + 2*!gamepadIsDown(j,0) : 4*gamepadIsDown(j,0);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
167
186
|
if (!gamepadsEnable || !navigator.getGamepads || !document.hasFocus() && !debug)
|
|
168
187
|
return;
|
|
169
188
|
|
|
@@ -181,8 +200,8 @@ function gamepadsUpdate()
|
|
|
181
200
|
// read clamp dead zone of analog sticks
|
|
182
201
|
const deadZone = .3, deadZoneMax = .8;
|
|
183
202
|
const applyDeadZone = (v)=>
|
|
184
|
-
v > deadZone ? percent( v,
|
|
185
|
-
v < -deadZone ? -percent(-v,
|
|
203
|
+
v > deadZone ? percent( v, deadZone, deadZoneMax) :
|
|
204
|
+
v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
|
|
186
205
|
|
|
187
206
|
// read analog sticks
|
|
188
207
|
for (let j = 0; j < gamepad.axes.length-1; j+=2)
|
|
@@ -194,6 +213,7 @@ function gamepadsUpdate()
|
|
|
194
213
|
const button = gamepad.buttons[j];
|
|
195
214
|
data[j] = button.pressed ? 1 + 2*!gamepadIsDown(j,i) : 4*gamepadIsDown(j,i);
|
|
196
215
|
isUsingGamepad |= !i && button.pressed;
|
|
216
|
+
touchGamepadEnable && touchGamepadTimer.unset(); // disable touch gamepad if using real gamepad
|
|
197
217
|
}
|
|
198
218
|
|
|
199
219
|
if (gamepadDirectionEmulateStick)
|
|
@@ -207,6 +227,17 @@ function gamepadsUpdate()
|
|
|
207
227
|
}
|
|
208
228
|
}
|
|
209
229
|
|
|
230
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
231
|
+
|
|
232
|
+
/** Pulse the vibration hardware if it exists
|
|
233
|
+
* @param {Number} [pattern=100] - a single value in miliseconds or vibration interval array
|
|
234
|
+
* @memberof Input */
|
|
235
|
+
const vibrate = (pattern)=> vibrateEnable && Navigator.vibrate && Navigator.vibrate(pattern);
|
|
236
|
+
|
|
237
|
+
/** Cancel any ongoing vibration
|
|
238
|
+
* @memberof Input */
|
|
239
|
+
const vibrateStop = ()=> vibrate(0);
|
|
240
|
+
|
|
210
241
|
///////////////////////////////////////////////////////////////////////////////
|
|
211
242
|
// Touch input
|
|
212
243
|
|
|
@@ -214,7 +245,9 @@ function gamepadsUpdate()
|
|
|
214
245
|
* @const {boolean}
|
|
215
246
|
* @memberof Input */
|
|
216
247
|
const isTouchDevice = window.ontouchstart !== undefined;
|
|
217
|
-
|
|
248
|
+
|
|
249
|
+
// try to enable touch mouse
|
|
250
|
+
if (isTouchDevice)
|
|
218
251
|
{
|
|
219
252
|
// handle all touch events the same way
|
|
220
253
|
let wasTouching, hadTouchInput;
|
|
@@ -245,19 +278,25 @@ if (touchMouseEnable && isTouchDevice)
|
|
|
245
278
|
}
|
|
246
279
|
|
|
247
280
|
///////////////////////////////////////////////////////////////////////////////
|
|
248
|
-
//
|
|
281
|
+
// touch gamepad, virtual on screen gamepad emulator for touch devices
|
|
282
|
+
|
|
283
|
+
// touch input internal variables
|
|
284
|
+
let touchGamepadTimer = new Timer, touchGamepadButtons = [], touchGamepadStick = vec2(), touchGamepadAnalog = 1;
|
|
249
285
|
|
|
250
|
-
// create the touch gamepad, called automatically by the engine
|
|
251
|
-
const touchGamepadTimer = new Timer;
|
|
286
|
+
// create the touch gamepad, called automatically by the engine
|
|
252
287
|
function touchGamepadCreate()
|
|
253
288
|
{
|
|
254
|
-
if (!
|
|
289
|
+
if (!touchGamepadEnable || !isTouchDevice)
|
|
255
290
|
return;
|
|
256
291
|
|
|
257
292
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
258
293
|
{
|
|
259
|
-
if (!
|
|
294
|
+
if (!touchGamepadEnable)
|
|
260
295
|
return;
|
|
296
|
+
|
|
297
|
+
// clear touch gamepad input
|
|
298
|
+
touchGamepadStick = vec2();
|
|
299
|
+
touchGamepadButtons = [];
|
|
261
300
|
|
|
262
301
|
const touching = e.touches.length;
|
|
263
302
|
if (touching)
|
|
@@ -267,6 +306,13 @@ function touchGamepadCreate()
|
|
|
267
306
|
// set that gamepad is active
|
|
268
307
|
isUsingGamepad = 1;
|
|
269
308
|
touchGamepadTimer.set();
|
|
309
|
+
|
|
310
|
+
if (paused)
|
|
311
|
+
{
|
|
312
|
+
// touch anywhere to press start when paused
|
|
313
|
+
touchGamepadButtons[9] = 1;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
270
316
|
}
|
|
271
317
|
|
|
272
318
|
// get center of left and right sides
|
|
@@ -274,68 +320,58 @@ function touchGamepadCreate()
|
|
|
274
320
|
const buttonCenter = mainCanvasSize.subtract(vec2(touchGamepadSize, touchGamepadSize));
|
|
275
321
|
const startCenter = mainCanvasSize.scale(.5);
|
|
276
322
|
|
|
277
|
-
// update virtual gamepad
|
|
278
|
-
const data = inputData[1] || (inputData[1] = []);
|
|
279
|
-
const sticks = stickData[0] || (stickData[0] = []);
|
|
280
|
-
sticks[0] = vec2();
|
|
281
|
-
|
|
282
323
|
// check each touch point
|
|
283
|
-
const buttons = [];
|
|
284
324
|
for (const touch of e.touches)
|
|
285
325
|
{
|
|
286
|
-
const touchPos = vec2(touch.clientX, touch.clientY);
|
|
326
|
+
const touchPos = mouseToScreen(vec2(touch.clientX, touch.clientY));
|
|
287
327
|
if (touchPos.distance(stickCenter) < touchGamepadSize)
|
|
288
328
|
{
|
|
289
329
|
// virtual analog stick
|
|
290
|
-
|
|
291
|
-
|
|
330
|
+
if (touchGamepadAnalog)
|
|
331
|
+
touchGamepadStick = touchPos.subtract(stickCenter).clampLength(touchGamepadSize/2).scale(2/touchGamepadSize);
|
|
332
|
+
else
|
|
333
|
+
{
|
|
334
|
+
// 8 way dpad
|
|
335
|
+
const angle = touchPos.subtract(stickCenter).angle();
|
|
336
|
+
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
337
|
+
}
|
|
292
338
|
}
|
|
293
339
|
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
294
340
|
{
|
|
295
341
|
// virtual face buttons
|
|
296
342
|
const button = touchPos.subtract(buttonCenter).direction();
|
|
297
|
-
|
|
343
|
+
touchGamepadButtons[button] = 1;
|
|
298
344
|
}
|
|
299
345
|
else if (touchPos.distance(startCenter) < touchGamepadSize)
|
|
300
346
|
{
|
|
301
|
-
// virtual start button
|
|
302
|
-
|
|
347
|
+
// virtual start button in center
|
|
348
|
+
touchGamepadButtons[9] = 1;
|
|
303
349
|
}
|
|
304
350
|
}
|
|
305
|
-
|
|
306
|
-
// read virtual buttons
|
|
307
|
-
for (let j=10; j--;)
|
|
308
|
-
data[j] = buttons[j] ? 1 + 2*!gamepadIsDown(j,0) : 4*gamepadIsDown(j,0);
|
|
309
351
|
}
|
|
310
352
|
}
|
|
311
353
|
|
|
312
354
|
// render the touch gamepad, called automatically by the engine
|
|
313
355
|
function touchGamepadRender()
|
|
314
356
|
{
|
|
315
|
-
if (!
|
|
357
|
+
if (!touchGamepadEnable || !touchGamepadTimer.isSet())
|
|
316
358
|
return;
|
|
317
359
|
|
|
318
|
-
// fade off when not touching
|
|
319
|
-
const alpha = percent(touchGamepadTimer.get(), 4,
|
|
320
|
-
if (!alpha)
|
|
360
|
+
// fade off when not touching or paused
|
|
361
|
+
const alpha = percent(touchGamepadTimer.get(), 4, 3);
|
|
362
|
+
if (!alpha || paused)
|
|
321
363
|
return;
|
|
322
364
|
|
|
323
365
|
// setup the canvas
|
|
324
366
|
overlayContext.save();
|
|
325
367
|
overlayContext.globalAlpha = alpha*touchGamepadAlpha;
|
|
326
|
-
overlayContext.fillStyle = '#fff6';
|
|
327
368
|
overlayContext.strokeStyle = '#fff';
|
|
328
369
|
overlayContext.lineWidth = 3;
|
|
329
370
|
|
|
330
|
-
// draw start button
|
|
331
|
-
//overlayContext.beginPath();
|
|
332
|
-
//overlayContext.arc(mainCanvasSize.x/2, mainCanvasSize.y/2, touchGamepadSize*.9, 0,9);
|
|
333
|
-
//overlayContext.fill();
|
|
334
|
-
//overlayContext.stroke();
|
|
335
|
-
|
|
336
371
|
// draw left analog stick
|
|
372
|
+
overlayContext.fillStyle = gamepadStick(0).length() > 0 ? '#fff' : '#000';
|
|
337
373
|
overlayContext.beginPath();
|
|
338
|
-
overlayContext.arc(touchGamepadSize, mainCanvasSize.y-touchGamepadSize, touchGamepadSize
|
|
374
|
+
overlayContext.arc(touchGamepadSize, mainCanvasSize.y-touchGamepadSize, touchGamepadSize/2, 0,9);
|
|
339
375
|
overlayContext.fill();
|
|
340
376
|
overlayContext.stroke();
|
|
341
377
|
|
|
@@ -343,9 +379,10 @@ function touchGamepadRender()
|
|
|
343
379
|
const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
344
380
|
for (let i=4; i--;)
|
|
345
381
|
{
|
|
346
|
-
const pos = rightCenter.add((new Vector2).setAngle(i*PI/2, touchGamepadSize
|
|
382
|
+
const pos = rightCenter.add((new Vector2).setAngle(i*PI/2, touchGamepadSize/2));
|
|
383
|
+
overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
|
|
347
384
|
overlayContext.beginPath();
|
|
348
|
-
overlayContext.arc(pos.x, pos.y, touchGamepadSize
|
|
385
|
+
overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
|
|
349
386
|
overlayContext.fill();
|
|
350
387
|
overlayContext.stroke();
|
|
351
388
|
}
|
package/engine/engineMedals.js
CHANGED
|
@@ -35,7 +35,7 @@ function medalsInit(saveName)
|
|
|
35
35
|
{
|
|
36
36
|
// check if medals are unlocked
|
|
37
37
|
medalsSaveName = saveName;
|
|
38
|
-
debugMedals || medals.forEach(medal=> medal.unlocked = localStorage[medal.storageKey()]);
|
|
38
|
+
debugMedals || medals.forEach(medal=> medal.unlocked = 1 || localStorage[medal.storageKey()]);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
@@ -68,13 +68,9 @@ class Medal
|
|
|
68
68
|
this.name = name;
|
|
69
69
|
this.description = description;
|
|
70
70
|
this.icon = icon;
|
|
71
|
-
|
|
71
|
+
this.image = new Image();
|
|
72
72
|
if (src)
|
|
73
|
-
{
|
|
74
|
-
// load image
|
|
75
|
-
this.image = new Image();
|
|
76
73
|
this.image.src = src;
|
|
77
|
-
}
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
/** Unlocks a medal if not already unlocked */
|
|
@@ -104,21 +100,23 @@ class Medal
|
|
|
104
100
|
const y = -medalDisplayHeight*hidePercent;
|
|
105
101
|
|
|
106
102
|
// draw containing rect and clip to that region
|
|
107
|
-
context.
|
|
103
|
+
context.save();
|
|
104
|
+
context.beginPath();
|
|
108
105
|
context.fillStyle = '#ddd'
|
|
109
106
|
context.fill(context.rect(x, y, width, medalDisplayHeight));
|
|
110
|
-
context.strokeStyle =
|
|
111
|
-
context.lineWidth =
|
|
107
|
+
context.strokeStyle = '#000';
|
|
108
|
+
context.lineWidth = 3;
|
|
112
109
|
context.stroke();
|
|
113
110
|
context.clip();
|
|
114
111
|
|
|
115
112
|
// draw the icon and text
|
|
116
113
|
this.renderIcon(x+15+medalDisplayIconSize/2, y+medalDisplayHeight/2);
|
|
117
114
|
context.textAlign = 'left';
|
|
118
|
-
context.font = '
|
|
119
|
-
context.fillText(this.name, x+medalDisplayIconSize+
|
|
120
|
-
context.font = '
|
|
121
|
-
context.
|
|
115
|
+
context.font = '38px '+ fontDefault;
|
|
116
|
+
context.fillText(this.name, x+medalDisplayIconSize+30, y+28);
|
|
117
|
+
context.font = '24px '+ fontDefault;
|
|
118
|
+
context.fillText(this.description, x+medalDisplayIconSize+30, y+60);
|
|
119
|
+
context.restore();
|
|
122
120
|
}
|
|
123
121
|
|
|
124
122
|
/** Render the icon for a medal
|
|
@@ -130,11 +128,11 @@ class Medal
|
|
|
130
128
|
{
|
|
131
129
|
// draw the image or icon
|
|
132
130
|
const context = overlayContext;
|
|
131
|
+
context.fillStyle = '#000';
|
|
133
132
|
context.textAlign = 'center';
|
|
134
133
|
context.textBaseline = 'middle';
|
|
135
|
-
context.font = size*.
|
|
136
|
-
|
|
137
|
-
if (this.image)
|
|
134
|
+
context.font = size*.7 + 'px '+ fontDefault;
|
|
135
|
+
if (this.image.src)
|
|
138
136
|
context.drawImage(this.image, x-size/2, y-size/2, size, size);
|
|
139
137
|
else
|
|
140
138
|
context.fillText(this.icon, x, y); // show icon if there is no image
|
|
@@ -210,7 +208,6 @@ class Newgrounds
|
|
|
210
208
|
if (medal)
|
|
211
209
|
{
|
|
212
210
|
// copy newgrounds medal data
|
|
213
|
-
medal.image = new Image();
|
|
214
211
|
medal.image.src = newgroundsMedal['icon'];
|
|
215
212
|
medal.name = newgroundsMedal['name'];
|
|
216
213
|
medal.description = newgroundsMedal['description'];
|
package/engine/engineObject.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
class EngineObject
|
|
33
33
|
{
|
|
34
34
|
/** Create an engine object and adds it to the list of objects
|
|
35
|
-
* @param {Vector2} [position=new Vector2(
|
|
35
|
+
* @param {Vector2} [position=new Vector2()] - World space position of the object
|
|
36
36
|
* @param {Vector2} [size=objectDefaultSize] - World space size of the object
|
|
37
37
|
* @param {Number} [tileIndex=-1] - Tile to use to render object, untextured if -1
|
|
38
38
|
* @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
|
|
@@ -77,12 +77,15 @@ class EngineObject
|
|
|
77
77
|
this.gravityScale = 1;
|
|
78
78
|
/** @property {Number} [renderOrder=0] - Objects are sorted by render order */
|
|
79
79
|
this.renderOrder = renderOrder;
|
|
80
|
+
/** @property {Vector2} [velocity=new Vector2()] - Velocity of the object */
|
|
81
|
+
this.velocity = new Vector2();
|
|
82
|
+
/** @property {Number} [angleVelocity=0] - Angular velocity of the object */
|
|
83
|
+
this.angleVelocity = 0;
|
|
80
84
|
|
|
81
85
|
// init other internal object stuff
|
|
82
86
|
this.spawnTime = time;
|
|
83
|
-
this.velocity = vec2(this.collideSolidObjects = this.angleVelocity = 0);
|
|
84
|
-
this.collideTiles = 1;
|
|
85
87
|
this.children = [];
|
|
88
|
+
this.collideTiles = 1;
|
|
86
89
|
|
|
87
90
|
// add to list of objects
|
|
88
91
|
engineObjects.push(this);
|
|
@@ -101,8 +104,8 @@ class EngineObject
|
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
// limit max speed to prevent missing collisions
|
|
104
|
-
this.velocity.x = clamp(this.velocity.x, objectMaxSpeed,
|
|
105
|
-
this.velocity.y = clamp(this.velocity.y, objectMaxSpeed,
|
|
107
|
+
this.velocity.x = clamp(this.velocity.x, -objectMaxSpeed, objectMaxSpeed);
|
|
108
|
+
this.velocity.y = clamp(this.velocity.y, -objectMaxSpeed, objectMaxSpeed);
|
|
106
109
|
|
|
107
110
|
// apply physics
|
|
108
111
|
const oldPos = this.pos.copy();
|
|
@@ -150,7 +153,7 @@ class EngineObject
|
|
|
150
153
|
// if already was touching, try to push away
|
|
151
154
|
const deltaPos = oldPos.subtract(o.pos);
|
|
152
155
|
const length = deltaPos.length();
|
|
153
|
-
const pushAwayAccel = .001; // push away if
|
|
156
|
+
const pushAwayAccel = .001; // push away if already overlapping
|
|
154
157
|
const velocity = length < .01 ? randVector(pushAwayAccel) : deltaPos.scale(pushAwayAccel/length);
|
|
155
158
|
this.velocity = this.velocity.add(velocity);
|
|
156
159
|
if (o.mass) // push away if not fixed
|
|
@@ -192,8 +195,8 @@ class EngineObject
|
|
|
192
195
|
|
|
193
196
|
// lerp betwen elastic or inelastic based on elasticity
|
|
194
197
|
const elasticity = max(this.elasticity, o.elasticity);
|
|
195
|
-
this.velocity.y = lerp(elasticity,
|
|
196
|
-
o.velocity.y = lerp(elasticity,
|
|
198
|
+
this.velocity.y = lerp(elasticity, inelastic, elastic0);
|
|
199
|
+
o.velocity.y = lerp(elasticity, inelastic, elastic1);
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
if (!smallStepUp && (isBlockedX || !isBlockedY)) // resolve x collision
|
|
@@ -213,8 +216,8 @@ class EngineObject
|
|
|
213
216
|
|
|
214
217
|
// lerp betwen elastic or inelastic based on elasticity
|
|
215
218
|
const elasticity = max(this.elasticity, o.elasticity);
|
|
216
|
-
this.velocity.x = lerp(elasticity,
|
|
217
|
-
o.velocity.x = lerp(elasticity,
|
|
219
|
+
this.velocity.x = lerp(elasticity, inelastic, elastic0);
|
|
220
|
+
o.velocity.x = lerp(elasticity, inelastic, elastic1);
|
|
218
221
|
}
|
|
219
222
|
else // bounce if other object is fixed
|
|
220
223
|
this.velocity.x *= -this.elasticity;
|
|
@@ -244,7 +247,7 @@ class EngineObject
|
|
|
244
247
|
|
|
245
248
|
// adjust next velocity to settle on ground
|
|
246
249
|
const o = (oldPos.y - this.size.y/2|0) - (oldPos.y - this.size.y/2);
|
|
247
|
-
if (o < 0 && o >
|
|
250
|
+
if (o < 0 && o > this.damping * this.velocity.y + gravity * this.gravityScale)
|
|
248
251
|
this.velocity.y = this.damping ? (o - gravity * this.gravityScale) / this.damping : 0;
|
|
249
252
|
|
|
250
253
|
// move to previous position
|
|
@@ -345,18 +348,6 @@ class EngineObject
|
|
|
345
348
|
{
|
|
346
349
|
ASSERT(collideSolidObjects || !isSolid); // solid objects must be set to collide
|
|
347
350
|
|
|
348
|
-
// track collidable objects in separate list
|
|
349
|
-
if (collideSolidObjects && !this.collideSolidObjects)
|
|
350
|
-
{
|
|
351
|
-
ASSERT(!engineObjectsCollide.includes(this));
|
|
352
|
-
engineObjectsCollide.push(this);
|
|
353
|
-
}
|
|
354
|
-
else if (!collideSolidObjects && this.collideSolidObjects)
|
|
355
|
-
{
|
|
356
|
-
ASSERT(engineObjectsCollide.includes(this))
|
|
357
|
-
engineObjectsCollide.splice(engineObjectsCollide.indexOf(this), 1);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
351
|
this.collideSolidObjects = collideSolidObjects;
|
|
361
352
|
this.isSolid = isSolid;
|
|
362
353
|
this.collideTiles = collideTiles;
|
|
@@ -51,7 +51,7 @@ class ParticleEmitter extends EngineObject
|
|
|
51
51
|
* @param {Number} [randomness=.2] - Apply extra randomness percent
|
|
52
52
|
* @param {Boolean} [collideTiles=0] - Do particles collide against tiles
|
|
53
53
|
* @param {Boolean} [additive=0] - Should particles use addtive blend
|
|
54
|
-
* @param {Boolean} [randomColorLinear=
|
|
54
|
+
* @param {Boolean} [randomColorLinear=1] - Should color be randomized linearly or across each component
|
|
55
55
|
* @param {Number} [renderOrder=0] - Render order for particles (additive is above other stuff by default)
|
|
56
56
|
*/
|
|
57
57
|
constructor
|
|
@@ -152,9 +152,9 @@ class ParticleEmitter extends EngineObject
|
|
|
152
152
|
if (!this.emitTime || this.getAliveTime() <= this.emitTime)
|
|
153
153
|
{
|
|
154
154
|
// emit particles
|
|
155
|
-
if (this.emitRate)
|
|
155
|
+
if (this.emitRate * particleEmitRateScale)
|
|
156
156
|
{
|
|
157
|
-
const rate = 1/this.emitRate;
|
|
157
|
+
const rate = 1/this.emitRate/particleEmitRateScale;
|
|
158
158
|
for (this.emitTimeBuffer += timeDelta; this.emitTimeBuffer > 0; this.emitTimeBuffer -= rate)
|
|
159
159
|
this.emitParticle();
|
|
160
160
|
}
|
package/engine/engineRelease.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
|
-
LittleJS - Release
|
|
2
|
+
LittleJS - Release Build
|
|
3
|
+
MIT License - Copyright 2021 Frank Force
|
|
4
|
+
|
|
3
5
|
- This file is used for release builds in place of engineDebug.js
|
|
4
6
|
- Debug functionality will be disabled to lower size and increase performance
|
|
5
7
|
*/
|