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/dist/littlejs.release.js
CHANGED
|
@@ -156,16 +156,57 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
|
156
156
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
157
157
|
|
|
158
158
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
159
|
-
* @param {Vector2}
|
|
160
|
-
* @param {Vector2} sizeA
|
|
161
|
-
* @param {Vector2}
|
|
162
|
-
* @param {Vector2} [sizeB=(0,0)]
|
|
163
|
-
* @return {Boolean}
|
|
159
|
+
* @param {Vector2} posA - Center of box A
|
|
160
|
+
* @param {Vector2} sizeA - Size of box A
|
|
161
|
+
* @param {Vector2} posB - Center of box B
|
|
162
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
163
|
+
* @return {Boolean} - True if overlapping
|
|
164
164
|
* @memberof Utilities */
|
|
165
|
-
function isOverlapping(
|
|
165
|
+
function isOverlapping(posA, sizeA, posB, sizeB=vec2())
|
|
166
166
|
{
|
|
167
|
-
return abs(
|
|
168
|
-
&& abs(
|
|
167
|
+
return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
|
|
168
|
+
&& abs(posA.y - posB.y)*2 < sizeA.y + sizeB.y;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Returns true if a line segment is intersecting an axis aligned box
|
|
172
|
+
* @param {Vector2} start - Start of raycast
|
|
173
|
+
* @param {Vector2} end - End of raycast
|
|
174
|
+
* @param {Vector2} pos - Center of box
|
|
175
|
+
* @param {Vector2} size - Size of box
|
|
176
|
+
* @return {Boolean} - True if intersecting
|
|
177
|
+
* @memberof Utilities */
|
|
178
|
+
function isIntersecting(start, end, pos, size)
|
|
179
|
+
{
|
|
180
|
+
// Liang-Barsky algorithm
|
|
181
|
+
const boxMin = pos.subtract(size.scale(.5));
|
|
182
|
+
const boxMax = boxMin.add(size);
|
|
183
|
+
const delta = end.subtract(start);
|
|
184
|
+
const a = start.subtract(boxMin);
|
|
185
|
+
const b = start.subtract(boxMax);
|
|
186
|
+
const p = [-delta.x, delta.x, -delta.y, delta.y];
|
|
187
|
+
const q = [a.x, -b.x, a.y, -b.y];
|
|
188
|
+
let tMin = 0, tMax = 1;
|
|
189
|
+
for (let i = 4; i--;)
|
|
190
|
+
{
|
|
191
|
+
if (p[i])
|
|
192
|
+
{
|
|
193
|
+
const t = q[i] / p[i];
|
|
194
|
+
if (p[i] < 0)
|
|
195
|
+
{
|
|
196
|
+
if (t > tMax) return false;
|
|
197
|
+
tMin = max(t, tMin);
|
|
198
|
+
}
|
|
199
|
+
else
|
|
200
|
+
{
|
|
201
|
+
if (t < tMin) return false;
|
|
202
|
+
tMax = min(t, tMax);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else if (q[i] < 0)
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return true;
|
|
169
210
|
}
|
|
170
211
|
|
|
171
212
|
/** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
|
|
@@ -665,7 +706,7 @@ class Color
|
|
|
665
706
|
|
|
666
707
|
/** Returns this color expressed in hsla format
|
|
667
708
|
* @return {Array} */
|
|
668
|
-
|
|
709
|
+
HSLA()
|
|
669
710
|
{
|
|
670
711
|
const r = clamp(this.r);
|
|
671
712
|
const g = clamp(this.g);
|
|
@@ -1349,6 +1390,8 @@ class EngineObject
|
|
|
1349
1390
|
this.collideSolidObjects = false;
|
|
1350
1391
|
/** @property {Boolean} - Object collides with and blocks other objects */
|
|
1351
1392
|
this.isSolid = false;
|
|
1393
|
+
/** @property {Boolean} - Object collides with raycasts */
|
|
1394
|
+
this.collideRaycast = false;
|
|
1352
1395
|
|
|
1353
1396
|
// add to list of objects
|
|
1354
1397
|
engineObjects.push(this);
|
|
@@ -1553,13 +1596,7 @@ class EngineObject
|
|
|
1553
1596
|
* @param {Number} tileData - the value of the tile at the position
|
|
1554
1597
|
* @param {Vector2} pos - tile where the collision occured
|
|
1555
1598
|
* @return {Boolean} - true if the collision should be resolved */
|
|
1556
|
-
collideWithTile(tileData, pos)
|
|
1557
|
-
|
|
1558
|
-
/** Called to check if a tile raycast hit
|
|
1559
|
-
* @param {Number} tileData - the value of the tile at the position
|
|
1560
|
-
* @param {Vector2} pos - tile where the raycast is
|
|
1561
|
-
* @return {Boolean} - true if the raycast should hit */
|
|
1562
|
-
collideWithTileRaycast(tileData, pos) { return tileData > 0; }
|
|
1599
|
+
collideWithTile(tileData, pos) { return tileData > 0; }
|
|
1563
1600
|
|
|
1564
1601
|
/** Called to check if a object collision should be resolved
|
|
1565
1602
|
* @param {EngineObject} object - the object to test against
|
|
@@ -1606,16 +1643,18 @@ class EngineObject
|
|
|
1606
1643
|
}
|
|
1607
1644
|
|
|
1608
1645
|
/** Set how this object collides
|
|
1609
|
-
* @param {Boolean} [collideSolidObjects] - Does it collide with solid objects
|
|
1610
|
-
* @param {Boolean} [isSolid] - Does it collide with and block other objects (expensive in large numbers)
|
|
1611
|
-
* @param {Boolean} [collideTiles] - Does it collide with the tile collision
|
|
1612
|
-
|
|
1646
|
+
* @param {Boolean} [collideSolidObjects] - Does it collide with solid objects?
|
|
1647
|
+
* @param {Boolean} [isSolid] - Does it collide with and block other objects? (expensive in large numbers)
|
|
1648
|
+
* @param {Boolean} [collideTiles] - Does it collide with the tile collision?
|
|
1649
|
+
* @param {Boolean} [collideRaycast] - Does it collide with raycasts? */
|
|
1650
|
+
setCollision(collideSolidObjects=true, isSolid=true, collideTiles=true, collideRaycast=true)
|
|
1613
1651
|
{
|
|
1614
1652
|
ASSERT(collideSolidObjects || !isSolid, 'solid objects must be set to collide');
|
|
1615
1653
|
|
|
1616
1654
|
this.collideSolidObjects = collideSolidObjects;
|
|
1617
1655
|
this.isSolid = isSolid;
|
|
1618
1656
|
this.collideTiles = collideTiles;
|
|
1657
|
+
this.collideRaycast = collideRaycast;
|
|
1619
1658
|
}
|
|
1620
1659
|
|
|
1621
1660
|
/** Returns string containg info about this object for debugging
|
|
@@ -1755,13 +1794,23 @@ class TileInfo
|
|
|
1755
1794
|
this.textureIndex = textureIndex;
|
|
1756
1795
|
}
|
|
1757
1796
|
|
|
1758
|
-
/** Returns
|
|
1797
|
+
/** Returns a copy of this tile offset by a vector
|
|
1759
1798
|
* @param {Vector2} offset - Offset to apply in pixels
|
|
1760
1799
|
* @return {TileInfo}
|
|
1761
1800
|
*/
|
|
1762
1801
|
offset(offset)
|
|
1763
1802
|
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
1764
1803
|
|
|
1804
|
+
/** Returns a copy of this tile offset by a number of animation frames
|
|
1805
|
+
* @param {Number} frame - Offset to apply in animation frames
|
|
1806
|
+
* @return {TileInfo}
|
|
1807
|
+
*/
|
|
1808
|
+
frame(frame)
|
|
1809
|
+
{
|
|
1810
|
+
ASSERT(typeof frame == 'number');
|
|
1811
|
+
return this.offset(vec2(frame*this.size.x, 0));
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1765
1814
|
/** Returns the texture info for this tile
|
|
1766
1815
|
* @return {TextureInfo}
|
|
1767
1816
|
*/
|
|
@@ -1912,21 +1961,6 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
1912
1961
|
drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
|
|
1913
1962
|
}
|
|
1914
1963
|
|
|
1915
|
-
/** Draw colored polygon using passed in points
|
|
1916
|
-
* @param {Array} points - Array of Vector2 points
|
|
1917
|
-
* @param {Color} [color=(1,1,1,1)]
|
|
1918
|
-
* @param {Boolean} [screenSpace=false]
|
|
1919
|
-
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1920
|
-
* @memberof Draw */
|
|
1921
|
-
function drawPoly(points, color=new Color, screenSpace, context=mainContext)
|
|
1922
|
-
{
|
|
1923
|
-
context.fillStyle = color.toString();
|
|
1924
|
-
context.beginPath();
|
|
1925
|
-
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
1926
|
-
context.lineTo(point.x, point.y);
|
|
1927
|
-
context.fill();
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
1964
|
/** Draw colored line between two points
|
|
1931
1965
|
* @param {Vector2} posA
|
|
1932
1966
|
* @param {Vector2} posB
|
|
@@ -2353,9 +2387,21 @@ function mouseToScreen(mousePos)
|
|
|
2353
2387
|
///////////////////////////////////////////////////////////////////////////////
|
|
2354
2388
|
// Gamepad input
|
|
2355
2389
|
|
|
2390
|
+
// gamepad internal variables
|
|
2356
2391
|
const stickData = [];
|
|
2392
|
+
|
|
2393
|
+
// gamepads are updated by engine every frame automatically
|
|
2357
2394
|
function gamepadsUpdate()
|
|
2358
2395
|
{
|
|
2396
|
+
const applyDeadZones = (v)=>
|
|
2397
|
+
{
|
|
2398
|
+
const min=.3, max=.8;
|
|
2399
|
+
const deadZone = (v)=>
|
|
2400
|
+
v > min ? percent( v, min, max) :
|
|
2401
|
+
v < -min ? -percent(-v, min, max) : 0;
|
|
2402
|
+
return vec2(deadZone(v.x), deadZone(-v.y)).clampLength();
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2359
2405
|
// update touch gamepad if enabled
|
|
2360
2406
|
if (touchGamepadEnable && isTouchDevice)
|
|
2361
2407
|
{
|
|
@@ -2367,7 +2413,16 @@ function gamepadsUpdate()
|
|
|
2367
2413
|
{
|
|
2368
2414
|
// read virtual analog stick
|
|
2369
2415
|
const sticks = stickData[0] || (stickData[0] = []);
|
|
2370
|
-
sticks[0] = vec2(
|
|
2416
|
+
sticks[0] = vec2();
|
|
2417
|
+
if (touchGamepadAnalog)
|
|
2418
|
+
sticks[0] = applyDeadZones(touchGamepadStick);
|
|
2419
|
+
else if (touchGamepadStick.lengthSquared() > .3)
|
|
2420
|
+
{
|
|
2421
|
+
// convert to 8 way dpad
|
|
2422
|
+
sticks[0].x = Math.round(touchGamepadStick.x);
|
|
2423
|
+
sticks[0].y = -Math.round(touchGamepadStick.y);
|
|
2424
|
+
sticks[0] = sticks[0].clampLength();
|
|
2425
|
+
}
|
|
2371
2426
|
|
|
2372
2427
|
// read virtual gamepad buttons
|
|
2373
2428
|
const data = inputData[1] || (inputData[1] = []);
|
|
@@ -2379,7 +2434,12 @@ function gamepadsUpdate()
|
|
|
2379
2434
|
}
|
|
2380
2435
|
}
|
|
2381
2436
|
|
|
2382
|
-
|
|
2437
|
+
// return if gamepads are disabled or not supported
|
|
2438
|
+
if (!gamepadsEnable || !navigator || !navigator.getGamepads)
|
|
2439
|
+
return;
|
|
2440
|
+
|
|
2441
|
+
// only poll gamepads when focused or in debug mode
|
|
2442
|
+
if (!debug && !document.hasFocus())
|
|
2383
2443
|
return;
|
|
2384
2444
|
|
|
2385
2445
|
// poll gamepads
|
|
@@ -2393,14 +2453,9 @@ function gamepadsUpdate()
|
|
|
2393
2453
|
|
|
2394
2454
|
if (gamepad)
|
|
2395
2455
|
{
|
|
2396
|
-
// read clamp dead zone of analog sticks
|
|
2397
|
-
const deadZone = .3, deadZoneMax = .8, applyDeadZone = (v)=>
|
|
2398
|
-
v > deadZone ? percent( v, deadZone, deadZoneMax) :
|
|
2399
|
-
v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
|
|
2400
|
-
|
|
2401
2456
|
// read analog sticks
|
|
2402
2457
|
for (let j = 0; j < gamepad.axes.length-1; j+=2)
|
|
2403
|
-
sticks[j>>1] = vec2(
|
|
2458
|
+
sticks[j>>1] = applyDeadZones(vec2(gamepad.axes[j],gamepad.axes[j+1]));
|
|
2404
2459
|
|
|
2405
2460
|
// read buttons
|
|
2406
2461
|
for (let j = gamepad.buttons.length; j--;)
|
|
@@ -2529,14 +2584,7 @@ function createTouchGamepad()
|
|
|
2529
2584
|
if (touchPos.distance(stickCenter) < touchGamepadSize)
|
|
2530
2585
|
{
|
|
2531
2586
|
// virtual analog stick
|
|
2532
|
-
|
|
2533
|
-
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
2534
|
-
else
|
|
2535
|
-
{
|
|
2536
|
-
// 8 way dpad
|
|
2537
|
-
const angle = touchPos.subtract(stickCenter).angle();
|
|
2538
|
-
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
2539
|
-
}
|
|
2587
|
+
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
2540
2588
|
}
|
|
2541
2589
|
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
2542
2590
|
{
|
|
@@ -2795,7 +2843,7 @@ class SoundWave extends Sound
|
|
|
2795
2843
|
* 1, 0, 9, 1 // channel notes
|
|
2796
2844
|
* ],
|
|
2797
2845
|
* [ // channel 1
|
|
2798
|
-
* 0, 1, // instrument
|
|
2846
|
+
* 0, 1, // instrument 0, right speaker
|
|
2799
2847
|
* 0, 12, 17, -1 // channel notes
|
|
2800
2848
|
* ]
|
|
2801
2849
|
* ],
|
|
@@ -3259,7 +3307,7 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
3259
3307
|
}
|
|
3260
3308
|
}
|
|
3261
3309
|
|
|
3262
|
-
/** Return the center of tile
|
|
3310
|
+
/** Return the center of first tile hit (does not return the exact intersection)
|
|
3263
3311
|
* @param {Vector2} posStart
|
|
3264
3312
|
* @param {Vector2} posEnd
|
|
3265
3313
|
* @param {EngineObject} [object]
|
|
@@ -3455,8 +3503,11 @@ class TileLayer extends EngineObject
|
|
|
3455
3503
|
mainCanvas.height = mainCanvasSize.y;
|
|
3456
3504
|
}
|
|
3457
3505
|
|
|
3458
|
-
//
|
|
3459
|
-
|
|
3506
|
+
// disable smoothing for pixel art
|
|
3507
|
+
this.context.imageSmoothingEnabled = !canvasPixelated;
|
|
3508
|
+
|
|
3509
|
+
// setup gl rendering if enabled
|
|
3510
|
+
glEnable && glPreRender();
|
|
3460
3511
|
}
|
|
3461
3512
|
|
|
3462
3513
|
/** Call to end the redraw process */
|
|
@@ -4605,7 +4656,7 @@ const engineName = 'LittleJS';
|
|
|
4605
4656
|
* @type {String}
|
|
4606
4657
|
* @default
|
|
4607
4658
|
* @memberof Engine */
|
|
4608
|
-
const engineVersion = '1.9.
|
|
4659
|
+
const engineVersion = '1.9.5';
|
|
4609
4660
|
|
|
4610
4661
|
/** Frames per second to update
|
|
4611
4662
|
* @type {Number}
|
|
@@ -4672,6 +4723,19 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4672
4723
|
{
|
|
4673
4724
|
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
4674
4725
|
|
|
4726
|
+
// Called automatically by engine to setup render system
|
|
4727
|
+
function enginePreRender()
|
|
4728
|
+
{
|
|
4729
|
+
// save canvas size
|
|
4730
|
+
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
4731
|
+
|
|
4732
|
+
// disable smoothing for pixel art
|
|
4733
|
+
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
4734
|
+
|
|
4735
|
+
// setup gl rendering if enabled
|
|
4736
|
+
glEnable && glPreRender();
|
|
4737
|
+
}
|
|
4738
|
+
|
|
4675
4739
|
// internal update loop for engine
|
|
4676
4740
|
function engineUpdate(frameTimeMS=0)
|
|
4677
4741
|
{
|
|
@@ -4687,7 +4751,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4687
4751
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
4688
4752
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
4689
4753
|
if (!debugSpeedUp)
|
|
4690
|
-
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp
|
|
4754
|
+
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp in case of slow framerate
|
|
4691
4755
|
updateCanvas();
|
|
4692
4756
|
|
|
4693
4757
|
if (paused)
|
|
@@ -4829,7 +4893,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4829
4893
|
}
|
|
4830
4894
|
image.src = src;
|
|
4831
4895
|
})
|
|
4832
|
-
)
|
|
4896
|
+
);
|
|
4833
4897
|
|
|
4834
4898
|
// draw splash screen
|
|
4835
4899
|
showSplashScreen && promises.push(new Promise(resolve =>
|
|
@@ -4854,19 +4918,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4854
4918
|
});
|
|
4855
4919
|
}
|
|
4856
4920
|
|
|
4857
|
-
// Called automatically by engine to setup render system
|
|
4858
|
-
function enginePreRender()
|
|
4859
|
-
{
|
|
4860
|
-
// save canvas size
|
|
4861
|
-
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
4862
|
-
|
|
4863
|
-
// disable smoothing for pixel art
|
|
4864
|
-
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
4865
|
-
|
|
4866
|
-
// setup gl rendering if enabled
|
|
4867
|
-
glEnable && glPreRender();
|
|
4868
|
-
}
|
|
4869
|
-
|
|
4870
4921
|
/** Update each engine object, remove destroyed objects, and update time
|
|
4871
4922
|
* @memberof Engine */
|
|
4872
4923
|
function engineObjectsUpdate()
|
|
@@ -4900,30 +4951,63 @@ function engineObjectsDestroy()
|
|
|
4900
4951
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
4901
4952
|
}
|
|
4902
4953
|
|
|
4903
|
-
/**
|
|
4904
|
-
* @param {Vector2} [pos] - Center of test area
|
|
4954
|
+
/** Collects all object within a given area
|
|
4955
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
4905
4956
|
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
4906
|
-
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
4907
4957
|
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
4958
|
+
* @return {Array} - List of collected objects
|
|
4908
4959
|
* @memberof Engine */
|
|
4909
|
-
function
|
|
4960
|
+
function engineObjectsCollect(pos, size, objects=engineObjects)
|
|
4910
4961
|
{
|
|
4962
|
+
const collectedObjects = [];
|
|
4911
4963
|
if (!pos) // all objects
|
|
4912
4964
|
{
|
|
4913
4965
|
for (const o of objects)
|
|
4914
|
-
|
|
4966
|
+
collectedObjects.push(o);
|
|
4915
4967
|
}
|
|
4916
|
-
else if (
|
|
4968
|
+
else if (size instanceof Vector2) // bounding box test
|
|
4917
4969
|
{
|
|
4918
4970
|
for (const o of objects)
|
|
4919
|
-
isOverlapping(pos, size, o.pos, o.size) &&
|
|
4971
|
+
isOverlapping(pos, size, o.pos, o.size) && collectedObjects.push(o);
|
|
4920
4972
|
}
|
|
4921
4973
|
else // circle test
|
|
4922
4974
|
{
|
|
4923
4975
|
const sizeSquared = size*size;
|
|
4924
4976
|
for (const o of objects)
|
|
4925
|
-
pos.distanceSquared(o.pos) < sizeSquared &&
|
|
4977
|
+
pos.distanceSquared(o.pos) < sizeSquared && collectedObjects.push(o);
|
|
4926
4978
|
}
|
|
4979
|
+
return collectedObjects;
|
|
4980
|
+
}
|
|
4981
|
+
|
|
4982
|
+
/** Triggers a callback for each object within a given area
|
|
4983
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
4984
|
+
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
4985
|
+
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
4986
|
+
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
4987
|
+
* @memberof Engine */
|
|
4988
|
+
function engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
|
4989
|
+
{ engineObjectsCollect(pos, size, objects).forEach(o => callbackFunction(o)); }
|
|
4990
|
+
|
|
4991
|
+
/** Return a list of objects intersecting a ray
|
|
4992
|
+
* @param {Vector2} start
|
|
4993
|
+
* @param {Vector2} end
|
|
4994
|
+
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
4995
|
+
* @return {Array} - List of objects hit
|
|
4996
|
+
* @memberof Engine */
|
|
4997
|
+
function engineObjectsRaycast(start, end, objects=engineObjects)
|
|
4998
|
+
{
|
|
4999
|
+
const hitObjects = [];
|
|
5000
|
+
for (const o of objects)
|
|
5001
|
+
{
|
|
5002
|
+
if (o.collideRaycast && isIntersecting(start, end, o.pos, o.size))
|
|
5003
|
+
{
|
|
5004
|
+
debugRaycast && debugRect(o.pos, o.size, '#f00');
|
|
5005
|
+
hitObjects.push(o);
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
|
|
5009
|
+
debugRaycast && debugLine(start, end, hitObjects.length ? '#f00' : '#00f', .02);
|
|
5010
|
+
return hitObjects;
|
|
4927
5011
|
}
|
|
4928
5012
|
|
|
4929
5013
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -5011,16 +5095,16 @@ function drawEngineSplashScreen(t)
|
|
|
5011
5095
|
rect(37,14,9,6);
|
|
5012
5096
|
|
|
5013
5097
|
// big stack
|
|
5014
|
-
rect(50,20,10,-
|
|
5015
|
-
rect(50,20,6.5,-
|
|
5016
|
-
rect(50,20,3.5,-
|
|
5017
|
-
rect(50,20,10,-
|
|
5018
|
-
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
5019
|
-
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
5020
|
-
circle(55,2,11.4,.5,PI-.5)
|
|
5021
|
-
rect(45,7,20,-7,color(0,2))
|
|
5022
|
-
rect(45,
|
|
5023
|
-
rect(45,
|
|
5098
|
+
rect(50,20,10,-8,color(0,1))
|
|
5099
|
+
rect(50,20,6.5,-8,color(0,2))
|
|
5100
|
+
rect(50,20,3.5,-8,color(0,3))
|
|
5101
|
+
rect(50,20,10,-8)
|
|
5102
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
5103
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
5104
|
+
circle(55,2,11.4,.5,PI-.5)
|
|
5105
|
+
rect(45,7,20,-7,color(0,2))
|
|
5106
|
+
rect(45,-1,20,4,color(0,3))
|
|
5107
|
+
rect(45,-1,20,8)
|
|
5024
5108
|
|
|
5025
5109
|
// engine
|
|
5026
5110
|
for (let i=5; i--;)
|
package/examples/module/game.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
// import module
|
|
10
10
|
import * as LittleJS from '../../dist/littlejs.esm.js';
|
|
11
|
-
const {
|
|
11
|
+
const {tile, vec2, hsl} = LittleJS;
|
|
12
12
|
|
|
13
13
|
// show the LittleJS splash screen
|
|
14
14
|
LittleJS.setShowSplashScreen(true);
|
|
@@ -218,8 +218,7 @@ class Character extends GameObject
|
|
|
218
218
|
const animationFrame = this.isDead() ? 0 :
|
|
219
219
|
this.climbingLadder || this.groundTimer.active() ?
|
|
220
220
|
2*this.walkCyclePercent|0 : 1;
|
|
221
|
-
|
|
222
|
-
this.tileInfo.pos.x = playerTile.pos.x + playerTile.size.x*animationFrame;
|
|
221
|
+
this.tileInfo = spriteAtlas.player.frame(animationFrame);
|
|
223
222
|
|
|
224
223
|
let bodyPos = this.pos;
|
|
225
224
|
if (!this.isDead())
|
|
@@ -130,14 +130,13 @@ function destroyTile(pos, makeSound = 1, cleanNeighbors = 1)
|
|
|
130
130
|
|
|
131
131
|
// destroy tile
|
|
132
132
|
const tileType = getTileCollisionData(pos);
|
|
133
|
-
|
|
134
|
-
if (!tileType || tileType == tileType_solid)
|
|
133
|
+
if (!tileType)
|
|
135
134
|
return 1;
|
|
136
135
|
|
|
137
136
|
const tileLayer = tileLayers[foregroundLayerIndex];
|
|
138
137
|
const centerPos = pos.add(vec2(.5));
|
|
139
138
|
const layerData = tileLayer.getData(pos);
|
|
140
|
-
if (!layerData)
|
|
139
|
+
if (!layerData || tileType == tileType_solid)
|
|
141
140
|
return;
|
|
142
141
|
|
|
143
142
|
// create effects
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
// import module
|
|
8
8
|
import * as LittleJS from '../../dist/littlejs.esm.js';
|
|
9
|
-
const {
|
|
9
|
+
const { tile, vec2, hsl } = LittleJS;
|
|
10
10
|
// show the LittleJS splash screen
|
|
11
11
|
LittleJS.setShowSplashScreen(true);
|
|
12
12
|
// sound effects
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
// import module
|
|
10
10
|
import * as LittleJS from '../../dist/littlejs.esm.js';
|
|
11
|
-
const {
|
|
11
|
+
const {tile, vec2, hsl} = LittleJS;
|
|
12
12
|
|
|
13
13
|
// show the LittleJS splash screen
|
|
14
14
|
LittleJS.setShowSplashScreen(true);
|
package/package.json
CHANGED
package/reference.md
CHANGED
|
@@ -13,13 +13,7 @@ To start LittleJS, you need to create a few functions and pass them to engineIni
|
|
|
13
13
|
|
|
14
14
|
```javascript
|
|
15
15
|
// Start up LittleJS engine with your callback functions
|
|
16
|
-
engineInit(init, update, updatePost, render, renderPost, imageSources=['tiles.png'])
|
|
17
|
-
|
|
18
|
-
// Destroy and remove all objects
|
|
19
|
-
engineObjectsDestroy()
|
|
20
|
-
|
|
21
|
-
// Trigger a callback for each object within a given area
|
|
22
|
-
engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
|
16
|
+
engineInit(init, update, updatePost, render, renderPost, imageSources=['tiles.png']);
|
|
23
17
|
```
|
|
24
18
|
|
|
25
19
|
## LittleJS Utilities Classes and Functions
|
|
@@ -53,6 +47,7 @@ lerpAngle(percent, angleA, angleB) // Linearly interpolates with wrap
|
|
|
53
47
|
smoothStep(percent) // Applies smoothstep function
|
|
54
48
|
nearestPowerOfTwo(value) // Returns the nearest power of two
|
|
55
49
|
isOverlapping(pointA, sizeA, pointB, sizeB) // Checks if bounding boxes overlap
|
|
50
|
+
isIntersecting(start, end, pos, size) // Checks if ray intersects box
|
|
56
51
|
wave(frequency=1, amplitude=1, t=time) // Returns oscillating wave
|
|
57
52
|
formatTime(t) // Formats seconds for display
|
|
58
53
|
|
|
@@ -103,7 +98,7 @@ Color.scale(scale, alphaScale=scale) // Scale by a float
|
|
|
103
98
|
Color.clamp() // Clamp this color
|
|
104
99
|
Color.lerp(c, percent) // Interpolate between colors
|
|
105
100
|
Color.setHSLA(h=0, s=0, l=1, a=1) // Set the color from HSLA values
|
|
106
|
-
Color.
|
|
101
|
+
Color.HSLA() // Get the color in HSLA format
|
|
107
102
|
Color.mutate(amount=.05, alphaAmount=0) // Randomly diverge from this color
|
|
108
103
|
Color.setHex(hex) // Set this color from a hex code
|
|
109
104
|
Color.rgbaInt() // Get this color as 32 bit RGBA value
|
|
@@ -138,7 +133,6 @@ Timer.valueOf() // Get how long since elapsed, 0 if not set
|
|
|
138
133
|
// Drawing functions
|
|
139
134
|
drawTile(pos, size=(1,1), tileInfo, color, angle=0, mirror, additiveColor)
|
|
140
135
|
drawRect(pos, size=(1,1), color=(1,1,1,1), angle=0)
|
|
141
|
-
drawPoly(points, color=(1,1,1,1))
|
|
142
136
|
drawLine(posA, posB, thickness=.1, color=(1,1,1,1))
|
|
143
137
|
drawCanvas2D(pos, size, angle, mirror, drawFunction)
|
|
144
138
|
drawText(text, pos, size=1, color=(1,1,1,1), lineWidth, lineColor)
|
|
@@ -153,6 +147,7 @@ TileInfo.pos // Top left corner of tile in pixels
|
|
|
153
147
|
TileInfo.size // Size of tile in pixels
|
|
154
148
|
TileInfo.textureIndex // Texture index to use
|
|
155
149
|
TileInfo.offset(offset) // Offset this tile by a certain amount in pixels
|
|
150
|
+
TileInfo.frame(frame) // Offset this tile by a number of animation frames
|
|
156
151
|
TileInfo.getTextureInfo() // Returns texture info for this tile
|
|
157
152
|
|
|
158
153
|
// Texture Info Object
|
|
@@ -285,7 +280,6 @@ EngineObject.update() // Update object, called auto
|
|
|
285
280
|
EngineObject.render() // Render object, called automatically
|
|
286
281
|
EngineObject.destroy() // Destroy this object and children
|
|
287
282
|
EngineObject.collideWithTile(tileData, pos) // Tile collision resolve check
|
|
288
|
-
EngineObject.collideWithTileRaycast(tileData, pos) // Check if raycast hit
|
|
289
283
|
EngineObject.collideWithObject(object) // Object collision resolve check
|
|
290
284
|
EngineObject.getAliveTime(object) // How long since object was created
|
|
291
285
|
EngineObject.applyAcceleration(acceleration) // Apply acceleration
|
|
@@ -314,7 +308,7 @@ EngineObject.renderOrder // Objects are sorted by render order
|
|
|
314
308
|
EngineObject.velocity // Velocity of the object
|
|
315
309
|
EngineObject.angleVelocity // Angular velocity of the object
|
|
316
310
|
|
|
317
|
-
// Object settings
|
|
311
|
+
// Engine Object settings
|
|
318
312
|
enablePhysicsSolver = true // Enable collisions between objects?
|
|
319
313
|
objectDefaultMass = 1 // Default object mass for collisions
|
|
320
314
|
objectDefaultDamping = 1 // How much to slow velocity by each frame (0-1)
|
|
@@ -323,6 +317,12 @@ objectDefaultElasticity = 0 // How much to bounce when a collision occurs (0-1
|
|
|
323
317
|
objectDefaultFriction = .8 // How much to slow when touching (0-1)
|
|
324
318
|
objectMaxSpeed = 1 // Clamp max speed to avoid fast objects missing collisions
|
|
325
319
|
gravity = 0 // How much gravity to apply to objects
|
|
320
|
+
|
|
321
|
+
// Engine Object functions
|
|
322
|
+
engineObjectsCollect(pos, size, objects=engineObjects)k
|
|
323
|
+
engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
|
324
|
+
engineObjectsRaycast(start, end, objects=engineObjects)
|
|
325
|
+
engineObjectsDestroy()
|
|
326
326
|
```
|
|
327
327
|
|
|
328
328
|
## LittleJS Tile Layer System
|