littlejsengine 1.9.3 → 1.9.5
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/LittleJS.zip +0 -0
- package/dist/littlejs.d.ts +24 -21
- package/dist/littlejs.esm.js +179 -91
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +179 -91
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +174 -90
- package/examples/module/game.js +1 -1
- package/examples/platformer/gameCharacter.js +1 -2
- package/examples/platformer/gameEffects.js +2 -3
- package/examples/platformer/gameLevel.js +0 -1
- package/examples/typescript/game.js +1 -1
- package/examples/typescript/game.ts +1 -1
- package/package.json +1 -1
- package/reference.md +11 -11
- package/src/engine.js +67 -34
- package/src/engineAudio.js +1 -1
- package/src/engineBuild.js +4 -4
- package/src/engineDebug.js +5 -1
- package/src/engineDraw.js +11 -16
- package/src/engineInput.js +30 -16
- package/src/engineObject.js +9 -11
- package/src/engineTileLayer.js +6 -3
- package/src/engineUtilities.js +50 -9
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {String}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.9.
|
|
33
|
+
const engineVersion = '1.9.5';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {Number}
|
|
@@ -97,6 +97,19 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
97
97
|
{
|
|
98
98
|
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
99
99
|
|
|
100
|
+
// Called automatically by engine to setup render system
|
|
101
|
+
function enginePreRender()
|
|
102
|
+
{
|
|
103
|
+
// save canvas size
|
|
104
|
+
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
105
|
+
|
|
106
|
+
// disable smoothing for pixel art
|
|
107
|
+
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
108
|
+
|
|
109
|
+
// setup gl rendering if enabled
|
|
110
|
+
glEnable && glPreRender();
|
|
111
|
+
}
|
|
112
|
+
|
|
100
113
|
// internal update loop for engine
|
|
101
114
|
function engineUpdate(frameTimeMS=0)
|
|
102
115
|
{
|
|
@@ -112,7 +125,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
112
125
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
113
126
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
114
127
|
if (!debugSpeedUp)
|
|
115
|
-
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp
|
|
128
|
+
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp in case of slow framerate
|
|
116
129
|
updateCanvas();
|
|
117
130
|
|
|
118
131
|
if (paused)
|
|
@@ -254,7 +267,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
254
267
|
}
|
|
255
268
|
image.src = src;
|
|
256
269
|
})
|
|
257
|
-
)
|
|
270
|
+
);
|
|
258
271
|
|
|
259
272
|
// draw splash screen
|
|
260
273
|
showSplashScreen && promises.push(new Promise(resolve =>
|
|
@@ -279,19 +292,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
279
292
|
});
|
|
280
293
|
}
|
|
281
294
|
|
|
282
|
-
// Called automatically by engine to setup render system
|
|
283
|
-
function enginePreRender()
|
|
284
|
-
{
|
|
285
|
-
// save canvas size
|
|
286
|
-
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
287
|
-
|
|
288
|
-
// disable smoothing for pixel art
|
|
289
|
-
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
290
|
-
|
|
291
|
-
// setup gl rendering if enabled
|
|
292
|
-
glEnable && glPreRender();
|
|
293
|
-
}
|
|
294
|
-
|
|
295
295
|
/** Update each engine object, remove destroyed objects, and update time
|
|
296
296
|
* @memberof Engine */
|
|
297
297
|
function engineObjectsUpdate()
|
|
@@ -325,30 +325,63 @@ function engineObjectsDestroy()
|
|
|
325
325
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
-
/**
|
|
329
|
-
* @param {Vector2} [pos] - Center of test area
|
|
328
|
+
/** Collects all object within a given area
|
|
329
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
330
330
|
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
331
|
-
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
332
331
|
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
332
|
+
* @return {Array} - List of collected objects
|
|
333
333
|
* @memberof Engine */
|
|
334
|
-
function
|
|
334
|
+
function engineObjectsCollect(pos, size, objects=engineObjects)
|
|
335
335
|
{
|
|
336
|
+
const collectedObjects = [];
|
|
336
337
|
if (!pos) // all objects
|
|
337
338
|
{
|
|
338
339
|
for (const o of objects)
|
|
339
|
-
|
|
340
|
+
collectedObjects.push(o);
|
|
340
341
|
}
|
|
341
|
-
else if (
|
|
342
|
+
else if (size instanceof Vector2) // bounding box test
|
|
342
343
|
{
|
|
343
344
|
for (const o of objects)
|
|
344
|
-
isOverlapping(pos, size, o.pos, o.size) &&
|
|
345
|
+
isOverlapping(pos, size, o.pos, o.size) && collectedObjects.push(o);
|
|
345
346
|
}
|
|
346
347
|
else // circle test
|
|
347
348
|
{
|
|
348
349
|
const sizeSquared = size*size;
|
|
349
350
|
for (const o of objects)
|
|
350
|
-
pos.distanceSquared(o.pos) < sizeSquared &&
|
|
351
|
+
pos.distanceSquared(o.pos) < sizeSquared && collectedObjects.push(o);
|
|
352
|
+
}
|
|
353
|
+
return collectedObjects;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Triggers a callback for each object within a given area
|
|
357
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
358
|
+
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
359
|
+
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
360
|
+
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
361
|
+
* @memberof Engine */
|
|
362
|
+
function engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
|
363
|
+
{ engineObjectsCollect(pos, size, objects).forEach(o => callbackFunction(o)); }
|
|
364
|
+
|
|
365
|
+
/** Return a list of objects intersecting a ray
|
|
366
|
+
* @param {Vector2} start
|
|
367
|
+
* @param {Vector2} end
|
|
368
|
+
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
369
|
+
* @return {Array} - List of objects hit
|
|
370
|
+
* @memberof Engine */
|
|
371
|
+
function engineObjectsRaycast(start, end, objects=engineObjects)
|
|
372
|
+
{
|
|
373
|
+
const hitObjects = [];
|
|
374
|
+
for (const o of objects)
|
|
375
|
+
{
|
|
376
|
+
if (o.collideRaycast && isIntersecting(start, end, o.pos, o.size))
|
|
377
|
+
{
|
|
378
|
+
debugRaycast && debugRect(o.pos, o.size, '#f00');
|
|
379
|
+
hitObjects.push(o);
|
|
380
|
+
}
|
|
351
381
|
}
|
|
382
|
+
|
|
383
|
+
debugRaycast && debugLine(start, end, hitObjects.length ? '#f00' : '#00f', .02);
|
|
384
|
+
return hitObjects;
|
|
352
385
|
}
|
|
353
386
|
|
|
354
387
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -436,16 +469,16 @@ function drawEngineSplashScreen(t)
|
|
|
436
469
|
rect(37,14,9,6);
|
|
437
470
|
|
|
438
471
|
// big stack
|
|
439
|
-
rect(50,20,10,-
|
|
440
|
-
rect(50,20,6.5,-
|
|
441
|
-
rect(50,20,3.5,-
|
|
442
|
-
rect(50,20,10,-
|
|
443
|
-
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
444
|
-
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
445
|
-
circle(55,2,11.4,.5,PI-.5)
|
|
446
|
-
rect(45,7,20,-7,color(0,2))
|
|
447
|
-
rect(45,
|
|
448
|
-
rect(45,
|
|
472
|
+
rect(50,20,10,-8,color(0,1))
|
|
473
|
+
rect(50,20,6.5,-8,color(0,2))
|
|
474
|
+
rect(50,20,3.5,-8,color(0,3))
|
|
475
|
+
rect(50,20,10,-8)
|
|
476
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
477
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
478
|
+
circle(55,2,11.4,.5,PI-.5)
|
|
479
|
+
rect(45,7,20,-7,color(0,2))
|
|
480
|
+
rect(45,-1,20,4,color(0,3))
|
|
481
|
+
rect(45,-1,20,8)
|
|
449
482
|
|
|
450
483
|
// engine
|
|
451
484
|
for (let i=5; i--;)
|
package/src/engineAudio.js
CHANGED
package/src/engineBuild.js
CHANGED
|
@@ -161,10 +161,10 @@ function typeScriptBuildStep(filename)
|
|
|
161
161
|
const tsFilename = `${BUILD_FOLDER}/${ENGINE_NAME}.d.ts`
|
|
162
162
|
child_process.execSync(`npx tsc ${filename} --declaration --allowJs --emitDeclarationOnly --outFile ${tsFilename}`);
|
|
163
163
|
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
// Make declare module part use the package name "littlejsengine"
|
|
165
|
+
let fileContent = fs.readFileSync(tsFilename, 'utf8');
|
|
166
|
+
fileContent = fileContent.replace(`${ENGINE_NAME}\.esm`, 'littlejsengine')
|
|
167
|
+
fs.writeFileSync(tsFilename, fileContent);
|
|
168
168
|
|
|
169
169
|
}
|
|
170
170
|
catch (e) { handleError(e, 'Failed to run TypeScript build step!'); }
|
package/src/engineDebug.js
CHANGED
|
@@ -260,6 +260,10 @@ function debugRender()
|
|
|
260
260
|
{
|
|
261
261
|
const saveContext = mainContext;
|
|
262
262
|
mainContext = overlayContext;
|
|
263
|
+
|
|
264
|
+
// draw red rectangle around screen
|
|
265
|
+
const cameraSize = getCameraSize();
|
|
266
|
+
debugRect(cameraPos, cameraSize.subtract(vec2(.1)), '#f008');
|
|
263
267
|
|
|
264
268
|
// mouse pick
|
|
265
269
|
let bestDistance = Infinity, bestObject;
|
|
@@ -349,7 +353,7 @@ function debugRender()
|
|
|
349
353
|
overlayContext.restore();
|
|
350
354
|
});
|
|
351
355
|
|
|
352
|
-
// remove expired
|
|
356
|
+
// remove expired primitives
|
|
353
357
|
debugPrimitives = debugPrimitives.filter(r=>r.time<0);
|
|
354
358
|
}
|
|
355
359
|
|
package/src/engineDraw.js
CHANGED
|
@@ -114,13 +114,23 @@ class TileInfo
|
|
|
114
114
|
this.textureIndex = textureIndex;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
/** Returns
|
|
117
|
+
/** Returns a copy of this tile offset by a vector
|
|
118
118
|
* @param {Vector2} offset - Offset to apply in pixels
|
|
119
119
|
* @return {TileInfo}
|
|
120
120
|
*/
|
|
121
121
|
offset(offset)
|
|
122
122
|
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
123
123
|
|
|
124
|
+
/** Returns a copy of this tile offset by a number of animation frames
|
|
125
|
+
* @param {Number} frame - Offset to apply in animation frames
|
|
126
|
+
* @return {TileInfo}
|
|
127
|
+
*/
|
|
128
|
+
frame(frame)
|
|
129
|
+
{
|
|
130
|
+
ASSERT(typeof frame == 'number');
|
|
131
|
+
return this.offset(vec2(frame*this.size.x, 0));
|
|
132
|
+
}
|
|
133
|
+
|
|
124
134
|
/** Returns the texture info for this tile
|
|
125
135
|
* @return {TextureInfo}
|
|
126
136
|
*/
|
|
@@ -271,21 +281,6 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
271
281
|
drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
|
|
272
282
|
}
|
|
273
283
|
|
|
274
|
-
/** Draw colored polygon using passed in points
|
|
275
|
-
* @param {Array} points - Array of Vector2 points
|
|
276
|
-
* @param {Color} [color=(1,1,1,1)]
|
|
277
|
-
* @param {Boolean} [screenSpace=false]
|
|
278
|
-
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
279
|
-
* @memberof Draw */
|
|
280
|
-
function drawPoly(points, color=new Color, screenSpace, context=mainContext)
|
|
281
|
-
{
|
|
282
|
-
context.fillStyle = color.toString();
|
|
283
|
-
context.beginPath();
|
|
284
|
-
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
285
|
-
context.lineTo(point.x, point.y);
|
|
286
|
-
context.fill();
|
|
287
|
-
}
|
|
288
|
-
|
|
289
284
|
/** Draw colored line between two points
|
|
290
285
|
* @param {Vector2} posA
|
|
291
286
|
* @param {Vector2} posB
|
package/src/engineInput.js
CHANGED
|
@@ -211,9 +211,21 @@ function mouseToScreen(mousePos)
|
|
|
211
211
|
///////////////////////////////////////////////////////////////////////////////
|
|
212
212
|
// Gamepad input
|
|
213
213
|
|
|
214
|
+
// gamepad internal variables
|
|
214
215
|
const stickData = [];
|
|
216
|
+
|
|
217
|
+
// gamepads are updated by engine every frame automatically
|
|
215
218
|
function gamepadsUpdate()
|
|
216
219
|
{
|
|
220
|
+
const applyDeadZones = (v)=>
|
|
221
|
+
{
|
|
222
|
+
const min=.3, max=.8;
|
|
223
|
+
const deadZone = (v)=>
|
|
224
|
+
v > min ? percent( v, min, max) :
|
|
225
|
+
v < -min ? -percent(-v, min, max) : 0;
|
|
226
|
+
return vec2(deadZone(v.x), deadZone(-v.y)).clampLength();
|
|
227
|
+
}
|
|
228
|
+
|
|
217
229
|
// update touch gamepad if enabled
|
|
218
230
|
if (touchGamepadEnable && isTouchDevice)
|
|
219
231
|
{
|
|
@@ -225,7 +237,16 @@ function gamepadsUpdate()
|
|
|
225
237
|
{
|
|
226
238
|
// read virtual analog stick
|
|
227
239
|
const sticks = stickData[0] || (stickData[0] = []);
|
|
228
|
-
sticks[0] = vec2(
|
|
240
|
+
sticks[0] = vec2();
|
|
241
|
+
if (touchGamepadAnalog)
|
|
242
|
+
sticks[0] = applyDeadZones(touchGamepadStick);
|
|
243
|
+
else if (touchGamepadStick.lengthSquared() > .3)
|
|
244
|
+
{
|
|
245
|
+
// convert to 8 way dpad
|
|
246
|
+
sticks[0].x = Math.round(touchGamepadStick.x);
|
|
247
|
+
sticks[0].y = -Math.round(touchGamepadStick.y);
|
|
248
|
+
sticks[0] = sticks[0].clampLength();
|
|
249
|
+
}
|
|
229
250
|
|
|
230
251
|
// read virtual gamepad buttons
|
|
231
252
|
const data = inputData[1] || (inputData[1] = []);
|
|
@@ -237,7 +258,12 @@ function gamepadsUpdate()
|
|
|
237
258
|
}
|
|
238
259
|
}
|
|
239
260
|
|
|
240
|
-
|
|
261
|
+
// return if gamepads are disabled or not supported
|
|
262
|
+
if (!gamepadsEnable || !navigator || !navigator.getGamepads)
|
|
263
|
+
return;
|
|
264
|
+
|
|
265
|
+
// only poll gamepads when focused or in debug mode
|
|
266
|
+
if (!debug && !document.hasFocus())
|
|
241
267
|
return;
|
|
242
268
|
|
|
243
269
|
// poll gamepads
|
|
@@ -251,14 +277,9 @@ function gamepadsUpdate()
|
|
|
251
277
|
|
|
252
278
|
if (gamepad)
|
|
253
279
|
{
|
|
254
|
-
// read clamp dead zone of analog sticks
|
|
255
|
-
const deadZone = .3, deadZoneMax = .8, applyDeadZone = (v)=>
|
|
256
|
-
v > deadZone ? percent( v, deadZone, deadZoneMax) :
|
|
257
|
-
v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
|
|
258
|
-
|
|
259
280
|
// read analog sticks
|
|
260
281
|
for (let j = 0; j < gamepad.axes.length-1; j+=2)
|
|
261
|
-
sticks[j>>1] = vec2(
|
|
282
|
+
sticks[j>>1] = applyDeadZones(vec2(gamepad.axes[j],gamepad.axes[j+1]));
|
|
262
283
|
|
|
263
284
|
// read buttons
|
|
264
285
|
for (let j = gamepad.buttons.length; j--;)
|
|
@@ -387,14 +408,7 @@ function createTouchGamepad()
|
|
|
387
408
|
if (touchPos.distance(stickCenter) < touchGamepadSize)
|
|
388
409
|
{
|
|
389
410
|
// virtual analog stick
|
|
390
|
-
|
|
391
|
-
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
392
|
-
else
|
|
393
|
-
{
|
|
394
|
-
// 8 way dpad
|
|
395
|
-
const angle = touchPos.subtract(stickCenter).angle();
|
|
396
|
-
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
397
|
-
}
|
|
411
|
+
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
398
412
|
}
|
|
399
413
|
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
400
414
|
{
|
package/src/engineObject.js
CHANGED
|
@@ -101,6 +101,8 @@ class EngineObject
|
|
|
101
101
|
this.collideSolidObjects = false;
|
|
102
102
|
/** @property {Boolean} - Object collides with and blocks other objects */
|
|
103
103
|
this.isSolid = false;
|
|
104
|
+
/** @property {Boolean} - Object collides with raycasts */
|
|
105
|
+
this.collideRaycast = false;
|
|
104
106
|
|
|
105
107
|
// add to list of objects
|
|
106
108
|
engineObjects.push(this);
|
|
@@ -305,13 +307,7 @@ class EngineObject
|
|
|
305
307
|
* @param {Number} tileData - the value of the tile at the position
|
|
306
308
|
* @param {Vector2} pos - tile where the collision occured
|
|
307
309
|
* @return {Boolean} - true if the collision should be resolved */
|
|
308
|
-
collideWithTile(tileData, pos)
|
|
309
|
-
|
|
310
|
-
/** Called to check if a tile raycast hit
|
|
311
|
-
* @param {Number} tileData - the value of the tile at the position
|
|
312
|
-
* @param {Vector2} pos - tile where the raycast is
|
|
313
|
-
* @return {Boolean} - true if the raycast should hit */
|
|
314
|
-
collideWithTileRaycast(tileData, pos) { return tileData > 0; }
|
|
310
|
+
collideWithTile(tileData, pos) { return tileData > 0; }
|
|
315
311
|
|
|
316
312
|
/** Called to check if a object collision should be resolved
|
|
317
313
|
* @param {EngineObject} object - the object to test against
|
|
@@ -358,16 +354,18 @@ class EngineObject
|
|
|
358
354
|
}
|
|
359
355
|
|
|
360
356
|
/** Set how this object collides
|
|
361
|
-
* @param {Boolean} [collideSolidObjects] - Does it collide with solid objects
|
|
362
|
-
* @param {Boolean} [isSolid] - Does it collide with and block other objects (expensive in large numbers)
|
|
363
|
-
* @param {Boolean} [collideTiles] - Does it collide with the tile collision
|
|
364
|
-
|
|
357
|
+
* @param {Boolean} [collideSolidObjects] - Does it collide with solid objects?
|
|
358
|
+
* @param {Boolean} [isSolid] - Does it collide with and block other objects? (expensive in large numbers)
|
|
359
|
+
* @param {Boolean} [collideTiles] - Does it collide with the tile collision?
|
|
360
|
+
* @param {Boolean} [collideRaycast] - Does it collide with raycasts? */
|
|
361
|
+
setCollision(collideSolidObjects=true, isSolid=true, collideTiles=true, collideRaycast=true)
|
|
365
362
|
{
|
|
366
363
|
ASSERT(collideSolidObjects || !isSolid, 'solid objects must be set to collide');
|
|
367
364
|
|
|
368
365
|
this.collideSolidObjects = collideSolidObjects;
|
|
369
366
|
this.isSolid = isSolid;
|
|
370
367
|
this.collideTiles = collideTiles;
|
|
368
|
+
this.collideRaycast = collideRaycast;
|
|
371
369
|
}
|
|
372
370
|
|
|
373
371
|
/** Returns string containg info about this object for debugging
|
package/src/engineTileLayer.js
CHANGED
|
@@ -72,7 +72,7 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
/** Return the center of tile
|
|
75
|
+
/** Return the center of first tile hit (does not return the exact intersection)
|
|
76
76
|
* @param {Vector2} posStart
|
|
77
77
|
* @param {Vector2} posEnd
|
|
78
78
|
* @param {EngineObject} [object]
|
|
@@ -268,8 +268,11 @@ class TileLayer extends EngineObject
|
|
|
268
268
|
mainCanvas.height = mainCanvasSize.y;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
//
|
|
272
|
-
|
|
271
|
+
// disable smoothing for pixel art
|
|
272
|
+
this.context.imageSmoothingEnabled = !canvasPixelated;
|
|
273
|
+
|
|
274
|
+
// setup gl rendering if enabled
|
|
275
|
+
glEnable && glPreRender();
|
|
273
276
|
}
|
|
274
277
|
|
|
275
278
|
/** Call to end the redraw process */
|
package/src/engineUtilities.js
CHANGED
|
@@ -121,16 +121,57 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
|
121
121
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
122
122
|
|
|
123
123
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
124
|
-
* @param {Vector2}
|
|
125
|
-
* @param {Vector2} sizeA
|
|
126
|
-
* @param {Vector2}
|
|
127
|
-
* @param {Vector2} [sizeB=(0,0)]
|
|
128
|
-
* @return {Boolean}
|
|
124
|
+
* @param {Vector2} posA - Center of box A
|
|
125
|
+
* @param {Vector2} sizeA - Size of box A
|
|
126
|
+
* @param {Vector2} posB - Center of box B
|
|
127
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
128
|
+
* @return {Boolean} - True if overlapping
|
|
129
129
|
* @memberof Utilities */
|
|
130
|
-
function isOverlapping(
|
|
130
|
+
function isOverlapping(posA, sizeA, posB, sizeB=vec2())
|
|
131
131
|
{
|
|
132
|
-
return abs(
|
|
133
|
-
&& abs(
|
|
132
|
+
return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
|
|
133
|
+
&& abs(posA.y - posB.y)*2 < sizeA.y + sizeB.y;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Returns true if a line segment is intersecting an axis aligned box
|
|
137
|
+
* @param {Vector2} start - Start of raycast
|
|
138
|
+
* @param {Vector2} end - End of raycast
|
|
139
|
+
* @param {Vector2} pos - Center of box
|
|
140
|
+
* @param {Vector2} size - Size of box
|
|
141
|
+
* @return {Boolean} - True if intersecting
|
|
142
|
+
* @memberof Utilities */
|
|
143
|
+
function isIntersecting(start, end, pos, size)
|
|
144
|
+
{
|
|
145
|
+
// Liang-Barsky algorithm
|
|
146
|
+
const boxMin = pos.subtract(size.scale(.5));
|
|
147
|
+
const boxMax = boxMin.add(size);
|
|
148
|
+
const delta = end.subtract(start);
|
|
149
|
+
const a = start.subtract(boxMin);
|
|
150
|
+
const b = start.subtract(boxMax);
|
|
151
|
+
const p = [-delta.x, delta.x, -delta.y, delta.y];
|
|
152
|
+
const q = [a.x, -b.x, a.y, -b.y];
|
|
153
|
+
let tMin = 0, tMax = 1;
|
|
154
|
+
for (let i = 4; i--;)
|
|
155
|
+
{
|
|
156
|
+
if (p[i])
|
|
157
|
+
{
|
|
158
|
+
const t = q[i] / p[i];
|
|
159
|
+
if (p[i] < 0)
|
|
160
|
+
{
|
|
161
|
+
if (t > tMax) return false;
|
|
162
|
+
tMin = max(t, tMin);
|
|
163
|
+
}
|
|
164
|
+
else
|
|
165
|
+
{
|
|
166
|
+
if (t < tMin) return false;
|
|
167
|
+
tMax = min(t, tMax);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else if (q[i] < 0)
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return true;
|
|
134
175
|
}
|
|
135
176
|
|
|
136
177
|
/** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
|
|
@@ -630,7 +671,7 @@ class Color
|
|
|
630
671
|
|
|
631
672
|
/** Returns this color expressed in hsla format
|
|
632
673
|
* @return {Array} */
|
|
633
|
-
|
|
674
|
+
HSLA()
|
|
634
675
|
{
|
|
635
676
|
const r = clamp(this.r);
|
|
636
677
|
const g = clamp(this.g);
|