littlejsengine 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -9
- package/build.bat +5 -5
- package/buildSetup.bat +7 -0
- package/engine/engine.all.js +193 -125
- package/engine/engine.all.min.js +1 -1
- package/engine/engine.all.release.js +183 -110
- package/engine/engine.js +10 -33
- package/engine/engineBuild.bat +3 -3
- package/engine/engineDebug.js +10 -15
- package/engine/engineDraw.js +38 -17
- package/engine/engineFont.png +0 -0
- package/engine/engineInput.js +22 -6
- package/engine/engineMedals.js +7 -4
- package/engine/engineObject.js +17 -1
- package/engine/engineParticles.js +5 -3
- package/engine/engineSettings.js +5 -0
- package/engine/engineTileLayer.js +11 -10
- package/engine/engineUtilities.js +38 -6
- package/engine/engineWebGL.js +30 -30
- package/engine/index.d.ts +55 -21
- package/examples/breakout/gameObjects.js +2 -2
- package/examples/breakout/index.html +3 -3
- package/examples/particles/index.html +366 -0
- package/examples/particles/tiles.png +0 -0
- package/examples/platformer/game.js +4 -4
- package/examples/platformer/gameEffects.js +9 -9
- package/examples/platformer/gameObjects.js +2 -2
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/game.js +2 -2
- package/examples/puzzle/index.html +2 -2
- package/examples/screenshot.jpg +0 -0
- package/examples/stress/index.html +2 -2
- package/game.js +4 -4
- package/index.html +13 -13
- package/package.json +1 -1
- package/engine/engineBuildSetup.bat +0 -7
package/engine/index.d.ts
CHANGED
|
@@ -60,7 +60,19 @@ declare function drawCanvas2D(pos: Vector2, size: Vector2, angle: number, mirror
|
|
|
60
60
|
* @param {Boolean} [useWebGL=glEnable]
|
|
61
61
|
* @memberof Draw */
|
|
62
62
|
declare function setBlendMode(additive?: boolean, useWebGL?: boolean): void;
|
|
63
|
+
/** Draw text on overlay canvas in screen space
|
|
64
|
+
* Automatically splits new lines into rows
|
|
65
|
+
* @param {String} text
|
|
66
|
+
* @param {Vector2} pos
|
|
67
|
+
* @param {Number} [size=1]
|
|
68
|
+
* @param {Color} [color=new Color(1,1,1)]
|
|
69
|
+
* @param {Number} [lineWidth=0]
|
|
70
|
+
* @param {Color} [lineColor=new Color(0,0,0)]
|
|
71
|
+
* @param {String} [textAlign='center']
|
|
72
|
+
* @memberof Draw */
|
|
73
|
+
declare function drawTextScreen(text: string, pos: Vector2, size?: number, color?: Color, lineWidth?: number, lineColor?: Color, textAlign?: string, font?: string): void;
|
|
63
74
|
/** Draw text on overlay canvas in world space
|
|
75
|
+
* Automatically splits new lines into rows
|
|
64
76
|
* @param {String} text
|
|
65
77
|
* @param {Vector2} pos
|
|
66
78
|
* @param {Number} [size=1]
|
|
@@ -69,7 +81,7 @@ declare function setBlendMode(additive?: boolean, useWebGL?: boolean): void;
|
|
|
69
81
|
* @param {Color} [lineColor=new Color(0,0,0)]
|
|
70
82
|
* @param {String} [textAlign='center']
|
|
71
83
|
* @memberof Draw */
|
|
72
|
-
declare function drawText(text: string, pos: Vector2, size?: number, color?: Color, lineWidth?: number, lineColor?: Color, textAlign?: string, font
|
|
84
|
+
declare function drawText(text: string, pos: Vector2, size?: number, color?: Color, lineWidth?: number, lineColor?: Color, textAlign?: string, font: any): void;
|
|
73
85
|
/** Toggle fullsceen mode
|
|
74
86
|
* @memberof Draw */
|
|
75
87
|
declare function toggleFullscreen(): void;
|
|
@@ -551,6 +563,10 @@ declare class Vector2 {
|
|
|
551
563
|
* @param {Vector2} arraySize
|
|
552
564
|
* @return {Boolean} */
|
|
553
565
|
arrayCheck(arraySize: Vector2): boolean;
|
|
566
|
+
/** Returns this vector expressed as a string
|
|
567
|
+
* @param {float} digits - precision to display
|
|
568
|
+
* @return {String} */
|
|
569
|
+
toString(digits?: float): string;
|
|
554
570
|
}
|
|
555
571
|
/**
|
|
556
572
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
@@ -606,7 +622,7 @@ declare class Color {
|
|
|
606
622
|
* @param {Number} percent
|
|
607
623
|
* @return {Color} */
|
|
608
624
|
lerp(c: any, p: any): Color;
|
|
609
|
-
/** Sets this color given a hue, saturation, lightness
|
|
625
|
+
/** Sets this color given a hue, saturation, lightness, and alpha
|
|
610
626
|
* @param {Number} [hue=0]
|
|
611
627
|
* @param {Number} [saturation=0]
|
|
612
628
|
* @param {Number} [lightness=1]
|
|
@@ -618,12 +634,19 @@ declare class Color {
|
|
|
618
634
|
* @param {Number} [alphaAmount=0]
|
|
619
635
|
* @return {Color} */
|
|
620
636
|
mutate(amount?: number, alphaAmount?: number): Color;
|
|
621
|
-
/** Returns this color expressed as an
|
|
637
|
+
/** Returns this color expressed as an CSS color value
|
|
622
638
|
* @return {String} */
|
|
623
|
-
|
|
624
|
-
/** Returns this color expressed as 32 bit integer value
|
|
639
|
+
toString(): string;
|
|
640
|
+
/** Returns this color expressed as 32 bit integer RGBA value
|
|
625
641
|
* @return {Number} */
|
|
626
642
|
rgbaInt(): number;
|
|
643
|
+
/** Returns this color expressed as a hex code
|
|
644
|
+
* @return {String} */
|
|
645
|
+
hex(): string;
|
|
646
|
+
/** Set this color from a hex code
|
|
647
|
+
* @param {String} hex - html hex code
|
|
648
|
+
* @return {Color} */
|
|
649
|
+
setHex(hex: string): Color;
|
|
627
650
|
}
|
|
628
651
|
/**
|
|
629
652
|
* Timer object tracks how long has passed since it was set
|
|
@@ -660,6 +683,9 @@ declare class Timer {
|
|
|
660
683
|
/** Get percentage elapsed based on time it was set to, returns 0 if not set
|
|
661
684
|
* @return {Number} */
|
|
662
685
|
getPercent(): number;
|
|
686
|
+
/** Returns this timer expressed as a string
|
|
687
|
+
* @return {String} */
|
|
688
|
+
toString(): string;
|
|
663
689
|
}
|
|
664
690
|
/** The max size of the canvas, centered if window is larger
|
|
665
691
|
* @type {Vector2}
|
|
@@ -760,6 +786,10 @@ declare let inputWASDEmulateDirection: number;
|
|
|
760
786
|
* @default
|
|
761
787
|
* @memberof Settings */
|
|
762
788
|
declare let touchGamepadEnable: number;
|
|
789
|
+
/** True if touch gamepad should be analog stick or false to use if 8 way dpad
|
|
790
|
+
* @default
|
|
791
|
+
* @memberof Settings */
|
|
792
|
+
declare let touchGamepadAnalog: number;
|
|
763
793
|
/** Size of virutal gamepad for touch devices in pixels
|
|
764
794
|
* @default
|
|
765
795
|
* @memberof Settings */
|
|
@@ -839,7 +869,7 @@ declare class EngineObject {
|
|
|
839
869
|
* @param {Vector2} [size=objectDefaultSize] - World space size of the object
|
|
840
870
|
* @param {Number} [tileIndex=-1] - Tile to use to render object, untextured if -1
|
|
841
871
|
* @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
|
|
842
|
-
* @param {Number} [angle=0] - Angle
|
|
872
|
+
* @param {Number} [angle=0] - Angle the object is rotated by
|
|
843
873
|
* @param {Color} [color] - Color to apply to tile when rendered
|
|
844
874
|
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
845
875
|
*/
|
|
@@ -927,6 +957,7 @@ declare class EngineObject {
|
|
|
927
957
|
setCollision(collideSolidObjects?: boolean, isSolid?: boolean, collideTiles?: boolean): void;
|
|
928
958
|
collideSolidObjects: boolean;
|
|
929
959
|
isSolid: boolean;
|
|
960
|
+
toString(): string;
|
|
930
961
|
}
|
|
931
962
|
/** Tile sheet for batch rendering system
|
|
932
963
|
* @type {Image}
|
|
@@ -974,6 +1005,7 @@ declare function worldToScreen(worldPos: Vector2): Vector2;
|
|
|
974
1005
|
* // draw text
|
|
975
1006
|
* font.drawTextScreen("LittleJS\nHello World!", vec2(200, 50));
|
|
976
1007
|
*/
|
|
1008
|
+
declare let engineFontImage: any;
|
|
977
1009
|
declare class FontImage {
|
|
978
1010
|
/** Create an image font
|
|
979
1011
|
* @param {Image} [image] - The image the font is stored in, if undefined the default font is used
|
|
@@ -983,7 +1015,7 @@ declare class FontImage {
|
|
|
983
1015
|
* @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
|
|
984
1016
|
*/
|
|
985
1017
|
constructor(image?: new (width?: number, height?: number) => HTMLImageElement, tileSize?: Vector2, paddingSize?: Vector2, startTileIndex?: number, context?: CanvasRenderingContext2D);
|
|
986
|
-
image:
|
|
1018
|
+
image: any;
|
|
987
1019
|
tileSize: Vector2;
|
|
988
1020
|
paddingSize: Vector2;
|
|
989
1021
|
startTileIndex: number;
|
|
@@ -1102,7 +1134,6 @@ declare const isTouchDevice: boolean;
|
|
|
1102
1134
|
declare let touchGamepadTimer: Timer;
|
|
1103
1135
|
declare let touchGamepadButtons: any[];
|
|
1104
1136
|
declare let touchGamepadStick: Vector2;
|
|
1105
|
-
declare let touchGamepadAnalog: number;
|
|
1106
1137
|
/**
|
|
1107
1138
|
* Sound Object - Stores a zzfx sound for later use and can be played positionally
|
|
1108
1139
|
* <br>
|
|
@@ -1268,12 +1299,12 @@ declare class TileLayerData {
|
|
|
1268
1299
|
*/
|
|
1269
1300
|
declare class TileLayer extends EngineObject {
|
|
1270
1301
|
/** Create a tile layer object
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1302
|
+
* @param {Vector2} [position=new Vector2()] - World space position
|
|
1303
|
+
* @param {Vector2} [size=tileCollisionSize] - World space size
|
|
1304
|
+
* @param {Vector2} [tileSize=tileSizeDefault] - Size of tiles in source pixels
|
|
1305
|
+
* @param {Vector2} [scale=new Vector2(1,1)] - How much to scale this layer when rendered
|
|
1306
|
+
* @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
|
|
1307
|
+
*/
|
|
1277
1308
|
constructor(pos: any, size?: Vector2, tileSize?: Vector2, scale?: Vector2, renderOrder?: number);
|
|
1278
1309
|
/** @property {HTMLCanvasElement} - The canvas used by this tile layer */
|
|
1279
1310
|
canvas: HTMLCanvasElement;
|
|
@@ -1337,9 +1368,9 @@ declare class TileLayer extends EngineObject {
|
|
|
1337
1368
|
* let pos = vec2(2,3);
|
|
1338
1369
|
* let particleEmiter = new ParticleEmitter
|
|
1339
1370
|
* (
|
|
1340
|
-
* pos, 1, 0, 500, PI, // pos, emitSize, emitTime, emitRate, emiteCone
|
|
1371
|
+
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
1341
1372
|
* 0, vec2(16), // tileIndex, tileSize
|
|
1342
|
-
* new Color,
|
|
1373
|
+
* new Color(1,1,1), new Color(0,0,0), // colorStartA, colorStartB
|
|
1343
1374
|
* new Color(1,1,1,0), new Color(0,0,0,0), // colorEndA, colorEndB
|
|
1344
1375
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
1345
1376
|
* .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
|
|
@@ -1349,6 +1380,7 @@ declare class TileLayer extends EngineObject {
|
|
|
1349
1380
|
declare class ParticleEmitter extends EngineObject {
|
|
1350
1381
|
/** Create a particle system with the given settings
|
|
1351
1382
|
* @param {Vector2} position - World space position of the emitter
|
|
1383
|
+
* @param {Number} [angle=0] - Angle to emit the particles
|
|
1352
1384
|
* @param {Number} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
|
|
1353
1385
|
* @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
|
|
1354
1386
|
* @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
|
|
@@ -1375,7 +1407,7 @@ declare class ParticleEmitter extends EngineObject {
|
|
|
1375
1407
|
* @param {Boolean} [randomColorLinear=1] - Should color be randomized linearly or across each component
|
|
1376
1408
|
* @param {Number} [renderOrder=0] - Render order for particles (additive is above other stuff by default)
|
|
1377
1409
|
*/
|
|
1378
|
-
constructor(pos: any, emitSize?: number, emitTime?: number, emitRate?: number, emitConeAngle?: number, tileIndex?: number, tileSize?: number, colorStartA?: Color, colorStartB?: Color, colorEndA?: Color, colorEndB?: Color, particleTime?: number, sizeStart?: number, sizeEnd?: number, speed?: number, angleSpeed?: number, damping?: number, angleDamping?: number, gravityScale?: number, particleConeAngle?: number, fadeRate?: number, randomness?: number, collideTiles?: boolean, additive?: boolean, randomColorLinear?: boolean, renderOrder?: number);
|
|
1410
|
+
constructor(pos: any, angle?: number, emitSize?: number, emitTime?: number, emitRate?: number, emitConeAngle?: number, tileIndex?: number, tileSize?: number, colorStartA?: Color, colorStartB?: Color, colorEndA?: Color, colorEndB?: Color, particleTime?: number, sizeStart?: number, sizeEnd?: number, speed?: number, angleSpeed?: number, damping?: number, angleDamping?: number, gravityScale?: number, particleConeAngle?: number, fadeRate?: number, randomness?: number, collideTiles?: boolean, additive?: boolean, randomColorLinear?: boolean, renderOrder?: number);
|
|
1379
1411
|
/** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
|
|
1380
1412
|
emitSize: number;
|
|
1381
1413
|
/** @property {Number} - How long to stay alive (0 is forever) */
|
|
@@ -1410,6 +1442,8 @@ declare class ParticleEmitter extends EngineObject {
|
|
|
1410
1442
|
fadeRate: number;
|
|
1411
1443
|
/** @property {Number} - Apply extra randomness percent */
|
|
1412
1444
|
randomness: number;
|
|
1445
|
+
/** @property {Number} - Do particles collide against tiles */
|
|
1446
|
+
collideTiles: boolean;
|
|
1413
1447
|
/** @property {Number} - Should particles use addtive blend */
|
|
1414
1448
|
additive: boolean;
|
|
1415
1449
|
/** @property {Number} - If set the partile is drawn as a trail, stretched in the drection of velocity */
|
|
@@ -1514,8 +1548,6 @@ declare class Newgrounds {
|
|
|
1514
1548
|
* @param {Number} id - The scoreboard id
|
|
1515
1549
|
* @param {Number} value - The score value */
|
|
1516
1550
|
postScore(id: number, value: number): any;
|
|
1517
|
-
/** Send message to log a view */
|
|
1518
|
-
logView(): any;
|
|
1519
1551
|
/** Get scores from a scoreboard
|
|
1520
1552
|
* @param {Number} id - The scoreboard id
|
|
1521
1553
|
* @param {String} [user=0] - A user's id or name
|
|
@@ -1525,6 +1557,8 @@ declare class Newgrounds {
|
|
|
1525
1557
|
* @return {Object} - The response JSON object
|
|
1526
1558
|
*/
|
|
1527
1559
|
getScores(id: number, user?: string, social?: number, skip?: number, limit?: number): any;
|
|
1560
|
+
/** Send message to log a view */
|
|
1561
|
+
logView(): any;
|
|
1528
1562
|
/** Send a message to call a component of the Newgrounds API
|
|
1529
1563
|
* @param {String} component - Name of the component
|
|
1530
1564
|
* @param {Object} [parameters=0] - Parameters to use for call
|
|
@@ -1583,7 +1617,7 @@ declare const gl_VERTEX_BYTE_STRIDE: number;
|
|
|
1583
1617
|
/** Name of engine */
|
|
1584
1618
|
declare const engineName: "LittleJS";
|
|
1585
1619
|
/** Version of engine */
|
|
1586
|
-
declare const engineVersion: "1.
|
|
1620
|
+
declare const engineVersion: "1.3.0";
|
|
1587
1621
|
/** Frames per second to update objects
|
|
1588
1622
|
* @default */
|
|
1589
1623
|
declare const frameRate: 60;
|
|
@@ -1609,4 +1643,4 @@ declare let tileImageFixBleed: any;
|
|
|
1609
1643
|
declare let averageFPS: any;
|
|
1610
1644
|
declare let drawCount: any;
|
|
1611
1645
|
declare const styleBody: string;
|
|
1612
|
-
declare const styleCanvas: "position:absolute";
|
|
1646
|
+
declare const styleCanvas: "position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";
|
|
@@ -56,11 +56,11 @@ class Block extends EngineObject
|
|
|
56
56
|
const color1 = this.color;
|
|
57
57
|
const color2 = color1.lerp(new Color, .5);
|
|
58
58
|
new ParticleEmitter(
|
|
59
|
-
this.pos, this.size, .1, 200, PI,
|
|
59
|
+
this.pos, 0, this.size, .1, 200, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
60
60
|
0, vec2(16), // tileIndex, tileSize
|
|
61
61
|
color1, color2, // colorStartA, colorStartB
|
|
62
62
|
color1.scale(1,0), color2.scale(1,0), // colorEndA, colorEndB
|
|
63
|
-
.2, 1, 1, .1, .05,
|
|
63
|
+
.2, 1, 1, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
64
64
|
.99, .95, .4, PI, .1, // damping, angleDamping, gravityScale, particleCone, fadeRate,
|
|
65
65
|
1, 0, 1 // randomness, collide, additive, randomColorLinear, renderOrder
|
|
66
66
|
);
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
<link rel=icon type=image/png href=../../favicon.png>
|
|
6
6
|
</head><body>
|
|
7
7
|
|
|
8
|
-
<script src=../../engine/engine.all.js?
|
|
9
|
-
<script src=game.js?
|
|
10
|
-
<script src=gameObjects.js?
|
|
8
|
+
<script src=../../engine/engine.all.js?104></script>
|
|
9
|
+
<script src=game.js?104></script>
|
|
10
|
+
<script src=gameObjects.js?104></script>
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
<html><head><meta charset=utf-8>
|
|
2
|
+
<meta name=viewport content=width=device-width,height=device-height,initial-scale=1,maximum-scale=1>
|
|
3
|
+
<meta name=apple-mobile-web-app-capable content=yes>
|
|
4
|
+
<meta name=mobile-web-app-capable content=yes>
|
|
5
|
+
<link rel=icon type=image/png href=favicon.png>
|
|
6
|
+
<style>
|
|
7
|
+
input
|
|
8
|
+
{
|
|
9
|
+
width:99px;
|
|
10
|
+
}
|
|
11
|
+
button
|
|
12
|
+
{
|
|
13
|
+
margin:1px;
|
|
14
|
+
}
|
|
15
|
+
</style>
|
|
16
|
+
</head><body>
|
|
17
|
+
|
|
18
|
+
<script src=../../engine/engineDebug.js?104></script>
|
|
19
|
+
<script src=../../engine/engineUtilities.js?104></script>
|
|
20
|
+
<script src=../../engine/engineSettings.js?104></script>
|
|
21
|
+
<script src=../../engine/engineObject.js?104></script>
|
|
22
|
+
<script src=../../engine/engineDraw.js?104></script>
|
|
23
|
+
<script src=../../engine/engineInput.js?104></script>
|
|
24
|
+
<script src=../../engine/engineAudio.js?104></script>
|
|
25
|
+
<script src=../../engine/engineTileLayer.js?104></script>
|
|
26
|
+
<script src=../../engine/engineParticles.js?104></script>
|
|
27
|
+
<script src=../../engine/engineMedals.js?104></script>
|
|
28
|
+
<script src=../../engine/engineWebGL.js?104></script>
|
|
29
|
+
<script src=../../engine/engine.js?104></script>
|
|
30
|
+
<script>
|
|
31
|
+
|
|
32
|
+
'use strict';
|
|
33
|
+
|
|
34
|
+
let particleEditor = 0, particleSystem, particleSystemDiv, particleSystemCode;
|
|
35
|
+
let inputCondense;
|
|
36
|
+
let restartTimer = new Timer();
|
|
37
|
+
const storagePrefix = 'particles_';
|
|
38
|
+
|
|
39
|
+
const particleSettings = [];
|
|
40
|
+
function addSetting(name, type, min, max, step, description)
|
|
41
|
+
{
|
|
42
|
+
particleSettings.push({name, type:type||'number', min, max, step, description});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
addSetting('emitSize', '', 0, 1e9, .1);
|
|
46
|
+
addSetting('emitTime', '', 0, 1e9, .1);
|
|
47
|
+
addSetting('emitRate', '', 0, 1e9, 1);
|
|
48
|
+
addSetting('emitConeAngle', '', 0, 1e9, .01);
|
|
49
|
+
addSetting('tileIndex', '', -1, 1e9, 1);
|
|
50
|
+
addSetting('tileSizeX', '', 0, 1e9, 1);
|
|
51
|
+
addSetting('tileSizeY', '', 0, 1e9, 1);
|
|
52
|
+
addSetting('colorStartA', 'color');
|
|
53
|
+
addSetting('colorStartB', 'color');
|
|
54
|
+
addSetting('colorEndA', 'color');
|
|
55
|
+
addSetting('colorEndB', 'color');
|
|
56
|
+
addSetting('colorAlphaStartA', 'alpha', 0, 1, .01);
|
|
57
|
+
addSetting('colorAlphaStartB', 'alpha', 0, 1, .01);
|
|
58
|
+
addSetting('colorAlphaEndA', 'alpha', 0, 1, .01);
|
|
59
|
+
addSetting('colorAlphaEndB', 'alpha', 0, 1, .01);
|
|
60
|
+
addSetting('particleTime', '', 0, 1e9, .1);
|
|
61
|
+
addSetting('sizeStart', '', 0, 1e9, .01);
|
|
62
|
+
addSetting('sizeEnd', '', 0, 1e9, .01);
|
|
63
|
+
addSetting('speed', '', 0, 1e9, .01);
|
|
64
|
+
addSetting('angleSpeed', '', 0, 1e9, .01);
|
|
65
|
+
addSetting('damping', '', 0, 1, .01);
|
|
66
|
+
addSetting('angleDamping', '', 0, 1, .01);
|
|
67
|
+
addSetting('gravityScale', '', -1e9, 1e9, .1);
|
|
68
|
+
addSetting('particleConeAngle','', 0, 1e9, .1);
|
|
69
|
+
addSetting('fadeRate', '', 0, 1, .01);
|
|
70
|
+
addSetting('randomness', '', 0, 1, .01);
|
|
71
|
+
addSetting('collideTiles', 'checkbox');
|
|
72
|
+
addSetting('additive', 'checkbox');
|
|
73
|
+
addSetting('randomColorLinear','checkbox');
|
|
74
|
+
|
|
75
|
+
function makeEmitter()
|
|
76
|
+
{
|
|
77
|
+
particleSystem = new ParticleEmitter(cameraPos);
|
|
78
|
+
particleSystem.emitConeAngle =
|
|
79
|
+
particleSystem.particleConeAngle = 3.14;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
83
|
+
function gameInit()
|
|
84
|
+
{
|
|
85
|
+
makeEmitter();
|
|
86
|
+
gravity = -.01;
|
|
87
|
+
cameraScale = 50;
|
|
88
|
+
|
|
89
|
+
const div = particleSystemDiv = document.createElement('div');
|
|
90
|
+
div.innerHTML = '<big><b>LittleJS Particle Tool';
|
|
91
|
+
div.style = 'position:absolute;top:10;left:10;color:#fff';
|
|
92
|
+
document.body.appendChild(div);
|
|
93
|
+
|
|
94
|
+
for (const setting of particleSettings)
|
|
95
|
+
{
|
|
96
|
+
const input = setting.input = document.createElement('input');
|
|
97
|
+
const name = setting.name;
|
|
98
|
+
input.oninput = (e)=> updateParticles();
|
|
99
|
+
input.type = setting.type == 'alpha' ? 'number' : setting.type;
|
|
100
|
+
if (setting.min !== undefined)
|
|
101
|
+
input.min = setting.min;
|
|
102
|
+
if (setting.max !== undefined)
|
|
103
|
+
input.max = setting.max;
|
|
104
|
+
if (setting.step !== undefined)
|
|
105
|
+
input.step = setting.step;
|
|
106
|
+
if (name == 'emitConeAngle' || name == 'particleConeAngle')
|
|
107
|
+
particleSystem[name] = 3.14; // simplify pi
|
|
108
|
+
|
|
109
|
+
div.appendChild(document.createElement('br'));
|
|
110
|
+
div.appendChild(input);
|
|
111
|
+
div.appendChild(document.createTextNode(' ' + name));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
div.appendChild(document.createElement('br'));
|
|
115
|
+
div.appendChild(document.createElement('br'));
|
|
116
|
+
|
|
117
|
+
{
|
|
118
|
+
const button = document.createElement('button')
|
|
119
|
+
div.appendChild(button);
|
|
120
|
+
button.innerHTML = 'Copy To Clipboard';
|
|
121
|
+
button.onclick = (e)=> navigator.clipboard.writeText(particleSystemCode.value);
|
|
122
|
+
}
|
|
123
|
+
{
|
|
124
|
+
const button = document.createElement('button');
|
|
125
|
+
div.appendChild(button);
|
|
126
|
+
button.innerHTML = 'Reset';
|
|
127
|
+
button.onclick = (e)=>
|
|
128
|
+
{
|
|
129
|
+
if (!confirm('Reset to default?'))
|
|
130
|
+
return;
|
|
131
|
+
particleSystem.destroy();
|
|
132
|
+
makeEmitter();
|
|
133
|
+
updateInputs(0);
|
|
134
|
+
cameraScale = 50;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
{
|
|
138
|
+
inputCondense = document.createElement('input');
|
|
139
|
+
div.appendChild(inputCondense);
|
|
140
|
+
inputCondense.checked = 'true';
|
|
141
|
+
inputCondense.type = 'checkbox';
|
|
142
|
+
inputCondense.style.width = 'initial';
|
|
143
|
+
inputCondense.oninput = (e)=> updateParticles();
|
|
144
|
+
div.appendChild(document.createTextNode(' Condense'));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//div.appendChild(document.createTextNode('JavaScript Code... '));
|
|
148
|
+
div.appendChild(document.createElement('br'));
|
|
149
|
+
div.appendChild(particleSystemCode = document.createElement('textarea'));
|
|
150
|
+
particleSystemCode.style.width = 500;
|
|
151
|
+
particleSystemCode.style.height = 100;
|
|
152
|
+
particleSystemCode.disabled = true;
|
|
153
|
+
|
|
154
|
+
updateInputs(0);
|
|
155
|
+
|
|
156
|
+
// load from storage
|
|
157
|
+
for (const setting of particleSettings)
|
|
158
|
+
{
|
|
159
|
+
const type = setting.type;
|
|
160
|
+
const storageName = storagePrefix + setting.name;
|
|
161
|
+
const savedValue = localStorage[storageName];
|
|
162
|
+
if (savedValue == undefined)
|
|
163
|
+
continue;
|
|
164
|
+
|
|
165
|
+
if (type == 'checkbox')
|
|
166
|
+
setting.input.checked = savedValue == 'true';
|
|
167
|
+
else
|
|
168
|
+
setting.input.value = savedValue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
updateParticles();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function updateParticles()
|
|
175
|
+
{
|
|
176
|
+
for (const setting of particleSettings)
|
|
177
|
+
{
|
|
178
|
+
const input = setting.input;
|
|
179
|
+
const name = setting.name;
|
|
180
|
+
const type = setting.type;
|
|
181
|
+
const inputFloat = parseFloat(input.value) || 0;
|
|
182
|
+
if (type == 'color')
|
|
183
|
+
{
|
|
184
|
+
const color = new Color().setHex(input.value);
|
|
185
|
+
particleSystem[name].r = color.r;
|
|
186
|
+
particleSystem[name].g = color.g;
|
|
187
|
+
particleSystem[name].b = color.b;
|
|
188
|
+
}
|
|
189
|
+
else if (type == 'alpha')
|
|
190
|
+
{
|
|
191
|
+
if (name == 'colorAlphaStartA')
|
|
192
|
+
particleSystem.colorStartA.a = clamp(inputFloat);
|
|
193
|
+
else if (name == 'colorAlphaStartB')
|
|
194
|
+
particleSystem.colorStartB.a = clamp(inputFloat);
|
|
195
|
+
else if (name == 'colorAlphaEndA')
|
|
196
|
+
particleSystem.colorEndA.a = clamp(inputFloat);
|
|
197
|
+
else if (name == 'colorAlphaEndB')
|
|
198
|
+
particleSystem.colorEndB.a = clamp(inputFloat);
|
|
199
|
+
}
|
|
200
|
+
else if (name == 'tileSizeX')
|
|
201
|
+
{
|
|
202
|
+
particleSystem.tileSize = vec2(parseInt(input.value), particleSystem.tileSize.y);
|
|
203
|
+
}
|
|
204
|
+
else if (name == 'tileSizeY')
|
|
205
|
+
{
|
|
206
|
+
particleSystem.tileSize = vec2(particleSystem.tileSize.x, parseInt(input.value));
|
|
207
|
+
}
|
|
208
|
+
else if (type == 'checkbox')
|
|
209
|
+
particleSystem[name] = input.checked ? 1 : 0;
|
|
210
|
+
else if (name == 'emitRate')
|
|
211
|
+
particleSystem[name] = min(inputFloat,1e3);
|
|
212
|
+
else
|
|
213
|
+
particleSystem[name] = clamp(inputFloat, setting.min, setting.max);
|
|
214
|
+
}
|
|
215
|
+
updateInputs();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function updateInputs(save=1)
|
|
219
|
+
{
|
|
220
|
+
for (const setting of particleSettings)
|
|
221
|
+
{
|
|
222
|
+
const input = setting.input;
|
|
223
|
+
const name = setting.name;
|
|
224
|
+
const type = setting.type;
|
|
225
|
+
|
|
226
|
+
if (type == 'color')
|
|
227
|
+
{
|
|
228
|
+
const color = particleSystem[name];
|
|
229
|
+
input.value = color.hex();
|
|
230
|
+
}
|
|
231
|
+
else if (type == 'alpha')
|
|
232
|
+
{
|
|
233
|
+
if (name == 'colorAlphaStartA')
|
|
234
|
+
input.value = particleSystem.colorStartA.a;
|
|
235
|
+
else if (name == 'colorAlphaStartB')
|
|
236
|
+
input.value = particleSystem.colorStartB.a;
|
|
237
|
+
else if (name == 'colorAlphaEndA')
|
|
238
|
+
input.value = particleSystem.colorEndA.a;
|
|
239
|
+
else if (name == 'colorAlphaEndB')
|
|
240
|
+
input.value = particleSystem.colorEndB.a;
|
|
241
|
+
}
|
|
242
|
+
else if (name == 'tileSizeX')
|
|
243
|
+
input.value = particleSystem.tileSize.x;
|
|
244
|
+
else if (name == 'tileSizeY')
|
|
245
|
+
input.value = particleSystem.tileSize.y;
|
|
246
|
+
else if (type == 'checkbox')
|
|
247
|
+
input.checked = particleSystem[name];
|
|
248
|
+
else
|
|
249
|
+
input.value = particleSystem[name] || '0';
|
|
250
|
+
|
|
251
|
+
if (save)
|
|
252
|
+
{
|
|
253
|
+
const storageName = storagePrefix + setting.name;
|
|
254
|
+
localStorage[storageName] = type == 'checkbox' ?
|
|
255
|
+
input.checked : input.value;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
particleSystemCode.value = getCode();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function getCode()
|
|
262
|
+
{
|
|
263
|
+
const condense = inputCondense.checked;
|
|
264
|
+
let code = '';
|
|
265
|
+
|
|
266
|
+
// https://www.codingem.com/javascript-how-to-limit-decimal-places/
|
|
267
|
+
Number.prototype.round = function(n) {
|
|
268
|
+
const d = Math.pow(10, n);
|
|
269
|
+
return Math.round((this + Number.EPSILON) * d) / d;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
code = 'new ParticleEmitter(';
|
|
273
|
+
if (condense)
|
|
274
|
+
code += 'vec2(), 0, ';
|
|
275
|
+
else
|
|
276
|
+
code += '\n vec2(), 0,\t//position, angle\n';
|
|
277
|
+
|
|
278
|
+
let count = 0;
|
|
279
|
+
for (const setting of particleSettings)
|
|
280
|
+
{
|
|
281
|
+
const name = setting.name;
|
|
282
|
+
const type = setting.type;
|
|
283
|
+
let value;
|
|
284
|
+
if (name == 'tileSizeX' || type == 'alpha')
|
|
285
|
+
continue;
|
|
286
|
+
|
|
287
|
+
if (name == 'tileSizeY')
|
|
288
|
+
value = `vec2(${particleSystem.tileSize.x}, ${particleSystem.tileSize.y})`;
|
|
289
|
+
else if (type == 'color')
|
|
290
|
+
{
|
|
291
|
+
const c = particleSystem[name];
|
|
292
|
+
const p = 3;
|
|
293
|
+
value = `new Color(${c.r.round(p)}, ${c.g.round(p)}, ${c.b.round(p)}, ${c.a.round(p)})`;
|
|
294
|
+
}
|
|
295
|
+
else if (type == 'checkbox')
|
|
296
|
+
value = particleSystem[name] ? 1 : 0;
|
|
297
|
+
else
|
|
298
|
+
value = particleSystem[name].round(3);
|
|
299
|
+
if (!condense)
|
|
300
|
+
code += ' ';
|
|
301
|
+
code += value;
|
|
302
|
+
|
|
303
|
+
const isEnd = name == 'randomColorLinear';
|
|
304
|
+
if (!condense)
|
|
305
|
+
{
|
|
306
|
+
code += ',\t// ' + name;
|
|
307
|
+
if (!isEnd)
|
|
308
|
+
code += '\n';
|
|
309
|
+
}
|
|
310
|
+
else if (!isEnd)
|
|
311
|
+
code += ', ';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
if (condense)
|
|
316
|
+
code += ');';
|
|
317
|
+
else
|
|
318
|
+
code += '\n); // particle emitter';
|
|
319
|
+
|
|
320
|
+
return code;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
324
|
+
function gameUpdate()
|
|
325
|
+
{
|
|
326
|
+
if (!restartTimer.isSet() && particleSystem.destroyed)
|
|
327
|
+
restartTimer.set(1);
|
|
328
|
+
else if (restartTimer.elapsed())
|
|
329
|
+
{
|
|
330
|
+
restartTimer.unset()
|
|
331
|
+
makeEmitter();
|
|
332
|
+
updateParticles();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (document.activeElement == document.body)
|
|
336
|
+
{
|
|
337
|
+
particleSystem.pos = mouseIsDown(0) ? mousePos : vec2();
|
|
338
|
+
if (mouseWheel)
|
|
339
|
+
{
|
|
340
|
+
cameraScale -= sign(mouseWheel)*cameraScale/5;
|
|
341
|
+
cameraScale = clamp(cameraScale, 10, 300);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
347
|
+
function gameUpdatePost()
|
|
348
|
+
{
|
|
349
|
+
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
353
|
+
function gameRender()
|
|
354
|
+
{
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
358
|
+
function gameRenderPost()
|
|
359
|
+
{
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
363
|
+
// Startup LittleJS Engine
|
|
364
|
+
engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, 'tiles.png');
|
|
365
|
+
|
|
366
|
+
</script>
|
|
Binary file
|
|
@@ -73,18 +73,18 @@ function gameRender()
|
|
|
73
73
|
function gameRenderPost()
|
|
74
74
|
{
|
|
75
75
|
// draw to overlay canvas for hud rendering
|
|
76
|
-
const drawText = (text, x, y, size=
|
|
76
|
+
const drawText = (text, x, y, size=50) =>
|
|
77
77
|
{
|
|
78
78
|
overlayContext.textAlign = 'center';
|
|
79
79
|
overlayContext.textBaseline = 'top';
|
|
80
80
|
overlayContext.font = size + 'px arial';
|
|
81
81
|
overlayContext.fillStyle = '#fff';
|
|
82
|
-
overlayContext.lineWidth =
|
|
82
|
+
overlayContext.lineWidth = 2;
|
|
83
83
|
overlayContext.strokeText(text, x, y);
|
|
84
84
|
overlayContext.fillText(text, x, y);
|
|
85
85
|
}
|
|
86
|
-
drawText('Score: ' + score, overlayCanvas.width*1/
|
|
87
|
-
drawText('Deaths: ' + deaths, overlayCanvas.width*
|
|
86
|
+
drawText('Score: ' + score, overlayCanvas.width*1/4, 20);
|
|
87
|
+
drawText('Deaths: ' + deaths, overlayCanvas.width*3/4, 20);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
///////////////////////////////////////////////////////////////////////////////
|