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
|
@@ -240,10 +240,10 @@ function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear)
|
|
|
240
240
|
* - Can be used to create a deterministic random number sequence
|
|
241
241
|
* @example
|
|
242
242
|
* let r = new RandomGenerator(123); // random number generator with seed 123
|
|
243
|
-
* let a = r.
|
|
244
|
-
* let b = r.
|
|
243
|
+
* let a = r.float(); // random value between 0 and 1
|
|
244
|
+
* let b = r.int(10); // random integer between 0 and 9
|
|
245
245
|
* r.seed = 123; // reset the seed
|
|
246
|
-
* let c = r.
|
|
246
|
+
* let c = r.float(); // the same value as a
|
|
247
247
|
*/
|
|
248
248
|
class RandomGenerator
|
|
249
249
|
{
|
|
@@ -272,18 +272,18 @@ class RandomGenerator
|
|
|
272
272
|
* @param {Number} valueA
|
|
273
273
|
* @param {Number} [valueB=0]
|
|
274
274
|
* @return {Number} */
|
|
275
|
-
int(valueA, valueB=0) { return Math.floor(this.
|
|
275
|
+
int(valueA, valueB=0) { return Math.floor(this.float(valueA, valueB)); }
|
|
276
276
|
|
|
277
277
|
/** Randomly returns either -1 or 1 deterministically
|
|
278
278
|
* @return {Number} */
|
|
279
|
-
sign() { return this.
|
|
279
|
+
sign() { return this.int(2) * 2 - 1; }
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
///////////////////////////////////////////////////////////////////////////////
|
|
283
283
|
|
|
284
284
|
/**
|
|
285
285
|
* Create a 2d vector, can take another Vector2 to copy, 2 scalars, or 1 scalar
|
|
286
|
-
* @param {Number} [x=0]
|
|
286
|
+
* @param {(Number|Vector2)} [x=0]
|
|
287
287
|
* @param {Number} [y=0]
|
|
288
288
|
* @return {Vector2}
|
|
289
289
|
* @example
|
|
@@ -767,7 +767,7 @@ let glOverlay = 1;
|
|
|
767
767
|
* @memberof Settings */
|
|
768
768
|
let tileSizeDefault = vec2(16);
|
|
769
769
|
|
|
770
|
-
/**
|
|
770
|
+
/** How many pixels smaller to draw tiles to prevent bleeding from neighbors
|
|
771
771
|
* @type {Number}
|
|
772
772
|
* @default
|
|
773
773
|
* @memberof Settings */
|
|
@@ -941,7 +941,200 @@ let medalDisplayIconSize = 50;
|
|
|
941
941
|
* @type {Boolean}
|
|
942
942
|
* @default 0
|
|
943
943
|
* @memberof Settings */
|
|
944
|
-
let medalsPreventUnlock;
|
|
944
|
+
let medalsPreventUnlock;
|
|
945
|
+
|
|
946
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
947
|
+
// Setters for global variables
|
|
948
|
+
|
|
949
|
+
/** Set position of camera in world space
|
|
950
|
+
* @param {Vector2} pos
|
|
951
|
+
* @memberof Settings */
|
|
952
|
+
function setCameraPos(pos) { cameraPos = pos; }
|
|
953
|
+
|
|
954
|
+
/** Set scale of camera in world space
|
|
955
|
+
* @param {Number} scale
|
|
956
|
+
* @memberof Settings */
|
|
957
|
+
function setCameraScale(scale) { cameraScale = scale; }
|
|
958
|
+
|
|
959
|
+
/** Set max size of the canvas
|
|
960
|
+
* @param {Vector2} size
|
|
961
|
+
* @memberof Settings */
|
|
962
|
+
function setCanvasMaxSize(size) { canvasMaxSize = size; }
|
|
963
|
+
|
|
964
|
+
/** Set fixed size of the canvas
|
|
965
|
+
* @param {Vector2} size
|
|
966
|
+
* @memberof Settings */
|
|
967
|
+
function setCanvasFixedSize(size) { canvasFixedSize = size; }
|
|
968
|
+
|
|
969
|
+
/** Disables anti aliasing for pixel art if true
|
|
970
|
+
* @param {Boolean} pixelated
|
|
971
|
+
* @memberof Settings */
|
|
972
|
+
function setCanvasPixelated(pixelated) { canvasPixelated = pixelated; }
|
|
973
|
+
|
|
974
|
+
/** Set default font used for text rendering
|
|
975
|
+
* @param {String} font
|
|
976
|
+
* @memberof Settings */
|
|
977
|
+
function setFontDefault(font) { fontDefault = font; }
|
|
978
|
+
|
|
979
|
+
/** Set if webgl rendering is enabled
|
|
980
|
+
* @param {Boolean} enable
|
|
981
|
+
* @memberof Settings */
|
|
982
|
+
function setGlEnable(enable) { glEnable = enable; }
|
|
983
|
+
|
|
984
|
+
/** Set to not composite the WebGL canvas
|
|
985
|
+
* @param {Boolean} overlay
|
|
986
|
+
* @memberof Settings */
|
|
987
|
+
function setGlOverlay(overlay) { glOverlay = overlay; }
|
|
988
|
+
|
|
989
|
+
/** Set default size of tiles in pixels
|
|
990
|
+
* @param {Vector2} size
|
|
991
|
+
* @memberof Settings */
|
|
992
|
+
function setTileSizeDefault(size) { tileSizeDefault = size; }
|
|
993
|
+
|
|
994
|
+
/** Set to prevent tile bleeding from neighbors in pixels
|
|
995
|
+
* @param {Number} scale
|
|
996
|
+
* @memberof Settings */
|
|
997
|
+
function setTileFixBleedScale(scale) { tileFixBleedScale = scale; }
|
|
998
|
+
|
|
999
|
+
/** Set if collisions between objects are enabled
|
|
1000
|
+
* @param {Boolean} enable
|
|
1001
|
+
* @memberof Settings */
|
|
1002
|
+
function setEnablePhysicsSolver(enable) { enablePhysicsSolver = enable; }
|
|
1003
|
+
|
|
1004
|
+
/** Set default object mass for collison calcuations
|
|
1005
|
+
* @param {Number} mass
|
|
1006
|
+
* @memberof Settings */
|
|
1007
|
+
function setObjectDefaultMass(mass) { objectDefaultMass = mass; }
|
|
1008
|
+
|
|
1009
|
+
/** Set how much to slow velocity by each frame
|
|
1010
|
+
* @param {Number} damping
|
|
1011
|
+
* @memberof Settings */
|
|
1012
|
+
function setObjectDefaultDamping(damp) { objectDefaultDamping = damp; }
|
|
1013
|
+
|
|
1014
|
+
/** Set how much to slow angular velocity each frame
|
|
1015
|
+
* @param {Number} damping
|
|
1016
|
+
* @memberof Settings */
|
|
1017
|
+
function setObjectDefaultAngleDamping(damp) { objectDefaultAngleDamping = damp; }
|
|
1018
|
+
|
|
1019
|
+
/** Set how much to bounce when a collision occur
|
|
1020
|
+
* @param {Number} elasticity
|
|
1021
|
+
* @memberof Settings */
|
|
1022
|
+
function setObjectDefaultElasticity(elasticity) { objectDefaultElasticity = elasticity; }
|
|
1023
|
+
|
|
1024
|
+
/** Set how much to slow when touching
|
|
1025
|
+
* @param {Number} friction
|
|
1026
|
+
* @memberof Settings */
|
|
1027
|
+
function setObjectDefaultFriction(friction) { objectDefaultFriction = friction; }
|
|
1028
|
+
|
|
1029
|
+
/** Set max speed to avoid fast objects missing collisions
|
|
1030
|
+
* @param {Number} speed
|
|
1031
|
+
* @memberof Settings */
|
|
1032
|
+
function setObjectMaxSpeed(speed) { objectMaxSpeed = speed; }
|
|
1033
|
+
|
|
1034
|
+
/** Set how much gravity to apply to objects along the Y axis
|
|
1035
|
+
* @param {Number} gravity
|
|
1036
|
+
* @memberof Settings */
|
|
1037
|
+
function setGravity(g) { gravity = g; }
|
|
1038
|
+
|
|
1039
|
+
/** Set to scales emit rate of particles
|
|
1040
|
+
* @param {Number} scale
|
|
1041
|
+
* @memberof Settings */
|
|
1042
|
+
function setParticleEmitRateScale(scale) { particleEmitRateScale = scale; }
|
|
1043
|
+
|
|
1044
|
+
/** Set if gamepads are enabled
|
|
1045
|
+
* @param {Boolean} enable
|
|
1046
|
+
* @memberof Settings */
|
|
1047
|
+
function setGamepadsEnable(enable) { gamepadsEnable = enable; }
|
|
1048
|
+
|
|
1049
|
+
/** Set if the dpad input is also routed to the left analog stick
|
|
1050
|
+
* @param {Boolean} enable
|
|
1051
|
+
* @memberof Settings */
|
|
1052
|
+
function setGamepadDirectionEmulateStick(enable) { gamepadDirectionEmulateStick = enable; }
|
|
1053
|
+
|
|
1054
|
+
/** Set if true the WASD keys are also routed to the direction keys
|
|
1055
|
+
* @param {Boolean} enable
|
|
1056
|
+
* @memberof Settings */
|
|
1057
|
+
function setInputWASDEmulateDirection(enable) { inputWASDEmulateDirection = enable; }
|
|
1058
|
+
|
|
1059
|
+
/** Set if touch gamepad should appear on mobile devices
|
|
1060
|
+
* @param {Boolean} enable
|
|
1061
|
+
* @memberof Settings */
|
|
1062
|
+
function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
|
|
1063
|
+
|
|
1064
|
+
/** Set if touch gamepad should be analog stick or 8 way dpad
|
|
1065
|
+
* @param {Boolean} analog
|
|
1066
|
+
* @memberof Settings */
|
|
1067
|
+
function setTouchGamepadAnalog(analog) { touchGamepadAnalog = analog; }
|
|
1068
|
+
|
|
1069
|
+
/** Set size of virutal gamepad for touch devices in pixels
|
|
1070
|
+
* @param {Number} size
|
|
1071
|
+
* @memberof Settings */
|
|
1072
|
+
function setTouchGamepadSize(size) { touchGamepadSize = size; }
|
|
1073
|
+
|
|
1074
|
+
/** Set transparency of touch gamepad overlay
|
|
1075
|
+
* @param {Number} alpha
|
|
1076
|
+
* @memberof Settings */
|
|
1077
|
+
function setTouchGamepadAlpha(alpha) { touchGamepadAlpha = alpha; }
|
|
1078
|
+
|
|
1079
|
+
/** Set to allow vibration hardware if it exists
|
|
1080
|
+
* @param {Boolean} enable
|
|
1081
|
+
* @memberof Settings */
|
|
1082
|
+
function setVibrateEnable(enable) { vibrateEnable = enable; }
|
|
1083
|
+
|
|
1084
|
+
/** Set to disable all audio code
|
|
1085
|
+
* @param {Boolean} enable
|
|
1086
|
+
* @memberof Settings */
|
|
1087
|
+
function setSoundEnable(enable) { soundEnable = enable; }
|
|
1088
|
+
|
|
1089
|
+
/** Set volume scale to apply to all sound, music and speech
|
|
1090
|
+
* @param {Number} volume
|
|
1091
|
+
* @memberof Settings */
|
|
1092
|
+
function setSoundVolume(volume) { soundVolume = volume; }
|
|
1093
|
+
|
|
1094
|
+
/** Set default range where sound no longer plays
|
|
1095
|
+
* @param {Number} range
|
|
1096
|
+
* @memberof Settings */
|
|
1097
|
+
function setSoundDefaultRange(range) { soundDefaultRange = range; }
|
|
1098
|
+
|
|
1099
|
+
/** Set default range percent to start tapering off sound
|
|
1100
|
+
* @param {Number} taper
|
|
1101
|
+
* @memberof Settings */
|
|
1102
|
+
function setSoundDefaultTaper(taper) { soundDefaultTaper = taper; }
|
|
1103
|
+
|
|
1104
|
+
/** Set how long to show medals for in seconds
|
|
1105
|
+
* @param {Number} time
|
|
1106
|
+
* @memberof Settings */
|
|
1107
|
+
function setMedalDisplayTime(time) { medalDisplayTime = time; }
|
|
1108
|
+
|
|
1109
|
+
/** Set how quickly to slide on/off medals in seconds
|
|
1110
|
+
* @param {Number} time
|
|
1111
|
+
* @memberof Settings */
|
|
1112
|
+
function setMedalDisplaySlideTime(time) { medalDisplaySlideTime = time; }
|
|
1113
|
+
|
|
1114
|
+
/** Set size of medal display
|
|
1115
|
+
* @param {Vector2} size
|
|
1116
|
+
* @memberof Settings */
|
|
1117
|
+
function setMedalDisplaySize(size) { medalDisplaySize = size; }
|
|
1118
|
+
|
|
1119
|
+
/** Set size of icon in medal display
|
|
1120
|
+
* @param {Number} size
|
|
1121
|
+
* @memberof Settings */
|
|
1122
|
+
function setMedalDisplayIconSize(size) { medalDisplayIconSize = size; }
|
|
1123
|
+
|
|
1124
|
+
/** Set to stop medals from being unlockable
|
|
1125
|
+
* @param {Boolean} preventUnlock
|
|
1126
|
+
* @memberof Settings */
|
|
1127
|
+
function setMedalsPreventUnlock(preventUnlock) { medalsPreventUnlock = preventUnlock; }
|
|
1128
|
+
|
|
1129
|
+
/** Set if watermark with FPS should be shown
|
|
1130
|
+
* @param {Boolean} show
|
|
1131
|
+
* @memberof Debug */
|
|
1132
|
+
function setShowWatermark(show) { showWatermark = show; }
|
|
1133
|
+
|
|
1134
|
+
/** Set key code used to toggle debug mode, Esc by default
|
|
1135
|
+
* @param {Number} key
|
|
1136
|
+
* @memberof Debug */
|
|
1137
|
+
function setDebugKey(key) { debugKey = key; }
|
|
945
1138
|
/**
|
|
946
1139
|
* LittleJS Object System
|
|
947
1140
|
*/
|
|
@@ -976,18 +1169,20 @@ let medalsPreventUnlock;
|
|
|
976
1169
|
class EngineObject
|
|
977
1170
|
{
|
|
978
1171
|
/** Create an engine object and adds it to the list of objects
|
|
979
|
-
* @param {Vector2} [
|
|
980
|
-
* @param {Vector2} [size=Vector2(1,1)]
|
|
981
|
-
* @param {
|
|
982
|
-
* @param {
|
|
983
|
-
* @param {
|
|
984
|
-
* @param {
|
|
985
|
-
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
1172
|
+
* @param {Vector2} [pos=Vector2()] - World space position of the object
|
|
1173
|
+
* @param {Vector2} [size=Vector2(1,1)] - World space size of the object
|
|
1174
|
+
* @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
|
|
1175
|
+
* @param {Number} [angle=0] - Angle the object is rotated by
|
|
1176
|
+
* @param {Color} [color=Color()] - Color to apply to tile when rendered
|
|
1177
|
+
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
986
1178
|
*/
|
|
987
|
-
constructor(pos=vec2(), size=vec2(1),
|
|
1179
|
+
constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color, renderOrder=0)
|
|
988
1180
|
{
|
|
989
1181
|
// set passed in params
|
|
990
1182
|
ASSERT(isVector2(pos) && isVector2(size)); // ensure pos and size are vec2s
|
|
1183
|
+
ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
|
|
1184
|
+
ASSERT(!(renderOrder instanceof Color)); // prevent old style calls
|
|
1185
|
+
// to fix old calls, replace with tile(tileIndex, tileSize)
|
|
991
1186
|
|
|
992
1187
|
/** @property {Vector2} - World space position of the object */
|
|
993
1188
|
this.pos = pos.copy();
|
|
@@ -995,10 +1190,8 @@ class EngineObject
|
|
|
995
1190
|
this.size = size;
|
|
996
1191
|
/** @property {Vector2} - Size of object used for drawing, uses size if not set */
|
|
997
1192
|
this.drawSize;
|
|
998
|
-
/** @property {
|
|
999
|
-
this.
|
|
1000
|
-
/** @property {Vector2} - Size of tile in source pixels */
|
|
1001
|
-
this.tileSize = tileSize;
|
|
1193
|
+
/** @property {TileInfo} - Tile info to render object (undefined is untextured) */
|
|
1194
|
+
this.tileInfo = tileInfo;
|
|
1002
1195
|
/** @property {Number} - Angle to rotate the object */
|
|
1003
1196
|
this.angle = angle;
|
|
1004
1197
|
/** @property {Color} - Color to apply when rendered */
|
|
@@ -1214,7 +1407,7 @@ class EngineObject
|
|
|
1214
1407
|
render()
|
|
1215
1408
|
{
|
|
1216
1409
|
// default object render
|
|
1217
|
-
drawTile(this.pos, this.drawSize || this.size, this.
|
|
1410
|
+
drawTile(this.pos, this.drawSize || this.size, this.tileInfo, this.color, this.angle, this.mirror, this.additiveColor);
|
|
1218
1411
|
}
|
|
1219
1412
|
|
|
1220
1413
|
/** Destroy this object, destroy it's children, detach it's parent, and mark it for removal */
|
|
@@ -1369,13 +1562,109 @@ let overlayContext;
|
|
|
1369
1562
|
* @memberof Draw */
|
|
1370
1563
|
let mainCanvasSize = vec2();
|
|
1371
1564
|
|
|
1372
|
-
/**
|
|
1373
|
-
* @type {
|
|
1565
|
+
/** Array containing texture info for batch rendering system
|
|
1566
|
+
* @type {Array}
|
|
1374
1567
|
* @memberof Draw */
|
|
1375
|
-
|
|
1568
|
+
let textureInfos = [];
|
|
1376
1569
|
|
|
1377
1570
|
// Engine internal variables not exposed to documentation
|
|
1378
|
-
let
|
|
1571
|
+
let drawCount;
|
|
1572
|
+
|
|
1573
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* Create a tile info object
|
|
1577
|
+
* - This can take vecs or floats for easier use and conversion
|
|
1578
|
+
* - If an index is passed in, the tile size and index will determine the position
|
|
1579
|
+
* @param {(Number|Vector2)} [pos=Vector2()] - Top left corner of tile in pixels or index
|
|
1580
|
+
* @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
|
|
1581
|
+
* @param {Number} [textureIndex=0] - Texture index to use
|
|
1582
|
+
* @return {TileInfo}
|
|
1583
|
+
* @example
|
|
1584
|
+
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
1585
|
+
* tile(5, 8) // a tile at index 5 using a tile size of 8
|
|
1586
|
+
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
1587
|
+
* tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
|
|
1588
|
+
* @memberof Draw
|
|
1589
|
+
*/
|
|
1590
|
+
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
1591
|
+
{
|
|
1592
|
+
// if size is a number, make it a vector
|
|
1593
|
+
if (size.x == undefined)
|
|
1594
|
+
{
|
|
1595
|
+
ASSERT(size > 0);
|
|
1596
|
+
size = vec2(size);
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// if pos is a number, use it as a tile index
|
|
1600
|
+
if (pos.x == undefined)
|
|
1601
|
+
{
|
|
1602
|
+
const textureInfo = textureInfos[textureIndex];
|
|
1603
|
+
if (textureInfo)
|
|
1604
|
+
{
|
|
1605
|
+
const cols = textureInfo.size.x / size.x |0;
|
|
1606
|
+
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
1607
|
+
}
|
|
1608
|
+
else
|
|
1609
|
+
pos = vec2();
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// return a tile info object
|
|
1613
|
+
return new TileInfo(pos, size, textureIndex);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* Tile Info - Stores info about how to draw a tile
|
|
1618
|
+
*/
|
|
1619
|
+
class TileInfo
|
|
1620
|
+
{
|
|
1621
|
+
/** Create a tile info object
|
|
1622
|
+
* @param {Vector2} [pos=Vector2()] - Top left corner of tile in pixels
|
|
1623
|
+
* @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
|
|
1624
|
+
* @param {Number} [textureIndex=0] - Texture index to use
|
|
1625
|
+
*/
|
|
1626
|
+
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
1627
|
+
{
|
|
1628
|
+
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
1629
|
+
this.pos = pos;
|
|
1630
|
+
/** @property {Vector2} - Size of tile in pixels */
|
|
1631
|
+
this.size = size;
|
|
1632
|
+
/** @property {Number} - Texture index to use */
|
|
1633
|
+
this.textureIndex = textureIndex;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
/** Returns an offset copy of this tile, useful for animation
|
|
1637
|
+
* @param {Vector2} offset - Offset to apply in pixels
|
|
1638
|
+
* @return {TileInfo}
|
|
1639
|
+
*/
|
|
1640
|
+
offset(offset)
|
|
1641
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
1642
|
+
|
|
1643
|
+
/** Returns the texture info for this tile
|
|
1644
|
+
* @return {TextureInfo}
|
|
1645
|
+
*/
|
|
1646
|
+
getTextureInfo()
|
|
1647
|
+
{ return textureInfos[this.textureIndex]; }
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
/** Texture Info - Stores info about each texture */
|
|
1651
|
+
class TextureInfo
|
|
1652
|
+
{
|
|
1653
|
+
// create a TextureInfo, called automatically by the engine
|
|
1654
|
+
constructor(image)
|
|
1655
|
+
{
|
|
1656
|
+
/** @property {CanvasImageSource} - image source */
|
|
1657
|
+
this.image = image;
|
|
1658
|
+
/** @property {Vector2} - size of the image */
|
|
1659
|
+
this.size = vec2(image.width, image.height);
|
|
1660
|
+
/** @property {WebGLTexture} - webgl texture */
|
|
1661
|
+
this.glTexture = glEnable && glCreateTexture(image);
|
|
1662
|
+
/** @property {Vector2} - size to adjust tile to fix bleeding */
|
|
1663
|
+
this.fixBleedSize = vec2(tileFixBleedScale).divide(this.size);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1379
1668
|
|
|
1380
1669
|
/** Convert from screen to world space coordinates
|
|
1381
1670
|
* @param {Vector2} screenPos
|
|
@@ -1406,7 +1695,7 @@ function worldToScreen(worldPos)
|
|
|
1406
1695
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
1407
1696
|
* @param {Vector2} pos - Center of the tile in world space
|
|
1408
1697
|
* @param {Vector2} [size=Vector2(1,1)] - Size of the tile in world space
|
|
1409
|
-
* @param {
|
|
1698
|
+
* @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
|
|
1410
1699
|
* @param {Vector2} [tileSize=tileSizeDefault] - Tile size in source pixels
|
|
1411
1700
|
* @param {Color} [color=Color()] - Color to modulate with
|
|
1412
1701
|
* @param {Number} [angle=0] - Angle to rotate by
|
|
@@ -1414,13 +1703,18 @@ function worldToScreen(worldPos)
|
|
|
1414
1703
|
* @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
|
|
1415
1704
|
* @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
1416
1705
|
* @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
|
|
1706
|
+
* @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
|
|
1417
1707
|
* @memberof Draw */
|
|
1418
|
-
function drawTile(pos, size=vec2(1),
|
|
1419
|
-
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
|
|
1708
|
+
function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
1709
|
+
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace, context)
|
|
1420
1710
|
{
|
|
1711
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
1712
|
+
ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
|
|
1713
|
+
// to fix old calls, replace with tile(tileIndex, tileSize)
|
|
1714
|
+
|
|
1421
1715
|
showWatermark && ++drawCount;
|
|
1422
|
-
|
|
1423
|
-
if (
|
|
1716
|
+
const textureInfo = tileInfo && tileInfo.getTextureInfo();
|
|
1717
|
+
if (useWebGL)
|
|
1424
1718
|
{
|
|
1425
1719
|
if (screenSpace)
|
|
1426
1720
|
{
|
|
@@ -1428,48 +1722,50 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
1428
1722
|
pos = screenToWorld(pos);
|
|
1429
1723
|
size = size.scale(1/cameraScale);
|
|
1430
1724
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
// if negative tile index or image not found, force untextured
|
|
1434
|
-
glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
|
|
1435
|
-
}
|
|
1436
|
-
else
|
|
1725
|
+
|
|
1726
|
+
if (textureInfo)
|
|
1437
1727
|
{
|
|
1438
1728
|
// calculate uvs and render
|
|
1439
|
-
const
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1729
|
+
const x = tileInfo.pos.x / textureInfo.size.x;
|
|
1730
|
+
const y = tileInfo.pos.y / textureInfo.size.y;
|
|
1731
|
+
const w = tileInfo.size.x / textureInfo.size.x;
|
|
1732
|
+
const h = tileInfo.size.y / textureInfo.size.y;
|
|
1733
|
+
const tileImageFixBleed = textureInfo.fixBleedSize;
|
|
1734
|
+
glSetTexture(textureInfo.glTexture);
|
|
1444
1735
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
1445
|
-
|
|
1446
|
-
|
|
1736
|
+
x + tileImageFixBleed.x, y + tileImageFixBleed.y,
|
|
1737
|
+
x - tileImageFixBleed.x + w, y - tileImageFixBleed.y + h,
|
|
1447
1738
|
color.rgbaInt(), additiveColor.rgbaInt());
|
|
1448
1739
|
}
|
|
1740
|
+
else
|
|
1741
|
+
{
|
|
1742
|
+
// if no tile info, force untextured
|
|
1743
|
+
glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
|
|
1744
|
+
}
|
|
1449
1745
|
}
|
|
1450
1746
|
else
|
|
1451
1747
|
{
|
|
1452
1748
|
// normal canvas 2D rendering method (slower)
|
|
1453
1749
|
drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
1454
1750
|
{
|
|
1455
|
-
if (
|
|
1751
|
+
if (textureInfo)
|
|
1456
1752
|
{
|
|
1457
|
-
//
|
|
1458
|
-
|
|
1459
|
-
|
|
1753
|
+
// calculate uvs and render
|
|
1754
|
+
const x = tileInfo.pos.x + tileFixBleedScale;
|
|
1755
|
+
const y = tileInfo.pos.y + tileFixBleedScale;
|
|
1756
|
+
const w = tileInfo.size.x - 2*tileFixBleedScale;
|
|
1757
|
+
const h = tileInfo.size.y - 2*tileFixBleedScale;
|
|
1758
|
+
context.globalAlpha = color.a; // only alpha is supported
|
|
1759
|
+
context.drawImage(textureInfo.image, x, y, w, h, -.5, -.5, 1, 1);
|
|
1760
|
+
context.globalAlpha = 1; // set back to full alpha
|
|
1460
1761
|
}
|
|
1461
1762
|
else
|
|
1462
1763
|
{
|
|
1463
|
-
//
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
const sY = (tileIndex/cols|0)*tileSize.y + tileFixBleedScale;
|
|
1467
|
-
const sWidth = tileSize.x - 2*tileFixBleedScale;
|
|
1468
|
-
const sHeight = tileSize.y - 2*tileFixBleedScale;
|
|
1469
|
-
context.globalAlpha = color.a; // only alpha is supported
|
|
1470
|
-
context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
|
|
1764
|
+
// if no tile info, force untextured
|
|
1765
|
+
context.fillStyle = color;
|
|
1766
|
+
context.fillRect(-.5, -.5, 1, 1);
|
|
1471
1767
|
}
|
|
1472
|
-
},
|
|
1768
|
+
}, screenSpace, context);
|
|
1473
1769
|
}
|
|
1474
1770
|
}
|
|
1475
1771
|
|
|
@@ -1480,28 +1776,36 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
1480
1776
|
* @param {Number} [angle=0]
|
|
1481
1777
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1482
1778
|
* @param {Boolean} [screenSpace=0]
|
|
1779
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
1483
1780
|
* @memberof Draw */
|
|
1484
|
-
function drawRect(pos, size, color, angle, useWebGL, screenSpace)
|
|
1485
|
-
{
|
|
1781
|
+
function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
1782
|
+
{
|
|
1783
|
+
drawTile(pos, size, undefined, color, angle, 0, undefined, useWebGL, screenSpace, context);
|
|
1784
|
+
}
|
|
1486
1785
|
|
|
1487
1786
|
/** Draw colored polygon using passed in points
|
|
1488
1787
|
* @param {Array} points - Array of Vector2 points
|
|
1489
1788
|
* @param {Color} [color=Color()]
|
|
1490
1789
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1491
1790
|
* @param {Boolean} [screenSpace=0]
|
|
1791
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
1492
1792
|
* @memberof Draw */
|
|
1493
|
-
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
1793
|
+
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace, context)
|
|
1494
1794
|
{
|
|
1795
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
1796
|
+
|
|
1495
1797
|
if (useWebGL)
|
|
1496
1798
|
glDrawPoints(screenSpace ? points.map(screenToWorld) : points, color.rgbaInt());
|
|
1497
1799
|
else
|
|
1498
1800
|
{
|
|
1499
1801
|
// draw using canvas
|
|
1500
|
-
|
|
1501
|
-
|
|
1802
|
+
if (!context)
|
|
1803
|
+
context = mainContext;
|
|
1804
|
+
context.fillStyle = color;
|
|
1805
|
+
context.beginPath();
|
|
1502
1806
|
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
1503
|
-
|
|
1504
|
-
|
|
1807
|
+
context.lineTo(point.x, point.y);
|
|
1808
|
+
context.fill();
|
|
1505
1809
|
}
|
|
1506
1810
|
}
|
|
1507
1811
|
|
|
@@ -1512,12 +1816,13 @@ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
|
1512
1816
|
* @param {Color} [color=Color()]
|
|
1513
1817
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1514
1818
|
* @param {Boolean} [screenSpace=0]
|
|
1819
|
+
* @param {CanvasRenderingContext2D} [context]
|
|
1515
1820
|
* @memberof Draw */
|
|
1516
|
-
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
|
|
1821
|
+
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
|
|
1517
1822
|
{
|
|
1518
1823
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
1519
1824
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
1520
|
-
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace);
|
|
1825
|
+
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace, context);
|
|
1521
1826
|
}
|
|
1522
1827
|
|
|
1523
1828
|
/** Draw directly to a 2d canvas context in world space
|
|
@@ -1526,10 +1831,10 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
|
|
|
1526
1831
|
* @param {Number} angle
|
|
1527
1832
|
* @param {Boolean} mirror
|
|
1528
1833
|
* @param {Function} drawFunction
|
|
1529
|
-
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1530
1834
|
* @param {Boolean} [screenSpace=0]
|
|
1835
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1531
1836
|
* @memberof Draw */
|
|
1532
|
-
function drawCanvas2D(pos, size, angle, mirror, drawFunction, context
|
|
1837
|
+
function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, context=mainContext)
|
|
1533
1838
|
{
|
|
1534
1839
|
if (!screenSpace)
|
|
1535
1840
|
{
|
|
@@ -1548,13 +1853,19 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
|
|
|
1548
1853
|
/** Enable normal or additive blend mode
|
|
1549
1854
|
* @param {Boolean} [additive=0]
|
|
1550
1855
|
* @param {Boolean} [useWebGL=glEnable]
|
|
1856
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
1551
1857
|
* @memberof Draw */
|
|
1552
|
-
function setBlendMode(additive, useWebGL=glEnable)
|
|
1858
|
+
function setBlendMode(additive, useWebGL=glEnable, context)
|
|
1553
1859
|
{
|
|
1554
|
-
|
|
1555
|
-
|
|
1860
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
1861
|
+
if (useWebGL)
|
|
1862
|
+
glAdditive = additive;
|
|
1556
1863
|
else
|
|
1557
|
-
|
|
1864
|
+
{
|
|
1865
|
+
if (!context)
|
|
1866
|
+
context = mainContext;
|
|
1867
|
+
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
1868
|
+
}
|
|
1558
1869
|
}
|
|
1559
1870
|
|
|
1560
1871
|
/** Draw text on overlay canvas in world space
|
|
@@ -1627,10 +1938,9 @@ class FontImage
|
|
|
1627
1938
|
* @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
|
|
1628
1939
|
* @param {Vector2} [tileSize=vec2(8)] - Size of the font source tiles
|
|
1629
1940
|
* @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
|
|
1630
|
-
* @param {Number} [startTileIndex=0] - Tile index in image where font starts
|
|
1631
1941
|
* @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
|
|
1632
1942
|
*/
|
|
1633
|
-
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1),
|
|
1943
|
+
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
|
|
1634
1944
|
{
|
|
1635
1945
|
// load default font image
|
|
1636
1946
|
if (!engineFontImage)
|
|
@@ -1639,7 +1949,6 @@ class FontImage
|
|
|
1639
1949
|
this.image = image || engineFontImage;
|
|
1640
1950
|
this.tileSize = tileSize;
|
|
1641
1951
|
this.paddingSize = paddingSize;
|
|
1642
|
-
this.startTileIndex = startTileIndex;
|
|
1643
1952
|
this.context = context;
|
|
1644
1953
|
}
|
|
1645
1954
|
|
|
@@ -1680,7 +1989,7 @@ class FontImage
|
|
|
1680
1989
|
charCode = 127; // unknown character
|
|
1681
1990
|
|
|
1682
1991
|
// get the character source location and draw it
|
|
1683
|
-
const tile =
|
|
1992
|
+
const tile = charCode - 32;
|
|
1684
1993
|
const x = tile % cols;
|
|
1685
1994
|
const y = tile / cols |0;
|
|
1686
1995
|
const drawPos = pos.add(vec2(j,i).multiply(drawSize));
|
|
@@ -1712,8 +2021,7 @@ function toggleFullscreen()
|
|
|
1712
2021
|
}
|
|
1713
2022
|
else if (document.body.requestFullscreen)
|
|
1714
2023
|
document.body.requestFullscreen();
|
|
1715
|
-
}
|
|
1716
|
-
|
|
2024
|
+
}
|
|
1717
2025
|
/**
|
|
1718
2026
|
* LittleJS Input System
|
|
1719
2027
|
* - Tracks keyboard down, pressed, and released
|
|
@@ -2209,7 +2517,8 @@ class Sound
|
|
|
2209
2517
|
if (zzfxSound)
|
|
2210
2518
|
{
|
|
2211
2519
|
// generate zzfx sound now for fast playback
|
|
2212
|
-
this.randomness = zzfxSound[1]
|
|
2520
|
+
this.randomness = zzfxSound[1];
|
|
2521
|
+
zzfxSound[1] = 0; // generate without randomness
|
|
2213
2522
|
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
2214
2523
|
this.sampleRate = zzfxR;
|
|
2215
2524
|
}
|
|
@@ -2871,7 +3180,7 @@ class TileLayerData
|
|
|
2871
3180
|
}
|
|
2872
3181
|
|
|
2873
3182
|
/**
|
|
2874
|
-
* Tile
|
|
3183
|
+
* Tile Layer - cached rendering system for tile layers
|
|
2875
3184
|
* - Each Tile layer is rendered to an off screen canvas
|
|
2876
3185
|
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
2877
3186
|
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
@@ -2887,13 +3196,13 @@ class TileLayer extends EngineObject
|
|
|
2887
3196
|
/** Create a tile layer object
|
|
2888
3197
|
* @param {Vector2} [position=Vector2()] - World space position
|
|
2889
3198
|
* @param {Vector2} [size=tileCollisionSize] - World space size
|
|
2890
|
-
* @param {
|
|
3199
|
+
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
2891
3200
|
* @param {Vector2} [scale=Vector2(1,1)] - How much to scale this layer when rendered
|
|
2892
3201
|
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
2893
3202
|
*/
|
|
2894
|
-
constructor(pos, size=tileCollisionSize,
|
|
3203
|
+
constructor(pos, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderOrder=0)
|
|
2895
3204
|
{
|
|
2896
|
-
super(pos, size,
|
|
3205
|
+
super(pos, size, tileInfo, 0, undefined, renderOrder);
|
|
2897
3206
|
|
|
2898
3207
|
/** @property {HTMLCanvasElement} - The canvas used by this tile layer */
|
|
2899
3208
|
this.canvas = document.createElement('canvas');
|
|
@@ -2970,13 +3279,13 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
2970
3279
|
mainCanvas = this.canvas;
|
|
2971
3280
|
mainContext = this.context;
|
|
2972
3281
|
cameraPos = this.size.scale(.5);
|
|
2973
|
-
cameraScale = this.
|
|
3282
|
+
cameraScale = this.tileInfo.size.x;
|
|
2974
3283
|
|
|
2975
3284
|
if (clear)
|
|
2976
3285
|
{
|
|
2977
3286
|
// clear and set size
|
|
2978
|
-
mainCanvas.width = this.size.x * this.
|
|
2979
|
-
mainCanvas.height = this.size.y * this.
|
|
3287
|
+
mainCanvas.width = this.size.x * this.tileInfo.size.x;
|
|
3288
|
+
mainCanvas.height = this.size.y * this.tileInfo.size.y;
|
|
2980
3289
|
}
|
|
2981
3290
|
|
|
2982
3291
|
// begin a new render for the tile canvas
|
|
@@ -3007,7 +3316,8 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3007
3316
|
if (d.tile != undefined)
|
|
3008
3317
|
{
|
|
3009
3318
|
ASSERT(mainContext == this.context); // must call redrawStart() before drawing tiles
|
|
3010
|
-
|
|
3319
|
+
const tileInfo = tile(d.tile, this.tileInfo.size, this.tileInfo.textureIndex);
|
|
3320
|
+
drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
|
|
3011
3321
|
}
|
|
3012
3322
|
}
|
|
3013
3323
|
|
|
@@ -3029,8 +3339,8 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3029
3339
|
{
|
|
3030
3340
|
const context = this.context;
|
|
3031
3341
|
context.save();
|
|
3032
|
-
pos = pos.subtract(this.pos).multiply(this.
|
|
3033
|
-
size = size.multiply(this.
|
|
3342
|
+
pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
|
|
3343
|
+
size = size.multiply(this.tileInfo.size);
|
|
3034
3344
|
context.translate(pos.x, this.canvas.height - pos.y);
|
|
3035
3345
|
context.rotate(angle);
|
|
3036
3346
|
context.scale(mirror ? -size.x : size.x, size.y);
|
|
@@ -3041,28 +3351,28 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3041
3351
|
/** Draw a tile directly onto the layer canvas
|
|
3042
3352
|
* @param {Vector2} pos
|
|
3043
3353
|
* @param {Vector2} [size=Vector2(1,1)]
|
|
3044
|
-
* @param {
|
|
3045
|
-
* @param {Vector2} [tileSize=tileSizeDefault]
|
|
3354
|
+
* @param {TileInfo} [tileInfo]
|
|
3046
3355
|
* @param {Color} [color=Color()]
|
|
3047
3356
|
* @param {Number} [angle=0]
|
|
3048
3357
|
* @param {Boolean} [mirror=0] */
|
|
3049
|
-
drawTile(pos, size=vec2(1),
|
|
3358
|
+
drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle, mirror)
|
|
3050
3359
|
{
|
|
3051
3360
|
this.drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
3052
3361
|
{
|
|
3053
|
-
|
|
3362
|
+
const textureInfo = tileInfo && tileInfo.getTextureInfo();
|
|
3363
|
+
if (textureInfo)
|
|
3054
3364
|
{
|
|
3055
|
-
//
|
|
3056
|
-
context.
|
|
3057
|
-
|
|
3365
|
+
context.globalAlpha = color.a; // only alpha is supported
|
|
3366
|
+
context.drawImage(textureInfo.image,
|
|
3367
|
+
tileInfo.pos.x, tileInfo.pos.y,
|
|
3368
|
+
tileInfo.size.x, tileInfo.size.y, -.5, -.5, 1, 1);
|
|
3369
|
+
context.globalAlpha = 1;
|
|
3058
3370
|
}
|
|
3059
3371
|
else
|
|
3060
3372
|
{
|
|
3061
|
-
|
|
3062
|
-
context.
|
|
3063
|
-
context.
|
|
3064
|
-
(tileIndex%cols)*tileSize.x, (tileIndex/cols|0)*tileSize.y,
|
|
3065
|
-
tileSize.x, tileSize.y, -.5, -.5, 1, 1);
|
|
3373
|
+
// untextured
|
|
3374
|
+
context.fillStyle = color;
|
|
3375
|
+
context.fillRect(-.5, -.5, 1, 1);
|
|
3066
3376
|
}
|
|
3067
3377
|
});
|
|
3068
3378
|
}
|
|
@@ -3090,7 +3400,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3090
3400
|
* let particleEmiter = new ParticleEmitter
|
|
3091
3401
|
* (
|
|
3092
3402
|
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
3093
|
-
* 0,
|
|
3403
|
+
* tile(0, 16), // tileInfo
|
|
3094
3404
|
* new Color(1,1,1), new Color(0,0,0), // colorStartA, colorStartB
|
|
3095
3405
|
* new Color(1,1,1,0), new Color(0,0,0,0), // colorEndA, colorEndB
|
|
3096
3406
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
@@ -3107,8 +3417,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3107
3417
|
* @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
|
|
3108
3418
|
* @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
|
|
3109
3419
|
* @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
|
|
3110
|
-
* @param {
|
|
3111
|
-
* @param {Vector2} [tileSize=tileSizeDefault] - Tile size for particles
|
|
3420
|
+
* @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
|
|
3112
3421
|
* @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
|
|
3113
3422
|
* @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
|
|
3114
3423
|
* @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
|
|
@@ -3138,8 +3447,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3138
3447
|
emitTime = 0,
|
|
3139
3448
|
emitRate = 100,
|
|
3140
3449
|
emitConeAngle = PI,
|
|
3141
|
-
|
|
3142
|
-
tileSize = tileSizeDefault,
|
|
3450
|
+
tileInfo,
|
|
3143
3451
|
colorStartA = new Color,
|
|
3144
3452
|
colorStartB = new Color,
|
|
3145
3453
|
colorEndA = new Color(1,1,1,0),
|
|
@@ -3162,7 +3470,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3162
3470
|
localSpace
|
|
3163
3471
|
)
|
|
3164
3472
|
{
|
|
3165
|
-
super(pos, vec2(),
|
|
3473
|
+
super(pos, vec2(), tileInfo, angle, undefined, renderOrder);
|
|
3166
3474
|
|
|
3167
3475
|
// emitter settings
|
|
3168
3476
|
/** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
@@ -3261,7 +3569,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3261
3569
|
angle += this.angle;
|
|
3262
3570
|
}
|
|
3263
3571
|
|
|
3264
|
-
const particle = new Particle(pos, this.
|
|
3572
|
+
const particle = new Particle(pos, this.tileInfo, this.tileSize, angle);
|
|
3265
3573
|
|
|
3266
3574
|
// randomness scales each paremeter by a percentage
|
|
3267
3575
|
const randomness = this.randomness;
|
|
@@ -3321,12 +3629,11 @@ class Particle extends EngineObject
|
|
|
3321
3629
|
/**
|
|
3322
3630
|
* Create a particle with the given settings
|
|
3323
3631
|
* @param {Vector2} position - World space position of the particle
|
|
3324
|
-
* @param {
|
|
3325
|
-
* @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
|
|
3632
|
+
* @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
|
|
3326
3633
|
* @param {Number} [angle=0] - Angle to rotate the particle
|
|
3327
3634
|
*/
|
|
3328
|
-
constructor(pos,
|
|
3329
|
-
{ super(pos, vec2(),
|
|
3635
|
+
constructor(pos, tileInfo, angle)
|
|
3636
|
+
{ super(pos, vec2(), tileInfo, angle); }
|
|
3330
3637
|
|
|
3331
3638
|
/** Render the particle, automatically called each frame, sorted by renderOrder */
|
|
3332
3639
|
render()
|
|
@@ -3360,14 +3667,17 @@ class Particle extends EngineObject
|
|
|
3360
3667
|
if (this.localSpaceEmitter)
|
|
3361
3668
|
velocity = velocity.rotate(-this.localSpaceEmitter.angle);
|
|
3362
3669
|
const speed = velocity.length();
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3670
|
+
if (speed)
|
|
3671
|
+
{
|
|
3672
|
+
const direction = velocity.scale(1/speed);
|
|
3673
|
+
const trailLength = speed * this.trailScale;
|
|
3674
|
+
size.y = max(size.x, trailLength);
|
|
3675
|
+
angle = direction.angle();
|
|
3676
|
+
drawTile(pos.add(direction.multiply(vec2(0,-trailLength/2))), size, this.tileInfo, color, angle, this.mirror);
|
|
3677
|
+
}
|
|
3368
3678
|
}
|
|
3369
3679
|
else
|
|
3370
|
-
drawTile(pos, size, this.
|
|
3680
|
+
drawTile(pos, size, this.tileInfo, color, angle, this.mirror);
|
|
3371
3681
|
this.additive && setBlendMode();
|
|
3372
3682
|
debugParticles && debugRect(pos, size, '#f005', 0, angle);
|
|
3373
3683
|
|
|
@@ -3414,7 +3724,7 @@ function medalsInit(saveName)
|
|
|
3414
3724
|
}
|
|
3415
3725
|
|
|
3416
3726
|
/**
|
|
3417
|
-
* Medal
|
|
3727
|
+
* Medal - Tracks an unlockable medal
|
|
3418
3728
|
* @example
|
|
3419
3729
|
* // create a medal
|
|
3420
3730
|
* const medal_example = new Medal(0, 'Example Medal', 'More info about the medal goes here.', '🎖️');
|
|
@@ -3427,7 +3737,7 @@ function medalsInit(saveName)
|
|
|
3427
3737
|
*/
|
|
3428
3738
|
class Medal
|
|
3429
3739
|
{
|
|
3430
|
-
/** Create
|
|
3740
|
+
/** Create a medal object and adds it to the list of medals
|
|
3431
3741
|
* @param {Number} id - The unique identifier of the medal
|
|
3432
3742
|
* @param {String} name - Name of the medal
|
|
3433
3743
|
* @param {String} [description] - Description of the medal
|
|
@@ -3539,33 +3849,33 @@ let newgrounds;
|
|
|
3539
3849
|
/** This can used to enable Newgrounds functionality
|
|
3540
3850
|
* @param {Number} app_id - The newgrounds App ID
|
|
3541
3851
|
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
3852
|
+
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher
|
|
3542
3853
|
* @memberof Medals */
|
|
3543
|
-
function newgroundsInit(app_id, cipher
|
|
3854
|
+
function newgroundsInit(app_id, cipher, cryptoJS)
|
|
3855
|
+
{ newgrounds = new Newgrounds(app_id, cipher, cryptoJS); }
|
|
3544
3856
|
|
|
3545
3857
|
/**
|
|
3546
3858
|
* Newgrounds API wrapper object
|
|
3547
3859
|
* @example
|
|
3548
|
-
* // create a newgrounds object, replace the app id
|
|
3860
|
+
* // create a newgrounds object, replace the app id with your own
|
|
3549
3861
|
* const app_id = '53123:1ZuSTQ9l';
|
|
3550
|
-
*
|
|
3551
|
-
* newgrounds = new Newgrounds(app_id, cipher);
|
|
3862
|
+
* newgrounds = new Newgrounds(app_id);
|
|
3552
3863
|
*/
|
|
3553
3864
|
class Newgrounds
|
|
3554
3865
|
{
|
|
3555
3866
|
/** Create a newgrounds object
|
|
3556
3867
|
* @param {Number} app_id - The newgrounds App ID
|
|
3557
|
-
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
3558
|
-
|
|
3868
|
+
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
3869
|
+
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher */
|
|
3870
|
+
constructor(app_id, cipher, cryptoJS)
|
|
3559
3871
|
{
|
|
3560
|
-
ASSERT(!newgrounds && app_id);
|
|
3872
|
+
ASSERT(!newgrounds && app_id); // can only be one newgrounds object
|
|
3873
|
+
ASSERT(!cipher || cryptoJS); // must provide cryptojs if there is a cipher
|
|
3561
3874
|
|
|
3562
3875
|
this.app_id = app_id;
|
|
3563
3876
|
this.cipher = cipher;
|
|
3877
|
+
this.cryptoJS = cryptoJS;
|
|
3564
3878
|
this.host = location ? location.hostname : '';
|
|
3565
|
-
|
|
3566
|
-
// create an instance of CryptoJS for encrypted calls
|
|
3567
|
-
if (cipher)
|
|
3568
|
-
this.cryptoJS = this.CryptoJS();
|
|
3569
3879
|
|
|
3570
3880
|
// get session id from url search params
|
|
3571
3881
|
const url = new URL(location.href);
|
|
@@ -3669,38 +3979,6 @@ class Newgrounds
|
|
|
3669
3979
|
debugMedals && console.log(xmlHttp.responseText);
|
|
3670
3980
|
return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
|
|
3671
3981
|
}
|
|
3672
|
-
|
|
3673
|
-
CryptoJS()
|
|
3674
|
-
{
|
|
3675
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
3676
|
-
// Crypto-JS - https://github.com/brix/crypto-js - MIT License
|
|
3677
|
-
//
|
|
3678
|
-
// [The MIT License (MIT)](http://opensource.org/licenses/MIT)
|
|
3679
|
-
//
|
|
3680
|
-
// Copyright (c) 2009-2013 Jeff Mott
|
|
3681
|
-
// Copyright (c) 2013-2016 Evan Vosberg
|
|
3682
|
-
//
|
|
3683
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3684
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
3685
|
-
// in the Software without restriction, including without limitation the rights
|
|
3686
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
3687
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
3688
|
-
// furnished to do so, subject to the following conditions:
|
|
3689
|
-
//
|
|
3690
|
-
// The above copyright notice and this permission notice shall be included in
|
|
3691
|
-
// all copies or substantial portions of the Software.
|
|
3692
|
-
//
|
|
3693
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
3694
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
3695
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
3696
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
3697
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
3698
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
3699
|
-
// THE SOFTWARE.
|
|
3700
|
-
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));
|
|
3701
|
-
// end of Crypto-JS
|
|
3702
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
3703
|
-
}
|
|
3704
3982
|
}
|
|
3705
3983
|
/**
|
|
3706
3984
|
* LittleJS WebGL Interface
|
|
@@ -3710,6 +3988,7 @@ class Newgrounds
|
|
|
3710
3988
|
* - Can be disabled with glEnable to revert to 2D canvas rendering
|
|
3711
3989
|
* - Batches sprite rendering on GPU for incredibly fast performance
|
|
3712
3990
|
* - Sprite transform math is done in the shader where possible
|
|
3991
|
+
* - Supports shadertoy style post processing shaders
|
|
3713
3992
|
* @namespace WebGL
|
|
3714
3993
|
*/
|
|
3715
3994
|
|
|
@@ -3725,11 +4004,6 @@ let glCanvas;
|
|
|
3725
4004
|
* @memberof WebGL */
|
|
3726
4005
|
let glContext;
|
|
3727
4006
|
|
|
3728
|
-
/** Main tile sheet texture automatically loaded by engine
|
|
3729
|
-
* @type {WebGLTexture}
|
|
3730
|
-
* @memberof WebGL */
|
|
3731
|
-
let glTileTexture;
|
|
3732
|
-
|
|
3733
4007
|
// WebGL internal variables not exposed to documentation
|
|
3734
4008
|
let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
3735
4009
|
|
|
@@ -3738,32 +4012,33 @@ let glActiveTexture, glShader, glArrayBuffer, glPositionData, glColorData, glBat
|
|
|
3738
4012
|
// Initalize WebGL, called automatically by the engine
|
|
3739
4013
|
function glInit()
|
|
3740
4014
|
{
|
|
3741
|
-
// create the canvas and
|
|
4015
|
+
// create the canvas and textures
|
|
3742
4016
|
glCanvas = document.createElement('canvas');
|
|
3743
|
-
glContext = glCanvas.getContext('
|
|
3744
|
-
glTileTexture = glCreateTexture(tileImage);
|
|
4017
|
+
glContext = glCanvas.getContext('webgl2');
|
|
3745
4018
|
|
|
3746
4019
|
// some browsers are much faster without copying the gl buffer so we just overlay it instead
|
|
3747
4020
|
glOverlay && document.body.appendChild(glCanvas);
|
|
3748
4021
|
|
|
3749
4022
|
// setup vertex and fragment shaders
|
|
3750
4023
|
glShader = glCreateProgram(
|
|
4024
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
3751
4025
|
'precision highp float;'+ // use highp for better accuracy
|
|
3752
4026
|
'uniform mat4 m;'+ // transform matrix
|
|
3753
|
-
'
|
|
3754
|
-
'
|
|
3755
|
-
'varying vec4 v,d,e;'+ // return uv, color, additiveColor
|
|
4027
|
+
'in vec4 p,c,a;'+ // position, uv, color, additiveColor
|
|
4028
|
+
'out vec4 v,d,e;'+ // return uv, color, additiveColor
|
|
3756
4029
|
'void main(){'+ // shader entry point
|
|
3757
|
-
'gl_Position=m*vec4(p,1,1);'+ // transform position
|
|
3758
|
-
'v=
|
|
4030
|
+
'gl_Position=m*vec4(p.xy,1,1);'+ // transform position
|
|
4031
|
+
'v=p;d=c;e=a;'+ // pass stuff to fragment shader
|
|
3759
4032
|
'}' // end of shader
|
|
3760
4033
|
,
|
|
3761
|
-
'
|
|
3762
|
-
'
|
|
3763
|
-
'
|
|
3764
|
-
'
|
|
3765
|
-
'
|
|
3766
|
-
'
|
|
4034
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4035
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
4036
|
+
'in vec4 v,d,e;'+ // position, uv, color, additiveColor
|
|
4037
|
+
'uniform sampler2D s;'+ // texture
|
|
4038
|
+
'out vec4 c;'+ // out color
|
|
4039
|
+
'void main(){'+ // shader entry point
|
|
4040
|
+
'c=texture(s,v.zw)*d+e;'+ // modulate texture by color plus additive
|
|
4041
|
+
'}' // end of shader
|
|
3767
4042
|
);
|
|
3768
4043
|
|
|
3769
4044
|
// init buffers
|
|
@@ -3784,10 +4059,10 @@ function glPreRender()
|
|
|
3784
4059
|
// set up the shader
|
|
3785
4060
|
glContext.useProgram(glShader);
|
|
3786
4061
|
glContext.activeTexture(gl_TEXTURE0);
|
|
3787
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture =
|
|
4062
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
|
|
3788
4063
|
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
3789
4064
|
glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
|
|
3790
|
-
|
|
4065
|
+
glAdditive = 0;
|
|
3791
4066
|
|
|
3792
4067
|
// set vertex attributes
|
|
3793
4068
|
let offset = 0;
|
|
@@ -3798,43 +4073,36 @@ function glPreRender()
|
|
|
3798
4073
|
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3799
4074
|
offset += size*typeSize;
|
|
3800
4075
|
}
|
|
3801
|
-
initVertexAttribArray('p', gl_FLOAT, 4,
|
|
3802
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
4076
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture coords
|
|
3803
4077
|
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3804
4078
|
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3805
4079
|
|
|
3806
4080
|
// build the transform matrix
|
|
3807
4081
|
const sx = 2 * cameraScale / mainCanvas.width;
|
|
3808
4082
|
const sy = 2 * cameraScale / mainCanvas.height;
|
|
4083
|
+
const cx = -1 - sx*cameraPos.x;
|
|
4084
|
+
const cy = -1 - sy*cameraPos.y;
|
|
3809
4085
|
glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
|
|
3810
4086
|
new Float32Array([
|
|
3811
|
-
sx,
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
4087
|
+
sx, 0, 0, 0,
|
|
4088
|
+
0, sy, 0, 0,
|
|
4089
|
+
1, 1, -1, 1,
|
|
4090
|
+
cx, cy, 0, 0
|
|
3815
4091
|
])
|
|
3816
4092
|
);
|
|
3817
4093
|
}
|
|
3818
4094
|
|
|
3819
|
-
/** Set the WebGl
|
|
3820
|
-
* @param {Boolean} [additive=0]
|
|
3821
|
-
* @memberof WebGL */
|
|
3822
|
-
function glSetBlendMode(additive)
|
|
3823
|
-
{
|
|
3824
|
-
// setup blending
|
|
3825
|
-
glAdditive = additive;
|
|
3826
|
-
}
|
|
3827
|
-
|
|
3828
|
-
/** Set the WebGl texture, not normally necessary unless multiple tile sheets are used
|
|
4095
|
+
/** Set the WebGl texture, called automatically if using multiple textures
|
|
3829
4096
|
* - This may also flush the gl buffer resulting in more draw calls and worse performance
|
|
3830
|
-
* @param {WebGLTexture}
|
|
4097
|
+
* @param {WebGLTexture} texture
|
|
3831
4098
|
* @memberof WebGL */
|
|
3832
|
-
function glSetTexture(texture
|
|
4099
|
+
function glSetTexture(texture)
|
|
3833
4100
|
{
|
|
3834
4101
|
// must flush cache with the old texture to set a new one
|
|
3835
|
-
if (texture
|
|
3836
|
-
|
|
4102
|
+
if (texture == glActiveTexture)
|
|
4103
|
+
return;
|
|
3837
4104
|
|
|
4105
|
+
glFlush();
|
|
3838
4106
|
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = texture);
|
|
3839
4107
|
}
|
|
3840
4108
|
|
|
@@ -4013,25 +4281,28 @@ function glInitPostProcess(shaderCode, includeOverlay)
|
|
|
4013
4281
|
{
|
|
4014
4282
|
ASSERT(!glPostShader); // can only have 1 post effects shader
|
|
4015
4283
|
|
|
4016
|
-
if (!shaderCode) // default shader
|
|
4017
|
-
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=
|
|
4284
|
+
if (!shaderCode) // default shader pass through
|
|
4285
|
+
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}';
|
|
4018
4286
|
|
|
4019
4287
|
// create the shader
|
|
4020
4288
|
glPostShader = glCreateProgram(
|
|
4289
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4021
4290
|
'precision highp float;'+ // use highp for better accuracy
|
|
4022
|
-
'
|
|
4291
|
+
'in vec2 p;'+ // position
|
|
4023
4292
|
'void main(){'+ // shader entry point
|
|
4024
4293
|
'gl_Position=vec4(p,1,1);'+ // set position
|
|
4025
4294
|
'}' // end of shader
|
|
4026
4295
|
,
|
|
4296
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
4027
4297
|
'precision highp float;'+ // use highp for better accuracy
|
|
4028
4298
|
'uniform sampler2D iChannel0;'+ // input texture
|
|
4029
4299
|
'uniform vec3 iResolution;'+ // size of output texture
|
|
4030
4300
|
'uniform float iTime;'+ // time passed
|
|
4301
|
+
'out vec4 c;'+ // out color
|
|
4031
4302
|
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
4032
4303
|
'void main(){'+ // shader entry point
|
|
4033
|
-
'mainImage(
|
|
4034
|
-
'
|
|
4304
|
+
'mainImage(c,gl_FragCoord.xy);'+ // call post process function
|
|
4305
|
+
'c.a=1.;'+ // always use full alpha
|
|
4035
4306
|
'}' // end of shader
|
|
4036
4307
|
);
|
|
4037
4308
|
|
|
@@ -4056,8 +4327,11 @@ function glRenderPostProcess()
|
|
|
4056
4327
|
glFlush(); // clear out the buffer
|
|
4057
4328
|
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
4058
4329
|
}
|
|
4059
|
-
else
|
|
4330
|
+
else
|
|
4331
|
+
{
|
|
4332
|
+
// set the viewport
|
|
4060
4333
|
glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
|
|
4334
|
+
}
|
|
4061
4335
|
|
|
4062
4336
|
if (glPostIncludeOverlay)
|
|
4063
4337
|
{
|
|
@@ -4104,7 +4378,6 @@ gl_ONE_MINUS_SRC_ALPHA = 771,
|
|
|
4104
4378
|
gl_BLEND = 3042,
|
|
4105
4379
|
gl_TEXTURE_2D = 3553,
|
|
4106
4380
|
gl_UNSIGNED_BYTE = 5121,
|
|
4107
|
-
gl_BYTE = 5120,
|
|
4108
4381
|
gl_FLOAT = 5126,
|
|
4109
4382
|
gl_RGBA = 6408,
|
|
4110
4383
|
gl_NEAREST = 9728,
|
|
@@ -4116,7 +4389,6 @@ gl_TEXTURE_WRAP_T = 10243,
|
|
|
4116
4389
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
4117
4390
|
gl_CLAMP_TO_EDGE = 33071,
|
|
4118
4391
|
gl_TEXTURE0 = 33984,
|
|
4119
|
-
gl_TEXTURE1 = 33985,
|
|
4120
4392
|
gl_ARRAY_BUFFER = 34962,
|
|
4121
4393
|
gl_STATIC_DRAW = 35044,
|
|
4122
4394
|
gl_DYNAMIC_DRAW = 35048,
|
|
@@ -4127,7 +4399,6 @@ gl_LINK_STATUS = 35714,
|
|
|
4127
4399
|
gl_UNPACK_FLIP_Y_WEBGL = 37440,
|
|
4128
4400
|
|
|
4129
4401
|
// constants for batch rendering
|
|
4130
|
-
gl_VERTICES_PER_QUAD = 6,
|
|
4131
4402
|
gl_INDICIES_PER_VERT = 6,
|
|
4132
4403
|
gl_MAX_BATCH = 1e5,
|
|
4133
4404
|
gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2, // vec2 * 2 + (char * 4) * 2
|
|
@@ -4164,7 +4435,7 @@ const engineName = 'LittleJS';
|
|
|
4164
4435
|
* @type {String}
|
|
4165
4436
|
* @default
|
|
4166
4437
|
* @memberof Engine */
|
|
4167
|
-
const engineVersion = '1.
|
|
4438
|
+
const engineVersion = '1.8.3';
|
|
4168
4439
|
|
|
4169
4440
|
/** Frames per second to update objects
|
|
4170
4441
|
* @type {Number}
|
|
@@ -4214,6 +4485,9 @@ let paused = 0;
|
|
|
4214
4485
|
* @memberof Engine */
|
|
4215
4486
|
function setPaused(_paused) { paused = _paused; }
|
|
4216
4487
|
|
|
4488
|
+
// Frame time tracking
|
|
4489
|
+
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
4490
|
+
|
|
4217
4491
|
///////////////////////////////////////////////////////////////////////////////
|
|
4218
4492
|
|
|
4219
4493
|
/** Start up LittleJS engine with your callback functions
|
|
@@ -4222,52 +4496,13 @@ function setPaused(_paused) { paused = _paused; }
|
|
|
4222
4496
|
* @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
|
|
4223
4497
|
* @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
|
|
4224
4498
|
* @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
|
|
4225
|
-
* @param {
|
|
4499
|
+
* @param {Array} [imageSources=['tiles.png']] - Image to load
|
|
4226
4500
|
* @memberof Engine */
|
|
4227
|
-
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost,
|
|
4501
|
+
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
|
|
4228
4502
|
{
|
|
4229
|
-
//
|
|
4230
|
-
tileImage.onerror = tileImage.onload = ()=>
|
|
4231
|
-
{
|
|
4232
|
-
// save tile image info
|
|
4233
|
-
tileImageFixBleed = vec2(tileFixBleedScale).divide(tileImageSize = vec2(tileImage.width, tileImage.height));
|
|
4234
|
-
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
4235
|
-
|
|
4236
|
-
// setup html
|
|
4237
|
-
const styleBody =
|
|
4238
|
-
'margin:0;overflow:hidden;' + // fill the window
|
|
4239
|
-
'background:#000;' + // set background color
|
|
4240
|
-
'touch-action:none;' + // prevent mobile pinch to resize
|
|
4241
|
-
'user-select:none;' + // prevent mobile hold to select
|
|
4242
|
-
'-webkit-user-select:none;' + // compatibility for ios
|
|
4243
|
-
'-webkit-touch-callout:none'; // compatibility for ios
|
|
4244
|
-
document.body.style = styleBody;
|
|
4245
|
-
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
4246
|
-
mainContext = mainCanvas.getContext('2d');
|
|
4247
|
-
|
|
4248
|
-
// init stuff and start engine
|
|
4249
|
-
debugInit();
|
|
4250
|
-
glEnable && glInit();
|
|
4251
|
-
|
|
4252
|
-
// create overlay canvas for hud to appear above gl canvas
|
|
4253
|
-
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
4254
|
-
overlayContext = overlayCanvas.getContext('2d');
|
|
4255
|
-
|
|
4256
|
-
// set canvas style
|
|
4257
|
-
const styleCanvas =
|
|
4258
|
-
'position:absolute;' + // position canvas
|
|
4259
|
-
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
|
|
4260
|
-
(canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
|
|
4261
|
-
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
4262
|
-
|
|
4263
|
-
gameInit();
|
|
4264
|
-
engineUpdate();
|
|
4265
|
-
};
|
|
4266
|
-
|
|
4267
|
-
// frame time tracking
|
|
4268
|
-
let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
4503
|
+
ASSERT(Array.isArray(imageSources)); // pass in images as array
|
|
4269
4504
|
|
|
4270
|
-
//
|
|
4505
|
+
// internal update loop for engine
|
|
4271
4506
|
function engineUpdate(frameTimeMS=0)
|
|
4272
4507
|
{
|
|
4273
4508
|
// update time keeping
|
|
@@ -4298,9 +4533,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4298
4533
|
}
|
|
4299
4534
|
else
|
|
4300
4535
|
{
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4536
|
+
// clear canvas and set size to same as window
|
|
4537
|
+
mainCanvas.width = min(innerWidth, canvasMaxSize.x);
|
|
4538
|
+
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
4304
4539
|
}
|
|
4305
4540
|
|
|
4306
4541
|
// clear overlay canvas and set size
|
|
@@ -4332,6 +4567,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4332
4567
|
// update multiple frames if necessary in case of slow framerate
|
|
4333
4568
|
for (;frameTimeBufferMS >= 0; frameTimeBufferMS -= 1e3 / frameRate)
|
|
4334
4569
|
{
|
|
4570
|
+
// increment frame and update time
|
|
4571
|
+
time = frame++ / frameRate;
|
|
4572
|
+
|
|
4335
4573
|
// update game and objects
|
|
4336
4574
|
inputUpdate();
|
|
4337
4575
|
gameUpdate();
|
|
@@ -4379,8 +4617,51 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4379
4617
|
requestAnimationFrame(engineUpdate);
|
|
4380
4618
|
}
|
|
4381
4619
|
|
|
4382
|
-
//
|
|
4383
|
-
|
|
4620
|
+
// setup html
|
|
4621
|
+
const styleBody =
|
|
4622
|
+
'margin:0;overflow:hidden;' + // fill the window
|
|
4623
|
+
'background:#000;' + // set background color
|
|
4624
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
4625
|
+
'user-select:none;' + // prevent mobile hold to select
|
|
4626
|
+
'-webkit-user-select:none;' + // compatibility for ios
|
|
4627
|
+
'-webkit-touch-callout:none'; // compatibility for ios
|
|
4628
|
+
document.body.style = styleBody;
|
|
4629
|
+
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
4630
|
+
mainContext = mainCanvas.getContext('2d');
|
|
4631
|
+
|
|
4632
|
+
// init stuff and start engine
|
|
4633
|
+
debugInit();
|
|
4634
|
+
glEnable && glInit();
|
|
4635
|
+
|
|
4636
|
+
// create overlay canvas for hud to appear above gl canvas
|
|
4637
|
+
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
4638
|
+
overlayContext = overlayCanvas.getContext('2d');
|
|
4639
|
+
|
|
4640
|
+
// set canvas style
|
|
4641
|
+
const styleCanvas =
|
|
4642
|
+
'position:absolute;' + // position
|
|
4643
|
+
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center
|
|
4644
|
+
(canvasPixelated?'image-rendering:pixelated':''); // pixelated rendering
|
|
4645
|
+
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
4646
|
+
|
|
4647
|
+
// load all of the images
|
|
4648
|
+
Promise.all(imageSources.map((src, textureIndex)=>
|
|
4649
|
+
new Promise((resolve, reject)=>
|
|
4650
|
+
{
|
|
4651
|
+
const image = new Image;
|
|
4652
|
+
image.onerror = image.onload = ()=>
|
|
4653
|
+
{
|
|
4654
|
+
textureInfos[textureIndex] = new TextureInfo(image);
|
|
4655
|
+
resolve();
|
|
4656
|
+
}
|
|
4657
|
+
image.src = src;
|
|
4658
|
+
})
|
|
4659
|
+
)).then(()=>
|
|
4660
|
+
{
|
|
4661
|
+
// start the engine
|
|
4662
|
+
gameInit();
|
|
4663
|
+
engineUpdate();
|
|
4664
|
+
});
|
|
4384
4665
|
}
|
|
4385
4666
|
|
|
4386
4667
|
// Called automatically by engine to setup render system
|
|
@@ -4418,9 +4699,6 @@ function engineObjectsUpdate()
|
|
|
4418
4699
|
|
|
4419
4700
|
// remove destroyed objects
|
|
4420
4701
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
4421
|
-
|
|
4422
|
-
// increment frame and update time
|
|
4423
|
-
time = ++frame / frameRate;
|
|
4424
4702
|
}
|
|
4425
4703
|
|
|
4426
4704
|
/** Destroy and remove all objects
|