littlejsengine 1.7.21 → 1.8.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 +28 -55
- package/build/littlejs.d.ts +595 -552
- package/build/littlejs.esm.js +626 -535
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +542 -264
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +542 -264
- package/examples/breakout/game.js +17 -14
- package/examples/breakout/gameObjects.js +29 -8
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/README.md +3 -3
- package/examples/breakoutTutorial/game.js +4 -4
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/game.js +3 -2
- package/examples/electron/index.html +2 -2
- package/examples/empty/game.js +1 -1
- package/examples/favicon.png +0 -0
- package/examples/js13k/game.js +20 -15
- package/examples/js13k/index.html +14 -14
- package/examples/module/game.js +5 -4
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +19 -22
- package/examples/platformer/game.js +3 -3
- package/examples/platformer/gameEffects.js +21 -19
- package/examples/platformer/gameLevel.js +6 -6
- package/examples/platformer/gameObjects.js +18 -18
- package/examples/platformer/gamePlayer.js +4 -3
- package/examples/platformer/index.html +6 -6
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +10 -8
- package/examples/puzzle/index.html +2 -2
- package/examples/screenshot.jpg +0 -0
- package/examples/starter/game.js +32 -21
- package/examples/starter/index.html +13 -13
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +4 -4
- package/examples/typescript/game.js +4 -3
- package/examples/typescript/game.ts +5 -4
- package/examples/typescript/index.html +1 -1
- package/package.json +2 -1
- package/src/engine.js +59 -52
- package/src/engineAudio.js +2 -1
- package/src/engineDraw.js +171 -55
- package/src/engineExport.js +84 -271
- package/src/engineMedals.js +13 -45
- package/src/engineObject.js +13 -13
- package/src/engineParticles.js +17 -17
- package/src/engineSettings.js +195 -2
- package/src/engineTileLayer.js +23 -22
- package/src/engineUtilities.js +6 -6
- package/src/engineWebGL.js +43 -50
package/build/littlejs.js
CHANGED
|
@@ -617,10 +617,10 @@ function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear)
|
|
|
617
617
|
* - Can be used to create a deterministic random number sequence
|
|
618
618
|
* @example
|
|
619
619
|
* let r = new RandomGenerator(123); // random number generator with seed 123
|
|
620
|
-
* let a = r.
|
|
621
|
-
* let b = r.
|
|
620
|
+
* let a = r.float(); // random value between 0 and 1
|
|
621
|
+
* let b = r.int(10); // random integer between 0 and 9
|
|
622
622
|
* r.seed = 123; // reset the seed
|
|
623
|
-
* let c = r.
|
|
623
|
+
* let c = r.float(); // the same value as a
|
|
624
624
|
*/
|
|
625
625
|
class RandomGenerator
|
|
626
626
|
{
|
|
@@ -649,18 +649,18 @@ class RandomGenerator
|
|
|
649
649
|
* @param {Number} valueA
|
|
650
650
|
* @param {Number} [valueB=0]
|
|
651
651
|
* @return {Number} */
|
|
652
|
-
int(valueA, valueB=0) { return Math.floor(this.
|
|
652
|
+
int(valueA, valueB=0) { return Math.floor(this.float(valueA, valueB)); }
|
|
653
653
|
|
|
654
654
|
/** Randomly returns either -1 or 1 deterministically
|
|
655
655
|
* @return {Number} */
|
|
656
|
-
sign() { return this.
|
|
656
|
+
sign() { return this.int(2) * 2 - 1; }
|
|
657
657
|
}
|
|
658
658
|
|
|
659
659
|
///////////////////////////////////////////////////////////////////////////////
|
|
660
660
|
|
|
661
661
|
/**
|
|
662
662
|
* Create a 2d vector, can take another Vector2 to copy, 2 scalars, or 1 scalar
|
|
663
|
-
* @param {Number} [x=0]
|
|
663
|
+
* @param {(Number|Vector2)} [x=0]
|
|
664
664
|
* @param {Number} [y=0]
|
|
665
665
|
* @return {Vector2}
|
|
666
666
|
* @example
|
|
@@ -1144,7 +1144,7 @@ let glOverlay = 1;
|
|
|
1144
1144
|
* @memberof Settings */
|
|
1145
1145
|
let tileSizeDefault = vec2(16);
|
|
1146
1146
|
|
|
1147
|
-
/**
|
|
1147
|
+
/** How many pixels smaller to draw tiles to prevent bleeding from neighbors
|
|
1148
1148
|
* @type {Number}
|
|
1149
1149
|
* @default
|
|
1150
1150
|
* @memberof Settings */
|
|
@@ -1318,7 +1318,200 @@ let medalDisplayIconSize = 50;
|
|
|
1318
1318
|
* @type {Boolean}
|
|
1319
1319
|
* @default 0
|
|
1320
1320
|
* @memberof Settings */
|
|
1321
|
-
let medalsPreventUnlock;
|
|
1321
|
+
let medalsPreventUnlock;
|
|
1322
|
+
|
|
1323
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1324
|
+
// Setters for global variables
|
|
1325
|
+
|
|
1326
|
+
/** Set position of camera in world space
|
|
1327
|
+
* @param {Vector2} pos
|
|
1328
|
+
* @memberof Settings */
|
|
1329
|
+
function setCameraPos(pos) { cameraPos = pos; }
|
|
1330
|
+
|
|
1331
|
+
/** Set scale of camera in world space
|
|
1332
|
+
* @param {Number} scale
|
|
1333
|
+
* @memberof Settings */
|
|
1334
|
+
function setCameraScale(scale) { cameraScale = scale; }
|
|
1335
|
+
|
|
1336
|
+
/** Set max size of the canvas
|
|
1337
|
+
* @param {Vector2} size
|
|
1338
|
+
* @memberof Settings */
|
|
1339
|
+
function setCanvasMaxSize(size) { canvasMaxSize = size; }
|
|
1340
|
+
|
|
1341
|
+
/** Set fixed size of the canvas
|
|
1342
|
+
* @param {Vector2} size
|
|
1343
|
+
* @memberof Settings */
|
|
1344
|
+
function setCanvasFixedSize(size) { canvasFixedSize = size; }
|
|
1345
|
+
|
|
1346
|
+
/** Disables anti aliasing for pixel art if true
|
|
1347
|
+
* @param {Boolean} pixelated
|
|
1348
|
+
* @memberof Settings */
|
|
1349
|
+
function setCanvasPixelated(pixelated) { canvasPixelated = pixelated; }
|
|
1350
|
+
|
|
1351
|
+
/** Set default font used for text rendering
|
|
1352
|
+
* @param {String} font
|
|
1353
|
+
* @memberof Settings */
|
|
1354
|
+
function setFontDefault(font) { fontDefault = font; }
|
|
1355
|
+
|
|
1356
|
+
/** Set if webgl rendering is enabled
|
|
1357
|
+
* @param {Boolean} enable
|
|
1358
|
+
* @memberof Settings */
|
|
1359
|
+
function setGlEnable(enable) { glEnable = enable; }
|
|
1360
|
+
|
|
1361
|
+
/** Set to not composite the WebGL canvas
|
|
1362
|
+
* @param {Boolean} overlay
|
|
1363
|
+
* @memberof Settings */
|
|
1364
|
+
function setGlOverlay(overlay) { glOverlay = overlay; }
|
|
1365
|
+
|
|
1366
|
+
/** Set default size of tiles in pixels
|
|
1367
|
+
* @param {Vector2} size
|
|
1368
|
+
* @memberof Settings */
|
|
1369
|
+
function setTileSizeDefault(size) { tileSizeDefault = size; }
|
|
1370
|
+
|
|
1371
|
+
/** Set to prevent tile bleeding from neighbors in pixels
|
|
1372
|
+
* @param {Number} scale
|
|
1373
|
+
* @memberof Settings */
|
|
1374
|
+
function setTileFixBleedScale(scale) { tileFixBleedScale = scale; }
|
|
1375
|
+
|
|
1376
|
+
/** Set if collisions between objects are enabled
|
|
1377
|
+
* @param {Boolean} enable
|
|
1378
|
+
* @memberof Settings */
|
|
1379
|
+
function setEnablePhysicsSolver(enable) { enablePhysicsSolver = enable; }
|
|
1380
|
+
|
|
1381
|
+
/** Set default object mass for collison calcuations
|
|
1382
|
+
* @param {Number} mass
|
|
1383
|
+
* @memberof Settings */
|
|
1384
|
+
function setObjectDefaultMass(mass) { objectDefaultMass = mass; }
|
|
1385
|
+
|
|
1386
|
+
/** Set how much to slow velocity by each frame
|
|
1387
|
+
* @param {Number} damping
|
|
1388
|
+
* @memberof Settings */
|
|
1389
|
+
function setObjectDefaultDamping(damp) { objectDefaultDamping = damp; }
|
|
1390
|
+
|
|
1391
|
+
/** Set how much to slow angular velocity each frame
|
|
1392
|
+
* @param {Number} damping
|
|
1393
|
+
* @memberof Settings */
|
|
1394
|
+
function setObjectDefaultAngleDamping(damp) { objectDefaultAngleDamping = damp; }
|
|
1395
|
+
|
|
1396
|
+
/** Set how much to bounce when a collision occur
|
|
1397
|
+
* @param {Number} elasticity
|
|
1398
|
+
* @memberof Settings */
|
|
1399
|
+
function setObjectDefaultElasticity(elasticity) { objectDefaultElasticity = elasticity; }
|
|
1400
|
+
|
|
1401
|
+
/** Set how much to slow when touching
|
|
1402
|
+
* @param {Number} friction
|
|
1403
|
+
* @memberof Settings */
|
|
1404
|
+
function setObjectDefaultFriction(friction) { objectDefaultFriction = friction; }
|
|
1405
|
+
|
|
1406
|
+
/** Set max speed to avoid fast objects missing collisions
|
|
1407
|
+
* @param {Number} speed
|
|
1408
|
+
* @memberof Settings */
|
|
1409
|
+
function setObjectMaxSpeed(speed) { objectMaxSpeed = speed; }
|
|
1410
|
+
|
|
1411
|
+
/** Set how much gravity to apply to objects along the Y axis
|
|
1412
|
+
* @param {Number} gravity
|
|
1413
|
+
* @memberof Settings */
|
|
1414
|
+
function setGravity(g) { gravity = g; }
|
|
1415
|
+
|
|
1416
|
+
/** Set to scales emit rate of particles
|
|
1417
|
+
* @param {Number} scale
|
|
1418
|
+
* @memberof Settings */
|
|
1419
|
+
function setParticleEmitRateScale(scale) { particleEmitRateScale = scale; }
|
|
1420
|
+
|
|
1421
|
+
/** Set if gamepads are enabled
|
|
1422
|
+
* @param {Boolean} enable
|
|
1423
|
+
* @memberof Settings */
|
|
1424
|
+
function setGamepadsEnable(enable) { gamepadsEnable = enable; }
|
|
1425
|
+
|
|
1426
|
+
/** Set if the dpad input is also routed to the left analog stick
|
|
1427
|
+
* @param {Boolean} enable
|
|
1428
|
+
* @memberof Settings */
|
|
1429
|
+
function setGamepadDirectionEmulateStick(enable) { gamepadDirectionEmulateStick = enable; }
|
|
1430
|
+
|
|
1431
|
+
/** Set if true the WASD keys are also routed to the direction keys
|
|
1432
|
+
* @param {Boolean} enable
|
|
1433
|
+
* @memberof Settings */
|
|
1434
|
+
function setInputWASDEmulateDirection(enable) { inputWASDEmulateDirection = enable; }
|
|
1435
|
+
|
|
1436
|
+
/** Set if touch gamepad should appear on mobile devices
|
|
1437
|
+
* @param {Boolean} enable
|
|
1438
|
+
* @memberof Settings */
|
|
1439
|
+
function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
|
|
1440
|
+
|
|
1441
|
+
/** Set if touch gamepad should be analog stick or 8 way dpad
|
|
1442
|
+
* @param {Boolean} analog
|
|
1443
|
+
* @memberof Settings */
|
|
1444
|
+
function setTouchGamepadAnalog(analog) { touchGamepadAnalog = analog; }
|
|
1445
|
+
|
|
1446
|
+
/** Set size of virutal gamepad for touch devices in pixels
|
|
1447
|
+
* @param {Number} size
|
|
1448
|
+
* @memberof Settings */
|
|
1449
|
+
function setTouchGamepadSize(size) { touchGamepadSize = size; }
|
|
1450
|
+
|
|
1451
|
+
/** Set transparency of touch gamepad overlay
|
|
1452
|
+
* @param {Number} alpha
|
|
1453
|
+
* @memberof Settings */
|
|
1454
|
+
function setTouchGamepadAlpha(alpha) { touchGamepadAlpha = alpha; }
|
|
1455
|
+
|
|
1456
|
+
/** Set to allow vibration hardware if it exists
|
|
1457
|
+
* @param {Boolean} enable
|
|
1458
|
+
* @memberof Settings */
|
|
1459
|
+
function setVibrateEnable(enable) { vibrateEnable = enable; }
|
|
1460
|
+
|
|
1461
|
+
/** Set to disable all audio code
|
|
1462
|
+
* @param {Boolean} enable
|
|
1463
|
+
* @memberof Settings */
|
|
1464
|
+
function setSoundEnable(enable) { soundEnable = enable; }
|
|
1465
|
+
|
|
1466
|
+
/** Set volume scale to apply to all sound, music and speech
|
|
1467
|
+
* @param {Number} volume
|
|
1468
|
+
* @memberof Settings */
|
|
1469
|
+
function setSoundVolume(volume) { soundVolume = volume; }
|
|
1470
|
+
|
|
1471
|
+
/** Set default range where sound no longer plays
|
|
1472
|
+
* @param {Number} range
|
|
1473
|
+
* @memberof Settings */
|
|
1474
|
+
function setSoundDefaultRange(range) { soundDefaultRange = range; }
|
|
1475
|
+
|
|
1476
|
+
/** Set default range percent to start tapering off sound
|
|
1477
|
+
* @param {Number} taper
|
|
1478
|
+
* @memberof Settings */
|
|
1479
|
+
function setSoundDefaultTaper(taper) { soundDefaultTaper = taper; }
|
|
1480
|
+
|
|
1481
|
+
/** Set how long to show medals for in seconds
|
|
1482
|
+
* @param {Number} time
|
|
1483
|
+
* @memberof Settings */
|
|
1484
|
+
function setMedalDisplayTime(time) { medalDisplayTime = time; }
|
|
1485
|
+
|
|
1486
|
+
/** Set how quickly to slide on/off medals in seconds
|
|
1487
|
+
* @param {Number} time
|
|
1488
|
+
* @memberof Settings */
|
|
1489
|
+
function setMedalDisplaySlideTime(time) { medalDisplaySlideTime = time; }
|
|
1490
|
+
|
|
1491
|
+
/** Set size of medal display
|
|
1492
|
+
* @param {Vector2} size
|
|
1493
|
+
* @memberof Settings */
|
|
1494
|
+
function setMedalDisplaySize(size) { medalDisplaySize = size; }
|
|
1495
|
+
|
|
1496
|
+
/** Set size of icon in medal display
|
|
1497
|
+
* @param {Number} size
|
|
1498
|
+
* @memberof Settings */
|
|
1499
|
+
function setMedalDisplayIconSize(size) { medalDisplayIconSize = size; }
|
|
1500
|
+
|
|
1501
|
+
/** Set to stop medals from being unlockable
|
|
1502
|
+
* @param {Boolean} preventUnlock
|
|
1503
|
+
* @memberof Settings */
|
|
1504
|
+
function setMedalsPreventUnlock(preventUnlock) { medalsPreventUnlock = preventUnlock; }
|
|
1505
|
+
|
|
1506
|
+
/** Set if watermark with FPS should be shown
|
|
1507
|
+
* @param {Boolean} show
|
|
1508
|
+
* @memberof Debug */
|
|
1509
|
+
function setShowWatermark(show) { showWatermark = show; }
|
|
1510
|
+
|
|
1511
|
+
/** Set key code used to toggle debug mode, Esc by default
|
|
1512
|
+
* @param {Number} key
|
|
1513
|
+
* @memberof Debug */
|
|
1514
|
+
function setDebugKey(key) { debugKey = key; }
|
|
1322
1515
|
/**
|
|
1323
1516
|
* LittleJS Object System
|
|
1324
1517
|
*/
|
|
@@ -1353,18 +1546,20 @@ let medalsPreventUnlock;
|
|
|
1353
1546
|
class EngineObject
|
|
1354
1547
|
{
|
|
1355
1548
|
/** Create an engine object and adds it to the list of objects
|
|
1356
|
-
* @param {Vector2} [
|
|
1357
|
-
* @param {Vector2} [size=Vector2(1,1)]
|
|
1358
|
-
* @param {
|
|
1359
|
-
* @param {
|
|
1360
|
-
* @param {
|
|
1361
|
-
* @param {
|
|
1362
|
-
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
1549
|
+
* @param {Vector2} [pos=Vector2()] - World space position of the object
|
|
1550
|
+
* @param {Vector2} [size=Vector2(1,1)] - World space size of the object
|
|
1551
|
+
* @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
|
|
1552
|
+
* @param {Number} [angle=0] - Angle the object is rotated by
|
|
1553
|
+
* @param {Color} [color=Color()] - Color to apply to tile when rendered
|
|
1554
|
+
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
1363
1555
|
*/
|
|
1364
|
-
constructor(pos=vec2(), size=vec2(1),
|
|
1556
|
+
constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color, renderOrder=0)
|
|
1365
1557
|
{
|
|
1366
1558
|
// set passed in params
|
|
1367
1559
|
ASSERT(isVector2(pos) && isVector2(size)); // ensure pos and size are vec2s
|
|
1560
|
+
ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
|
|
1561
|
+
ASSERT(!(renderOrder instanceof Color)); // prevent old style calls
|
|
1562
|
+
// to fix old calls, replace with tile(tileIndex, tileSize)
|
|
1368
1563
|
|
|
1369
1564
|
/** @property {Vector2} - World space position of the object */
|
|
1370
1565
|
this.pos = pos.copy();
|
|
@@ -1372,10 +1567,8 @@ class EngineObject
|
|
|
1372
1567
|
this.size = size;
|
|
1373
1568
|
/** @property {Vector2} - Size of object used for drawing, uses size if not set */
|
|
1374
1569
|
this.drawSize;
|
|
1375
|
-
/** @property {
|
|
1376
|
-
this.
|
|
1377
|
-
/** @property {Vector2} - Size of tile in source pixels */
|
|
1378
|
-
this.tileSize = tileSize;
|
|
1570
|
+
/** @property {TileInfo} - Tile info to render object (undefined is untextured) */
|
|
1571
|
+
this.tileInfo = tileInfo;
|
|
1379
1572
|
/** @property {Number} - Angle to rotate the object */
|
|
1380
1573
|
this.angle = angle;
|
|
1381
1574
|
/** @property {Color} - Color to apply when rendered */
|
|
@@ -1591,7 +1784,7 @@ class EngineObject
|
|
|
1591
1784
|
render()
|
|
1592
1785
|
{
|
|
1593
1786
|
// default object render
|
|
1594
|
-
drawTile(this.pos, this.drawSize || this.size, this.
|
|
1787
|
+
drawTile(this.pos, this.drawSize || this.size, this.tileInfo, this.color, this.angle, this.mirror, this.additiveColor);
|
|
1595
1788
|
}
|
|
1596
1789
|
|
|
1597
1790
|
/** Destroy this object, destroy it's children, detach it's parent, and mark it for removal */
|
|
@@ -1746,13 +1939,109 @@ let overlayContext;
|
|
|
1746
1939
|
* @memberof Draw */
|
|
1747
1940
|
let mainCanvasSize = vec2();
|
|
1748
1941
|
|
|
1749
|
-
/**
|
|
1750
|
-
* @type {
|
|
1942
|
+
/** Array containing texture info for batch rendering system
|
|
1943
|
+
* @type {Array}
|
|
1751
1944
|
* @memberof Draw */
|
|
1752
|
-
|
|
1945
|
+
let textureInfos = [];
|
|
1753
1946
|
|
|
1754
1947
|
// Engine internal variables not exposed to documentation
|
|
1755
|
-
let
|
|
1948
|
+
let drawCount;
|
|
1949
|
+
|
|
1950
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1951
|
+
|
|
1952
|
+
/**
|
|
1953
|
+
* Create a tile info object
|
|
1954
|
+
* - This can take vecs or floats for easier use and conversion
|
|
1955
|
+
* - If an index is passed in, the tile size and index will determine the position
|
|
1956
|
+
* @param {(Number|Vector2)} [pos=Vector2()] - Top left corner of tile in pixels or index
|
|
1957
|
+
* @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
|
|
1958
|
+
* @param {Number} [textureIndex=0] - Texture index to use
|
|
1959
|
+
* @return {TileInfo}
|
|
1960
|
+
* @example
|
|
1961
|
+
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
1962
|
+
* tile(5, 8) // a tile at index 5 using a tile size of 8
|
|
1963
|
+
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
1964
|
+
* tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
|
|
1965
|
+
* @memberof Draw
|
|
1966
|
+
*/
|
|
1967
|
+
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
1968
|
+
{
|
|
1969
|
+
// if size is a number, make it a vector
|
|
1970
|
+
if (size.x == undefined)
|
|
1971
|
+
{
|
|
1972
|
+
ASSERT(size > 0);
|
|
1973
|
+
size = vec2(size);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
// if pos is a number, use it as a tile index
|
|
1977
|
+
if (pos.x == undefined)
|
|
1978
|
+
{
|
|
1979
|
+
const textureInfo = textureInfos[textureIndex];
|
|
1980
|
+
if (textureInfo)
|
|
1981
|
+
{
|
|
1982
|
+
const cols = textureInfo.size.x / size.x |0;
|
|
1983
|
+
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
1984
|
+
}
|
|
1985
|
+
else
|
|
1986
|
+
pos = vec2();
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
// return a tile info object
|
|
1990
|
+
return new TileInfo(pos, size, textureIndex);
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
/**
|
|
1994
|
+
* Tile Info - Stores info about how to draw a tile
|
|
1995
|
+
*/
|
|
1996
|
+
class TileInfo
|
|
1997
|
+
{
|
|
1998
|
+
/** Create a tile info object
|
|
1999
|
+
* @param {Vector2} [pos=Vector2()] - Top left corner of tile in pixels
|
|
2000
|
+
* @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
|
|
2001
|
+
* @param {Number} [textureIndex=0] - Texture index to use
|
|
2002
|
+
*/
|
|
2003
|
+
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
2004
|
+
{
|
|
2005
|
+
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
2006
|
+
this.pos = pos;
|
|
2007
|
+
/** @property {Vector2} - Size of tile in pixels */
|
|
2008
|
+
this.size = size;
|
|
2009
|
+
/** @property {Number} - Texture index to use */
|
|
2010
|
+
this.textureIndex = textureIndex;
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
/** Returns an offset copy of this tile, useful for animation
|
|
2014
|
+
* @param {Vector2} offset - Offset to apply in pixels
|
|
2015
|
+
* @return {TileInfo}
|
|
2016
|
+
*/
|
|
2017
|
+
offset(offset)
|
|
2018
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
2019
|
+
|
|
2020
|
+
/** Returns the texture info for this tile
|
|
2021
|
+
* @return {TextureInfo}
|
|
2022
|
+
*/
|
|
2023
|
+
getTextureInfo()
|
|
2024
|
+
{ return textureInfos[this.textureIndex]; }
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
/** Texture Info - Stores info about each texture */
|
|
2028
|
+
class TextureInfo
|
|
2029
|
+
{
|
|
2030
|
+
// create a TextureInfo, called automatically by the engine
|
|
2031
|
+
constructor(image)
|
|
2032
|
+
{
|
|
2033
|
+
/** @property {CanvasImageSource} - image source */
|
|
2034
|
+
this.image = image;
|
|
2035
|
+
/** @property {Vector2} - size of the image */
|
|
2036
|
+
this.size = vec2(image.width, image.height);
|
|
2037
|
+
/** @property {WebGLTexture} - webgl texture */
|
|
2038
|
+
this.glTexture = glEnable && glCreateTexture(image);
|
|
2039
|
+
/** @property {Vector2} - size to adjust tile to fix bleeding */
|
|
2040
|
+
this.fixBleedSize = vec2(tileFixBleedScale).divide(this.size);
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1756
2045
|
|
|
1757
2046
|
/** Convert from screen to world space coordinates
|
|
1758
2047
|
* @param {Vector2} screenPos
|
|
@@ -1783,7 +2072,7 @@ function worldToScreen(worldPos)
|
|
|
1783
2072
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
1784
2073
|
* @param {Vector2} pos - Center of the tile in world space
|
|
1785
2074
|
* @param {Vector2} [size=Vector2(1,1)] - Size of the tile in world space
|
|
1786
|
-
* @param {
|
|
2075
|
+
* @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
|
|
1787
2076
|
* @param {Vector2} [tileSize=tileSizeDefault] - Tile size in source pixels
|
|
1788
2077
|
* @param {Color} [color=Color()] - Color to modulate with
|
|
1789
2078
|
* @param {Number} [angle=0] - Angle to rotate by
|
|
@@ -1791,13 +2080,18 @@ function worldToScreen(worldPos)
|
|
|
1791
2080
|
* @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
|
|
1792
2081
|
* @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
1793
2082
|
* @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
|
|
2083
|
+
* @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
|
|
1794
2084
|
* @memberof Draw */
|
|
1795
|
-
function drawTile(pos, size=vec2(1),
|
|
1796
|
-
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
|
|
2085
|
+
function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
2086
|
+
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace, context)
|
|
1797
2087
|
{
|
|
2088
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
2089
|
+
ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
|
|
2090
|
+
// to fix old calls, replace with tile(tileIndex, tileSize)
|
|
2091
|
+
|
|
1798
2092
|
showWatermark && ++drawCount;
|
|
1799
|
-
|
|
1800
|
-
if (
|
|
2093
|
+
const textureInfo = tileInfo && tileInfo.getTextureInfo();
|
|
2094
|
+
if (useWebGL)
|
|
1801
2095
|
{
|
|
1802
2096
|
if (screenSpace)
|
|
1803
2097
|
{
|
|
@@ -1805,48 +2099,50 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
1805
2099
|
pos = screenToWorld(pos);
|
|
1806
2100
|
size = size.scale(1/cameraScale);
|
|
1807
2101
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
// if negative tile index or image not found, force untextured
|
|
1811
|
-
glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
|
|
1812
|
-
}
|
|
1813
|
-
else
|
|
2102
|
+
|
|
2103
|
+
if (textureInfo)
|
|
1814
2104
|
{
|
|
1815
2105
|
// calculate uvs and render
|
|
1816
|
-
const
|
|
1817
|
-
const
|
|
1818
|
-
const
|
|
1819
|
-
const
|
|
1820
|
-
|
|
2106
|
+
const x = tileInfo.pos.x / textureInfo.size.x;
|
|
2107
|
+
const y = tileInfo.pos.y / textureInfo.size.y;
|
|
2108
|
+
const w = tileInfo.size.x / textureInfo.size.x;
|
|
2109
|
+
const h = tileInfo.size.y / textureInfo.size.y;
|
|
2110
|
+
const tileImageFixBleed = textureInfo.fixBleedSize;
|
|
2111
|
+
glSetTexture(textureInfo.glTexture);
|
|
1821
2112
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
1822
|
-
|
|
1823
|
-
|
|
2113
|
+
x + tileImageFixBleed.x, y + tileImageFixBleed.y,
|
|
2114
|
+
x - tileImageFixBleed.x + w, y - tileImageFixBleed.y + h,
|
|
1824
2115
|
color.rgbaInt(), additiveColor.rgbaInt());
|
|
1825
2116
|
}
|
|
2117
|
+
else
|
|
2118
|
+
{
|
|
2119
|
+
// if no tile info, force untextured
|
|
2120
|
+
glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
|
|
2121
|
+
}
|
|
1826
2122
|
}
|
|
1827
2123
|
else
|
|
1828
2124
|
{
|
|
1829
2125
|
// normal canvas 2D rendering method (slower)
|
|
1830
2126
|
drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
1831
2127
|
{
|
|
1832
|
-
if (
|
|
2128
|
+
if (textureInfo)
|
|
1833
2129
|
{
|
|
1834
|
-
//
|
|
1835
|
-
|
|
1836
|
-
|
|
2130
|
+
// calculate uvs and render
|
|
2131
|
+
const x = tileInfo.pos.x + tileFixBleedScale;
|
|
2132
|
+
const y = tileInfo.pos.y + tileFixBleedScale;
|
|
2133
|
+
const w = tileInfo.size.x - 2*tileFixBleedScale;
|
|
2134
|
+
const h = tileInfo.size.y - 2*tileFixBleedScale;
|
|
2135
|
+
context.globalAlpha = color.a; // only alpha is supported
|
|
2136
|
+
context.drawImage(textureInfo.image, x, y, w, h, -.5, -.5, 1, 1);
|
|
2137
|
+
context.globalAlpha = 1; // set back to full alpha
|
|
1837
2138
|
}
|
|
1838
2139
|
else
|
|
1839
2140
|
{
|
|
1840
|
-
//
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
const sY = (tileIndex/cols|0)*tileSize.y + tileFixBleedScale;
|
|
1844
|
-
const sWidth = tileSize.x - 2*tileFixBleedScale;
|
|
1845
|
-
const sHeight = tileSize.y - 2*tileFixBleedScale;
|
|
1846
|
-
context.globalAlpha = color.a; // only alpha is supported
|
|
1847
|
-
context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
|
|
2141
|
+
// if no tile info, force untextured
|
|
2142
|
+
context.fillStyle = color;
|
|
2143
|
+
context.fillRect(-.5, -.5, 1, 1);
|
|
1848
2144
|
}
|
|
1849
|
-
},
|
|
2145
|
+
}, screenSpace, context);
|
|
1850
2146
|
}
|
|
1851
2147
|
}
|
|
1852
2148
|
|
|
@@ -1857,28 +2153,36 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
1857
2153
|
* @param {Number} [angle=0]
|
|
1858
2154
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1859
2155
|
* @param {Boolean} [screenSpace=0]
|
|
2156
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
1860
2157
|
* @memberof Draw */
|
|
1861
|
-
function drawRect(pos, size, color, angle, useWebGL, screenSpace)
|
|
1862
|
-
{
|
|
2158
|
+
function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
2159
|
+
{
|
|
2160
|
+
drawTile(pos, size, undefined, color, angle, 0, undefined, useWebGL, screenSpace, context);
|
|
2161
|
+
}
|
|
1863
2162
|
|
|
1864
2163
|
/** Draw colored polygon using passed in points
|
|
1865
2164
|
* @param {Array} points - Array of Vector2 points
|
|
1866
2165
|
* @param {Color} [color=Color()]
|
|
1867
2166
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1868
2167
|
* @param {Boolean} [screenSpace=0]
|
|
2168
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
1869
2169
|
* @memberof Draw */
|
|
1870
|
-
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
2170
|
+
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace, context)
|
|
1871
2171
|
{
|
|
2172
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
2173
|
+
|
|
1872
2174
|
if (useWebGL)
|
|
1873
2175
|
glDrawPoints(screenSpace ? points.map(screenToWorld) : points, color.rgbaInt());
|
|
1874
2176
|
else
|
|
1875
2177
|
{
|
|
1876
2178
|
// draw using canvas
|
|
1877
|
-
|
|
1878
|
-
|
|
2179
|
+
if (!context)
|
|
2180
|
+
context = mainContext;
|
|
2181
|
+
context.fillStyle = color;
|
|
2182
|
+
context.beginPath();
|
|
1879
2183
|
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
1880
|
-
|
|
1881
|
-
|
|
2184
|
+
context.lineTo(point.x, point.y);
|
|
2185
|
+
context.fill();
|
|
1882
2186
|
}
|
|
1883
2187
|
}
|
|
1884
2188
|
|
|
@@ -1889,12 +2193,13 @@ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
|
1889
2193
|
* @param {Color} [color=Color()]
|
|
1890
2194
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1891
2195
|
* @param {Boolean} [screenSpace=0]
|
|
2196
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
1892
2197
|
* @memberof Draw */
|
|
1893
|
-
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
|
|
2198
|
+
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
|
|
1894
2199
|
{
|
|
1895
2200
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
1896
2201
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
1897
|
-
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace);
|
|
2202
|
+
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace, context);
|
|
1898
2203
|
}
|
|
1899
2204
|
|
|
1900
2205
|
/** Draw directly to a 2d canvas context in world space
|
|
@@ -1903,10 +2208,10 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
|
|
|
1903
2208
|
* @param {Number} angle
|
|
1904
2209
|
* @param {Boolean} mirror
|
|
1905
2210
|
* @param {Function} drawFunction
|
|
1906
|
-
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1907
2211
|
* @param {Boolean} [screenSpace=0]
|
|
2212
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1908
2213
|
* @memberof Draw */
|
|
1909
|
-
function drawCanvas2D(pos, size, angle, mirror, drawFunction, context
|
|
2214
|
+
function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, context=mainContext)
|
|
1910
2215
|
{
|
|
1911
2216
|
if (!screenSpace)
|
|
1912
2217
|
{
|
|
@@ -1925,13 +2230,19 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
|
|
|
1925
2230
|
/** Enable normal or additive blend mode
|
|
1926
2231
|
* @param {Boolean} [additive=0]
|
|
1927
2232
|
* @param {Boolean} [useWebGL=glEnable]
|
|
2233
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1928
2234
|
* @memberof Draw */
|
|
1929
|
-
function setBlendMode(additive, useWebGL=glEnable)
|
|
2235
|
+
function setBlendMode(additive, useWebGL=glEnable, context)
|
|
1930
2236
|
{
|
|
1931
|
-
|
|
1932
|
-
|
|
2237
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
2238
|
+
if (useWebGL)
|
|
2239
|
+
glAdditive = additive;
|
|
1933
2240
|
else
|
|
1934
|
-
|
|
2241
|
+
{
|
|
2242
|
+
if (!context)
|
|
2243
|
+
context = mainContext;
|
|
2244
|
+
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
2245
|
+
}
|
|
1935
2246
|
}
|
|
1936
2247
|
|
|
1937
2248
|
/** Draw text on overlay canvas in world space
|
|
@@ -2004,10 +2315,9 @@ class FontImage
|
|
|
2004
2315
|
* @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
|
|
2005
2316
|
* @param {Vector2} [tileSize=vec2(8)] - Size of the font source tiles
|
|
2006
2317
|
* @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
|
|
2007
|
-
* @param {Number} [startTileIndex=0] - Tile index in image where font starts
|
|
2008
2318
|
* @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
|
|
2009
2319
|
*/
|
|
2010
|
-
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1),
|
|
2320
|
+
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
|
|
2011
2321
|
{
|
|
2012
2322
|
// load default font image
|
|
2013
2323
|
if (!engineFontImage)
|
|
@@ -2016,7 +2326,6 @@ class FontImage
|
|
|
2016
2326
|
this.image = image || engineFontImage;
|
|
2017
2327
|
this.tileSize = tileSize;
|
|
2018
2328
|
this.paddingSize = paddingSize;
|
|
2019
|
-
this.startTileIndex = startTileIndex;
|
|
2020
2329
|
this.context = context;
|
|
2021
2330
|
}
|
|
2022
2331
|
|
|
@@ -2057,7 +2366,7 @@ class FontImage
|
|
|
2057
2366
|
charCode = 127; // unknown character
|
|
2058
2367
|
|
|
2059
2368
|
// get the character source location and draw it
|
|
2060
|
-
const tile =
|
|
2369
|
+
const tile = charCode - 32;
|
|
2061
2370
|
const x = tile % cols;
|
|
2062
2371
|
const y = tile / cols |0;
|
|
2063
2372
|
const drawPos = pos.add(vec2(j,i).multiply(drawSize));
|
|
@@ -2089,8 +2398,7 @@ function toggleFullscreen()
|
|
|
2089
2398
|
}
|
|
2090
2399
|
else if (document.body.requestFullscreen)
|
|
2091
2400
|
document.body.requestFullscreen();
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2401
|
+
}
|
|
2094
2402
|
/**
|
|
2095
2403
|
* LittleJS Input System
|
|
2096
2404
|
* - Tracks keyboard down, pressed, and released
|
|
@@ -2586,7 +2894,8 @@ class Sound
|
|
|
2586
2894
|
if (zzfxSound)
|
|
2587
2895
|
{
|
|
2588
2896
|
// generate zzfx sound now for fast playback
|
|
2589
|
-
this.randomness = zzfxSound[1]
|
|
2897
|
+
this.randomness = zzfxSound[1];
|
|
2898
|
+
zzfxSound[1] = 0; // generate without randomness
|
|
2590
2899
|
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
2591
2900
|
this.sampleRate = zzfxR;
|
|
2592
2901
|
}
|
|
@@ -3248,7 +3557,7 @@ class TileLayerData
|
|
|
3248
3557
|
}
|
|
3249
3558
|
|
|
3250
3559
|
/**
|
|
3251
|
-
* Tile
|
|
3560
|
+
* Tile Layer - cached rendering system for tile layers
|
|
3252
3561
|
* - Each Tile layer is rendered to an off screen canvas
|
|
3253
3562
|
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
3254
3563
|
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
@@ -3264,13 +3573,13 @@ class TileLayer extends EngineObject
|
|
|
3264
3573
|
/** Create a tile layer object
|
|
3265
3574
|
* @param {Vector2} [position=Vector2()] - World space position
|
|
3266
3575
|
* @param {Vector2} [size=tileCollisionSize] - World space size
|
|
3267
|
-
* @param {
|
|
3576
|
+
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
3268
3577
|
* @param {Vector2} [scale=Vector2(1,1)] - How much to scale this layer when rendered
|
|
3269
3578
|
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
3270
3579
|
*/
|
|
3271
|
-
constructor(pos, size=tileCollisionSize,
|
|
3580
|
+
constructor(pos, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderOrder=0)
|
|
3272
3581
|
{
|
|
3273
|
-
super(pos, size,
|
|
3582
|
+
super(pos, size, tileInfo, 0, undefined, renderOrder);
|
|
3274
3583
|
|
|
3275
3584
|
/** @property {HTMLCanvasElement} - The canvas used by this tile layer */
|
|
3276
3585
|
this.canvas = document.createElement('canvas');
|
|
@@ -3347,13 +3656,13 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3347
3656
|
mainCanvas = this.canvas;
|
|
3348
3657
|
mainContext = this.context;
|
|
3349
3658
|
cameraPos = this.size.scale(.5);
|
|
3350
|
-
cameraScale = this.
|
|
3659
|
+
cameraScale = this.tileInfo.size.x;
|
|
3351
3660
|
|
|
3352
3661
|
if (clear)
|
|
3353
3662
|
{
|
|
3354
3663
|
// clear and set size
|
|
3355
|
-
mainCanvas.width = this.size.x * this.
|
|
3356
|
-
mainCanvas.height = this.size.y * this.
|
|
3664
|
+
mainCanvas.width = this.size.x * this.tileInfo.size.x;
|
|
3665
|
+
mainCanvas.height = this.size.y * this.tileInfo.size.y;
|
|
3357
3666
|
}
|
|
3358
3667
|
|
|
3359
3668
|
// begin a new render for the tile canvas
|
|
@@ -3384,7 +3693,8 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3384
3693
|
if (d.tile != undefined)
|
|
3385
3694
|
{
|
|
3386
3695
|
ASSERT(mainContext == this.context); // must call redrawStart() before drawing tiles
|
|
3387
|
-
|
|
3696
|
+
const tileInfo = tile(d.tile, this.tileInfo.size, this.tileInfo.textureIndex);
|
|
3697
|
+
drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
|
|
3388
3698
|
}
|
|
3389
3699
|
}
|
|
3390
3700
|
|
|
@@ -3406,8 +3716,8 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3406
3716
|
{
|
|
3407
3717
|
const context = this.context;
|
|
3408
3718
|
context.save();
|
|
3409
|
-
pos = pos.subtract(this.pos).multiply(this.
|
|
3410
|
-
size = size.multiply(this.
|
|
3719
|
+
pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
|
|
3720
|
+
size = size.multiply(this.tileInfo.size);
|
|
3411
3721
|
context.translate(pos.x, this.canvas.height - pos.y);
|
|
3412
3722
|
context.rotate(angle);
|
|
3413
3723
|
context.scale(mirror ? -size.x : size.x, size.y);
|
|
@@ -3418,28 +3728,28 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3418
3728
|
/** Draw a tile directly onto the layer canvas
|
|
3419
3729
|
* @param {Vector2} pos
|
|
3420
3730
|
* @param {Vector2} [size=Vector2(1,1)]
|
|
3421
|
-
* @param {
|
|
3422
|
-
* @param {Vector2} [tileSize=tileSizeDefault]
|
|
3731
|
+
* @param {TileInfo} [tileInfo]
|
|
3423
3732
|
* @param {Color} [color=Color()]
|
|
3424
3733
|
* @param {Number} [angle=0]
|
|
3425
3734
|
* @param {Boolean} [mirror=0] */
|
|
3426
|
-
drawTile(pos, size=vec2(1),
|
|
3735
|
+
drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle, mirror)
|
|
3427
3736
|
{
|
|
3428
3737
|
this.drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
3429
3738
|
{
|
|
3430
|
-
|
|
3739
|
+
const textureInfo = tileInfo && tileInfo.getTextureInfo();
|
|
3740
|
+
if (textureInfo)
|
|
3431
3741
|
{
|
|
3432
|
-
//
|
|
3433
|
-
context.
|
|
3434
|
-
|
|
3742
|
+
context.globalAlpha = color.a; // only alpha is supported
|
|
3743
|
+
context.drawImage(textureInfo.image,
|
|
3744
|
+
tileInfo.pos.x, tileInfo.pos.y,
|
|
3745
|
+
tileInfo.size.x, tileInfo.size.y, -.5, -.5, 1, 1);
|
|
3746
|
+
context.globalAlpha = 1;
|
|
3435
3747
|
}
|
|
3436
3748
|
else
|
|
3437
3749
|
{
|
|
3438
|
-
|
|
3439
|
-
context.
|
|
3440
|
-
context.
|
|
3441
|
-
(tileIndex%cols)*tileSize.x, (tileIndex/cols|0)*tileSize.y,
|
|
3442
|
-
tileSize.x, tileSize.y, -.5, -.5, 1, 1);
|
|
3750
|
+
// untextured
|
|
3751
|
+
context.fillStyle = color;
|
|
3752
|
+
context.fillRect(-.5, -.5, 1, 1);
|
|
3443
3753
|
}
|
|
3444
3754
|
});
|
|
3445
3755
|
}
|
|
@@ -3467,7 +3777,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3467
3777
|
* let particleEmiter = new ParticleEmitter
|
|
3468
3778
|
* (
|
|
3469
3779
|
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
3470
|
-
* 0,
|
|
3780
|
+
* tile(0, 16), // tileInfo
|
|
3471
3781
|
* new Color(1,1,1), new Color(0,0,0), // colorStartA, colorStartB
|
|
3472
3782
|
* new Color(1,1,1,0), new Color(0,0,0,0), // colorEndA, colorEndB
|
|
3473
3783
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
@@ -3484,8 +3794,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3484
3794
|
* @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
|
|
3485
3795
|
* @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
|
|
3486
3796
|
* @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
|
|
3487
|
-
* @param {
|
|
3488
|
-
* @param {Vector2} [tileSize=tileSizeDefault] - Tile size for particles
|
|
3797
|
+
* @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
|
|
3489
3798
|
* @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
|
|
3490
3799
|
* @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
|
|
3491
3800
|
* @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
|
|
@@ -3515,8 +3824,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3515
3824
|
emitTime = 0,
|
|
3516
3825
|
emitRate = 100,
|
|
3517
3826
|
emitConeAngle = PI,
|
|
3518
|
-
|
|
3519
|
-
tileSize = tileSizeDefault,
|
|
3827
|
+
tileInfo,
|
|
3520
3828
|
colorStartA = new Color,
|
|
3521
3829
|
colorStartB = new Color,
|
|
3522
3830
|
colorEndA = new Color(1,1,1,0),
|
|
@@ -3539,7 +3847,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3539
3847
|
localSpace
|
|
3540
3848
|
)
|
|
3541
3849
|
{
|
|
3542
|
-
super(pos, vec2(),
|
|
3850
|
+
super(pos, vec2(), tileInfo, angle, undefined, renderOrder);
|
|
3543
3851
|
|
|
3544
3852
|
// emitter settings
|
|
3545
3853
|
/** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
@@ -3638,7 +3946,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3638
3946
|
angle += this.angle;
|
|
3639
3947
|
}
|
|
3640
3948
|
|
|
3641
|
-
const particle = new Particle(pos, this.
|
|
3949
|
+
const particle = new Particle(pos, this.tileInfo, this.tileSize, angle);
|
|
3642
3950
|
|
|
3643
3951
|
// randomness scales each paremeter by a percentage
|
|
3644
3952
|
const randomness = this.randomness;
|
|
@@ -3698,12 +4006,11 @@ class Particle extends EngineObject
|
|
|
3698
4006
|
/**
|
|
3699
4007
|
* Create a particle with the given settings
|
|
3700
4008
|
* @param {Vector2} position - World space position of the particle
|
|
3701
|
-
* @param {
|
|
3702
|
-
* @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
|
|
4009
|
+
* @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
|
|
3703
4010
|
* @param {Number} [angle=0] - Angle to rotate the particle
|
|
3704
4011
|
*/
|
|
3705
|
-
constructor(pos,
|
|
3706
|
-
{ super(pos, vec2(),
|
|
4012
|
+
constructor(pos, tileInfo, angle)
|
|
4013
|
+
{ super(pos, vec2(), tileInfo, angle); }
|
|
3707
4014
|
|
|
3708
4015
|
/** Render the particle, automatically called each frame, sorted by renderOrder */
|
|
3709
4016
|
render()
|
|
@@ -3737,14 +4044,17 @@ class Particle extends EngineObject
|
|
|
3737
4044
|
if (this.localSpaceEmitter)
|
|
3738
4045
|
velocity = velocity.rotate(-this.localSpaceEmitter.angle);
|
|
3739
4046
|
const speed = velocity.length();
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
4047
|
+
if (speed)
|
|
4048
|
+
{
|
|
4049
|
+
const direction = velocity.scale(1/speed);
|
|
4050
|
+
const trailLength = speed * this.trailScale;
|
|
4051
|
+
size.y = max(size.x, trailLength);
|
|
4052
|
+
angle = direction.angle();
|
|
4053
|
+
drawTile(pos.add(direction.multiply(vec2(0,-trailLength/2))), size, this.tileInfo, color, angle, this.mirror);
|
|
4054
|
+
}
|
|
3745
4055
|
}
|
|
3746
4056
|
else
|
|
3747
|
-
drawTile(pos, size, this.
|
|
4057
|
+
drawTile(pos, size, this.tileInfo, color, angle, this.mirror);
|
|
3748
4058
|
this.additive && setBlendMode();
|
|
3749
4059
|
debugParticles && debugRect(pos, size, '#f005', 0, angle);
|
|
3750
4060
|
|
|
@@ -3791,7 +4101,7 @@ function medalsInit(saveName)
|
|
|
3791
4101
|
}
|
|
3792
4102
|
|
|
3793
4103
|
/**
|
|
3794
|
-
* Medal
|
|
4104
|
+
* Medal - Tracks an unlockable medal
|
|
3795
4105
|
* @example
|
|
3796
4106
|
* // create a medal
|
|
3797
4107
|
* const medal_example = new Medal(0, 'Example Medal', 'More info about the medal goes here.', '🎖️');
|
|
@@ -3804,7 +4114,7 @@ function medalsInit(saveName)
|
|
|
3804
4114
|
*/
|
|
3805
4115
|
class Medal
|
|
3806
4116
|
{
|
|
3807
|
-
/** Create
|
|
4117
|
+
/** Create a medal object and adds it to the list of medals
|
|
3808
4118
|
* @param {Number} id - The unique identifier of the medal
|
|
3809
4119
|
* @param {String} name - Name of the medal
|
|
3810
4120
|
* @param {String} [description] - Description of the medal
|
|
@@ -3916,33 +4226,33 @@ let newgrounds;
|
|
|
3916
4226
|
/** This can used to enable Newgrounds functionality
|
|
3917
4227
|
* @param {Number} app_id - The newgrounds App ID
|
|
3918
4228
|
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
4229
|
+
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher
|
|
3919
4230
|
* @memberof Medals */
|
|
3920
|
-
function newgroundsInit(app_id, cipher
|
|
4231
|
+
function newgroundsInit(app_id, cipher, cryptoJS)
|
|
4232
|
+
{ newgrounds = new Newgrounds(app_id, cipher, cryptoJS); }
|
|
3921
4233
|
|
|
3922
4234
|
/**
|
|
3923
4235
|
* Newgrounds API wrapper object
|
|
3924
4236
|
* @example
|
|
3925
|
-
* // create a newgrounds object, replace the app id
|
|
4237
|
+
* // create a newgrounds object, replace the app id with your own
|
|
3926
4238
|
* const app_id = '53123:1ZuSTQ9l';
|
|
3927
|
-
*
|
|
3928
|
-
* newgrounds = new Newgrounds(app_id, cipher);
|
|
4239
|
+
* newgrounds = new Newgrounds(app_id);
|
|
3929
4240
|
*/
|
|
3930
4241
|
class Newgrounds
|
|
3931
4242
|
{
|
|
3932
4243
|
/** Create a newgrounds object
|
|
3933
4244
|
* @param {Number} app_id - The newgrounds App ID
|
|
3934
|
-
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
3935
|
-
|
|
4245
|
+
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
4246
|
+
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher */
|
|
4247
|
+
constructor(app_id, cipher, cryptoJS)
|
|
3936
4248
|
{
|
|
3937
|
-
ASSERT(!newgrounds && app_id);
|
|
4249
|
+
ASSERT(!newgrounds && app_id); // can only be one newgrounds object
|
|
4250
|
+
ASSERT(!cipher || cryptoJS); // must provide cryptojs if there is a cipher
|
|
3938
4251
|
|
|
3939
4252
|
this.app_id = app_id;
|
|
3940
4253
|
this.cipher = cipher;
|
|
4254
|
+
this.cryptoJS = cryptoJS;
|
|
3941
4255
|
this.host = location ? location.hostname : '';
|
|
3942
|
-
|
|
3943
|
-
// create an instance of CryptoJS for encrypted calls
|
|
3944
|
-
if (cipher)
|
|
3945
|
-
this.cryptoJS = this.CryptoJS();
|
|
3946
4256
|
|
|
3947
4257
|
// get session id from url search params
|
|
3948
4258
|
const url = new URL(location.href);
|
|
@@ -4046,38 +4356,6 @@ class Newgrounds
|
|
|
4046
4356
|
debugMedals && console.log(xmlHttp.responseText);
|
|
4047
4357
|
return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
|
|
4048
4358
|
}
|
|
4049
|
-
|
|
4050
|
-
CryptoJS()
|
|
4051
|
-
{
|
|
4052
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
4053
|
-
// Crypto-JS - https://github.com/brix/crypto-js - MIT License
|
|
4054
|
-
//
|
|
4055
|
-
// [The MIT License (MIT)](http://opensource.org/licenses/MIT)
|
|
4056
|
-
//
|
|
4057
|
-
// Copyright (c) 2009-2013 Jeff Mott
|
|
4058
|
-
// Copyright (c) 2013-2016 Evan Vosberg
|
|
4059
|
-
//
|
|
4060
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4061
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
4062
|
-
// in the Software without restriction, including without limitation the rights
|
|
4063
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
4064
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
4065
|
-
// furnished to do so, subject to the following conditions:
|
|
4066
|
-
//
|
|
4067
|
-
// The above copyright notice and this permission notice shall be included in
|
|
4068
|
-
// all copies or substantial portions of the Software.
|
|
4069
|
-
//
|
|
4070
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
4071
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
4072
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
4073
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
4074
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
4075
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
4076
|
-
// THE SOFTWARE.
|
|
4077
|
-
return eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",...']charCodeAtUinyxpf',"for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],1<<17,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(1<<15),new Uint8Array(51e6),0,0,0,0));
|
|
4078
|
-
// end of Crypto-JS
|
|
4079
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
4080
|
-
}
|
|
4081
4359
|
}
|
|
4082
4360
|
/**
|
|
4083
4361
|
* LittleJS WebGL Interface
|
|
@@ -4087,6 +4365,7 @@ class Newgrounds
|
|
|
4087
4365
|
* - Can be disabled with glEnable to revert to 2D canvas rendering
|
|
4088
4366
|
* - Batches sprite rendering on GPU for incredibly fast performance
|
|
4089
4367
|
* - Sprite transform math is done in the shader where possible
|
|
4368
|
+
* - Supports shadertoy style post processing shaders
|
|
4090
4369
|
* @namespace WebGL
|
|
4091
4370
|
*/
|
|
4092
4371
|
|
|
@@ -4102,11 +4381,6 @@ let glCanvas;
|
|
|
4102
4381
|
* @memberof WebGL */
|
|
4103
4382
|
let glContext;
|
|
4104
4383
|
|
|
4105
|
-
/** Main tile sheet texture automatically loaded by engine
|
|
4106
|
-
* @type {WebGLTexture}
|
|
4107
|
-
* @memberof WebGL */
|
|
4108
|
-
let glTileTexture;
|
|
4109
|
-
|
|
4110
4384
|
// WebGL internal variables not exposed to documentation
|
|
4111
4385
|
let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
4112
4386
|
|
|
@@ -4115,32 +4389,33 @@ let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBat
|
|
|
4115
4389
|
// Initalize WebGL, called automatically by the engine
|
|
4116
4390
|
function glInit()
|
|
4117
4391
|
{
|
|
4118
|
-
// create the canvas and
|
|
4392
|
+
// create the canvas and textures
|
|
4119
4393
|
glCanvas = document.createElement('canvas');
|
|
4120
|
-
glContext = glCanvas.getContext('
|
|
4121
|
-
glTileTexture = glCreateTexture(tileImage);
|
|
4394
|
+
glContext = glCanvas.getContext('webgl2');
|
|
4122
4395
|
|
|
4123
4396
|
// some browsers are much faster without copying the gl buffer so we just overlay it instead
|
|
4124
4397
|
glOverlay && document.body.appendChild(glCanvas);
|
|
4125
4398
|
|
|
4126
4399
|
// setup vertex and fragment shaders
|
|
4127
4400
|
glShader = glCreateProgram(
|
|
4401
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4128
4402
|
'precision highp float;'+ // use highp for better accuracy
|
|
4129
4403
|
'uniform mat4 m;'+ // transform matrix
|
|
4130
|
-
'
|
|
4131
|
-
'
|
|
4132
|
-
'varying vec4 v,d,e;'+ // return uv, color, additiveColor
|
|
4404
|
+
'in vec4 p,c,a;'+ // position, uv, color, additiveColor
|
|
4405
|
+
'out vec4 v,d,e;'+ // return uv, color, additiveColor
|
|
4133
4406
|
'void main(){'+ // shader entry point
|
|
4134
|
-
'gl_Position=m*vec4(p,1,1);'+ // transform position
|
|
4135
|
-
'v=
|
|
4407
|
+
'gl_Position=m*vec4(p.xy,1,1);'+ // transform position
|
|
4408
|
+
'v=p;d=c;e=a;'+ // pass stuff to fragment shader
|
|
4136
4409
|
'}' // end of shader
|
|
4137
4410
|
,
|
|
4138
|
-
'
|
|
4139
|
-
'
|
|
4140
|
-
'
|
|
4141
|
-
'
|
|
4142
|
-
'
|
|
4143
|
-
'
|
|
4411
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4412
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
4413
|
+
'in vec4 v,d,e;'+ // position, uv, color, additiveColor
|
|
4414
|
+
'uniform sampler2D s;'+ // texture
|
|
4415
|
+
'out vec4 c;'+ // out color
|
|
4416
|
+
'void main(){'+ // shader entry point
|
|
4417
|
+
'c=texture(s,v.zw)*d+e;'+ // modulate texture by color plus additive
|
|
4418
|
+
'}' // end of shader
|
|
4144
4419
|
);
|
|
4145
4420
|
|
|
4146
4421
|
// init buffers
|
|
@@ -4161,10 +4436,10 @@ function glPreRender()
|
|
|
4161
4436
|
// set up the shader
|
|
4162
4437
|
glContext.useProgram(glShader);
|
|
4163
4438
|
glContext.activeTexture(gl_TEXTURE0);
|
|
4164
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture =
|
|
4439
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
|
|
4165
4440
|
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
4166
4441
|
glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
|
|
4167
|
-
|
|
4442
|
+
glAdditive = 0;
|
|
4168
4443
|
|
|
4169
4444
|
// set vertex attributes
|
|
4170
4445
|
let offset = 0;
|
|
@@ -4175,43 +4450,36 @@ function glPreRender()
|
|
|
4175
4450
|
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
4176
4451
|
offset += size*typeSize;
|
|
4177
4452
|
}
|
|
4178
|
-
initVertexAttribArray('p', gl_FLOAT, 4,
|
|
4179
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
4453
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture coords
|
|
4180
4454
|
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
4181
4455
|
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
4182
4456
|
|
|
4183
4457
|
// build the transform matrix
|
|
4184
4458
|
const sx = 2 * cameraScale / mainCanvas.width;
|
|
4185
4459
|
const sy = 2 * cameraScale / mainCanvas.height;
|
|
4460
|
+
const cx = -1 - sx*cameraPos.x;
|
|
4461
|
+
const cy = -1 - sy*cameraPos.y;
|
|
4186
4462
|
glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
|
|
4187
4463
|
new Float32Array([
|
|
4188
|
-
sx,
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4464
|
+
sx, 0, 0, 0,
|
|
4465
|
+
0, sy, 0, 0,
|
|
4466
|
+
1, 1, -1, 1,
|
|
4467
|
+
cx, cy, 0, 0
|
|
4192
4468
|
])
|
|
4193
4469
|
);
|
|
4194
4470
|
}
|
|
4195
4471
|
|
|
4196
|
-
/** Set the WebGl
|
|
4197
|
-
* @param {Boolean} [additive=0]
|
|
4198
|
-
* @memberof WebGL */
|
|
4199
|
-
function glSetBlendMode(additive)
|
|
4200
|
-
{
|
|
4201
|
-
// setup blending
|
|
4202
|
-
glAdditive = additive;
|
|
4203
|
-
}
|
|
4204
|
-
|
|
4205
|
-
/** Set the WebGl texture, not normally necessary unless multiple tile sheets are used
|
|
4472
|
+
/** Set the WebGl texture, called automatically if using multiple textures
|
|
4206
4473
|
* - This may also flush the gl buffer resulting in more draw calls and worse performance
|
|
4207
|
-
* @param {WebGLTexture}
|
|
4474
|
+
* @param {WebGLTexture} texture
|
|
4208
4475
|
* @memberof WebGL */
|
|
4209
|
-
function glSetTexture(texture
|
|
4476
|
+
function glSetTexture(texture)
|
|
4210
4477
|
{
|
|
4211
4478
|
// must flush cache with the old texture to set a new one
|
|
4212
|
-
if (texture
|
|
4213
|
-
|
|
4479
|
+
if (texture == glActiveTexture)
|
|
4480
|
+
return;
|
|
4214
4481
|
|
|
4482
|
+
glFlush();
|
|
4215
4483
|
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = texture);
|
|
4216
4484
|
}
|
|
4217
4485
|
|
|
@@ -4390,25 +4658,28 @@ function glInitPostProcess(shaderCode, includeOverlay)
|
|
|
4390
4658
|
{
|
|
4391
4659
|
ASSERT(!glPostShader); // can only have 1 post effects shader
|
|
4392
4660
|
|
|
4393
|
-
if (!shaderCode) // default shader
|
|
4394
|
-
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=
|
|
4661
|
+
if (!shaderCode) // default shader pass through
|
|
4662
|
+
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}';
|
|
4395
4663
|
|
|
4396
4664
|
// create the shader
|
|
4397
4665
|
glPostShader = glCreateProgram(
|
|
4666
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4398
4667
|
'precision highp float;'+ // use highp for better accuracy
|
|
4399
|
-
'
|
|
4668
|
+
'in vec2 p;'+ // position
|
|
4400
4669
|
'void main(){'+ // shader entry point
|
|
4401
4670
|
'gl_Position=vec4(p,1,1);'+ // set position
|
|
4402
4671
|
'}' // end of shader
|
|
4403
4672
|
,
|
|
4673
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4404
4674
|
'precision highp float;'+ // use highp for better accuracy
|
|
4405
4675
|
'uniform sampler2D iChannel0;'+ // input texture
|
|
4406
4676
|
'uniform vec3 iResolution;'+ // size of output texture
|
|
4407
4677
|
'uniform float iTime;'+ // time passed
|
|
4678
|
+
'out vec4 c;'+ // out color
|
|
4408
4679
|
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
4409
4680
|
'void main(){'+ // shader entry point
|
|
4410
|
-
'mainImage(
|
|
4411
|
-
'
|
|
4681
|
+
'mainImage(c,gl_FragCoord.xy);'+ // call post process function
|
|
4682
|
+
'c.a=1.;'+ // always use full alpha
|
|
4412
4683
|
'}' // end of shader
|
|
4413
4684
|
);
|
|
4414
4685
|
|
|
@@ -4433,8 +4704,11 @@ function glRenderPostProcess()
|
|
|
4433
4704
|
glFlush(); // clear out the buffer
|
|
4434
4705
|
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
4435
4706
|
}
|
|
4436
|
-
else
|
|
4707
|
+
else
|
|
4708
|
+
{
|
|
4709
|
+
// set the viewport
|
|
4437
4710
|
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
4711
|
+
}
|
|
4438
4712
|
|
|
4439
4713
|
if (glPostIncludeOverlay)
|
|
4440
4714
|
{
|
|
@@ -4481,7 +4755,6 @@ gl_ONE_MINUS_SRC_ALPHA = 771,
|
|
|
4481
4755
|
gl_BLEND = 3042,
|
|
4482
4756
|
gl_TEXTURE_2D = 3553,
|
|
4483
4757
|
gl_UNSIGNED_BYTE = 5121,
|
|
4484
|
-
gl_BYTE = 5120,
|
|
4485
4758
|
gl_FLOAT = 5126,
|
|
4486
4759
|
gl_RGBA = 6408,
|
|
4487
4760
|
gl_NEAREST = 9728,
|
|
@@ -4493,7 +4766,6 @@ gl_TEXTURE_WRAP_T = 10243,
|
|
|
4493
4766
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
4494
4767
|
gl_CLAMP_TO_EDGE = 33071,
|
|
4495
4768
|
gl_TEXTURE0 = 33984,
|
|
4496
|
-
gl_TEXTURE1 = 33985,
|
|
4497
4769
|
gl_ARRAY_BUFFER = 34962,
|
|
4498
4770
|
gl_STATIC_DRAW = 35044,
|
|
4499
4771
|
gl_DYNAMIC_DRAW = 35048,
|
|
@@ -4504,7 +4776,6 @@ gl_LINK_STATUS = 35714,
|
|
|
4504
4776
|
gl_UNPACK_FLIP_Y_WEBGL = 37440,
|
|
4505
4777
|
|
|
4506
4778
|
// constants for batch rendering
|
|
4507
|
-
gl_VERTICES_PER_QUAD = 6,
|
|
4508
4779
|
gl_INDICIES_PER_VERT = 6,
|
|
4509
4780
|
gl_MAX_BATCH = 1e5,
|
|
4510
4781
|
gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2, // vec2 * 2 + (char * 4) * 2
|
|
@@ -4541,7 +4812,7 @@ const engineName = 'LittleJS';
|
|
|
4541
4812
|
* @type {String}
|
|
4542
4813
|
* @default
|
|
4543
4814
|
* @memberof Engine */
|
|
4544
|
-
const engineVersion = '1.
|
|
4815
|
+
const engineVersion = '1.8.3';
|
|
4545
4816
|
|
|
4546
4817
|
/** Frames per second to update objects
|
|
4547
4818
|
* @type {Number}
|
|
@@ -4591,6 +4862,9 @@ let paused = 0;
|
|
|
4591
4862
|
* @memberof Engine */
|
|
4592
4863
|
function setPaused(_paused) { paused = _paused; }
|
|
4593
4864
|
|
|
4865
|
+
// Frame time tracking
|
|
4866
|
+
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
4867
|
+
|
|
4594
4868
|
///////////////////////////////////////////////////////////////////////////////
|
|
4595
4869
|
|
|
4596
4870
|
/** Start up LittleJS engine with your callback functions
|
|
@@ -4599,52 +4873,13 @@ function setPaused(_paused) { paused = _paused; }
|
|
|
4599
4873
|
* @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
|
|
4600
4874
|
* @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
|
|
4601
4875
|
* @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
|
|
4602
|
-
* @param {
|
|
4876
|
+
* @param {Array} [imageSources=['tiles.png']] - Image to load
|
|
4603
4877
|
* @memberof Engine */
|
|
4604
|
-
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost,
|
|
4878
|
+
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
|
|
4605
4879
|
{
|
|
4606
|
-
//
|
|
4607
|
-
tileImage.onerror = tileImage.onload = ()=>
|
|
4608
|
-
{
|
|
4609
|
-
// save tile image info
|
|
4610
|
-
tileImageFixBleed = vec2(tileFixBleedScale).divide(tileImageSize = vec2(tileImage.width, tileImage.height));
|
|
4611
|
-
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
4612
|
-
|
|
4613
|
-
// setup html
|
|
4614
|
-
const styleBody =
|
|
4615
|
-
'margin:0;overflow:hidden;' + // fill the window
|
|
4616
|
-
'background:#000;' + // set background color
|
|
4617
|
-
'touch-action:none;' + // prevent mobile pinch to resize
|
|
4618
|
-
'user-select:none;' + // prevent mobile hold to select
|
|
4619
|
-
'-webkit-user-select:none;' + // compatibility for ios
|
|
4620
|
-
'-webkit-touch-callout:none'; // compatibility for ios
|
|
4621
|
-
document.body.style = styleBody;
|
|
4622
|
-
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
4623
|
-
mainContext = mainCanvas.getContext('2d');
|
|
4624
|
-
|
|
4625
|
-
// init stuff and start engine
|
|
4626
|
-
debugInit();
|
|
4627
|
-
glEnable && glInit();
|
|
4628
|
-
|
|
4629
|
-
// create overlay canvas for hud to appear above gl canvas
|
|
4630
|
-
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
4631
|
-
overlayContext = overlayCanvas.getContext('2d');
|
|
4632
|
-
|
|
4633
|
-
// set canvas style
|
|
4634
|
-
const styleCanvas =
|
|
4635
|
-
'position:absolute;' + // position canvas
|
|
4636
|
-
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
|
|
4637
|
-
(canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
|
|
4638
|
-
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
4639
|
-
|
|
4640
|
-
gameInit();
|
|
4641
|
-
engineUpdate();
|
|
4642
|
-
};
|
|
4643
|
-
|
|
4644
|
-
// frame time tracking
|
|
4645
|
-
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
4880
|
+
ASSERT(Array.isArray(imageSources)); // pass in images as array
|
|
4646
4881
|
|
|
4647
|
-
//
|
|
4882
|
+
// internal update loop for engine
|
|
4648
4883
|
function engineUpdate(frameTimeMS=0)
|
|
4649
4884
|
{
|
|
4650
4885
|
// update time keeping
|
|
@@ -4675,9 +4910,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4675
4910
|
}
|
|
4676
4911
|
else
|
|
4677
4912
|
{
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4913
|
+
// clear canvas and set size to same as window
|
|
4914
|
+
mainCanvas.width = min(innerWidth, canvasMaxSize.x);
|
|
4915
|
+
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
4681
4916
|
}
|
|
4682
4917
|
|
|
4683
4918
|
// clear overlay canvas and set size
|
|
@@ -4709,6 +4944,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4709
4944
|
// update multiple frames if necessary in case of slow framerate
|
|
4710
4945
|
for (;frameTimeBufferMS >= 0; frameTimeBufferMS -= 1e3 / frameRate)
|
|
4711
4946
|
{
|
|
4947
|
+
// increment frame and update time
|
|
4948
|
+
time = frame++ / frameRate;
|
|
4949
|
+
|
|
4712
4950
|
// update game and objects
|
|
4713
4951
|
inputUpdate();
|
|
4714
4952
|
gameUpdate();
|
|
@@ -4756,8 +4994,51 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4756
4994
|
requestAnimationFrame(engineUpdate);
|
|
4757
4995
|
}
|
|
4758
4996
|
|
|
4759
|
-
//
|
|
4760
|
-
|
|
4997
|
+
// setup html
|
|
4998
|
+
const styleBody =
|
|
4999
|
+
'margin:0;overflow:hidden;' + // fill the window
|
|
5000
|
+
'background:#000;' + // set background color
|
|
5001
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
5002
|
+
'user-select:none;' + // prevent mobile hold to select
|
|
5003
|
+
'-webkit-user-select:none;' + // compatibility for ios
|
|
5004
|
+
'-webkit-touch-callout:none'; // compatibility for ios
|
|
5005
|
+
document.body.style = styleBody;
|
|
5006
|
+
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
5007
|
+
mainContext = mainCanvas.getContext('2d');
|
|
5008
|
+
|
|
5009
|
+
// init stuff and start engine
|
|
5010
|
+
debugInit();
|
|
5011
|
+
glEnable && glInit();
|
|
5012
|
+
|
|
5013
|
+
// create overlay canvas for hud to appear above gl canvas
|
|
5014
|
+
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
5015
|
+
overlayContext = overlayCanvas.getContext('2d');
|
|
5016
|
+
|
|
5017
|
+
// set canvas style
|
|
5018
|
+
const styleCanvas =
|
|
5019
|
+
'position:absolute;' + // position
|
|
5020
|
+
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center
|
|
5021
|
+
(canvasPixelated?'image-rendering:pixelated':''); // pixelated rendering
|
|
5022
|
+
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
5023
|
+
|
|
5024
|
+
// load all of the images
|
|
5025
|
+
Promise.all(imageSources.map((src, textureIndex)=>
|
|
5026
|
+
new Promise((resolve, reject)=>
|
|
5027
|
+
{
|
|
5028
|
+
const image = new Image;
|
|
5029
|
+
image.onerror = image.onload = ()=>
|
|
5030
|
+
{
|
|
5031
|
+
textureInfos[textureIndex] = new TextureInfo(image);
|
|
5032
|
+
resolve();
|
|
5033
|
+
}
|
|
5034
|
+
image.src = src;
|
|
5035
|
+
})
|
|
5036
|
+
)).then(()=>
|
|
5037
|
+
{
|
|
5038
|
+
// start the engine
|
|
5039
|
+
gameInit();
|
|
5040
|
+
engineUpdate();
|
|
5041
|
+
});
|
|
4761
5042
|
}
|
|
4762
5043
|
|
|
4763
5044
|
// Called automatically by engine to setup render system
|
|
@@ -4795,9 +5076,6 @@ function engineObjectsUpdate()
|
|
|
4795
5076
|
|
|
4796
5077
|
// remove destroyed objects
|
|
4797
5078
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
4798
|
-
|
|
4799
|
-
// increment frame and update time
|
|
4800
|
-
time = ++frame / frameRate;
|
|
4801
5079
|
}
|
|
4802
5080
|
|
|
4803
5081
|
/** Destroy and remove all objects
|