littlejsengine 1.18.2 → 1.18.7
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/COPYRIGHT.txt +38 -0
- package/FAQ.md +633 -0
- package/LICENSE +5 -27
- package/README.md +19 -1
- package/dist/littlejs.d.ts +550 -57
- package/dist/littlejs.esm.js +2208 -492
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +2165 -480
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +2166 -481
- package/package.json +8 -1
- package/plugins/box2d.js +36 -9
- package/{src/engineMedals.js → plugins/medalSystem.js} +248 -196
- package/plugins/pathFinder.js +758 -0
- package/plugins/pluginExport.js +26 -0
- package/plugins/tween.js +509 -0
- package/plugins/tweenSystem.js +509 -0
- package/plugins/uiSystem.js +151 -12
- package/src/engine.js +9 -145
- package/src/engineAudio.js +8 -5
- package/src/engineBuild.mjs +4 -1
- package/src/engineDebug.js +1 -1
- package/src/engineDraw.js +154 -5
- package/src/engineExport.js +17 -12
- package/src/engineInput.js +27 -1
- package/src/engineLogo.js +146 -0
- package/src/engineMath.js +10 -3
- package/src/engineObject.js +11 -5
- package/src/engineParticles.js +6 -3
- package/src/engineRelease.js +1 -1
- package/src/engineSettings.js +17 -47
- package/src/engineUtilities.js +7 -2
- package/src/engineWebGL.js +31 -8
- package/src/jsconfig.json +3 -1
- package/.claude/settings.local.json +0 -7
- package/.github/workflows/test.yml +0 -17
- package/AI.md +0 -172
- package/CLAUDE.md +0 -1
- package/examples/box2d/game.js +0 -192
- package/examples/box2d/gameObjects.js +0 -564
- package/examples/box2d/index.html +0 -9
- package/examples/box2d/scenes.js +0 -194
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +0 -175
- package/examples/breakout/gameObjects.js +0 -147
- package/examples/breakout/index.html +0 -8
- package/examples/breakout/tiles.png +0 -0
- package/examples/breakoutTutorial/README.md +0 -521
- package/examples/breakoutTutorial/game.js +0 -191
- package/examples/breakoutTutorial/images/1.png +0 -0
- package/examples/breakoutTutorial/images/10.png +0 -0
- package/examples/breakoutTutorial/images/11.png +0 -0
- package/examples/breakoutTutorial/images/2.png +0 -0
- package/examples/breakoutTutorial/images/3.png +0 -0
- package/examples/breakoutTutorial/images/4.png +0 -0
- package/examples/breakoutTutorial/images/5.png +0 -0
- package/examples/breakoutTutorial/images/6.png +0 -0
- package/examples/breakoutTutorial/images/7.png +0 -0
- package/examples/breakoutTutorial/images/8.png +0 -0
- package/examples/breakoutTutorial/images/9.png +0 -0
- package/examples/breakoutTutorial/index.html +0 -8
- package/examples/electron/build.mjs +0 -127
- package/examples/electron/electron.js +0 -35
- package/examples/electron/game.js +0 -54
- package/examples/electron/index.html +0 -13
- package/examples/electron/package.json +0 -5
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/game.js +0 -51
- package/examples/empty/index.html +0 -5
- package/examples/empty/tiles.png +0 -0
- package/examples/favicon.png +0 -0
- package/examples/games.jpg +0 -0
- package/examples/htmlMenu/game.js +0 -82
- package/examples/htmlMenu/index.html +0 -45
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +0 -800
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/module/build.mjs +0 -124
- package/examples/module/game.js +0 -132
- package/examples/module/index.html +0 -10
- package/examples/module/tiles.png +0 -0
- package/examples/particles/index.html +0 -426
- package/examples/particles/tiles.png +0 -0
- package/examples/platformer/data/gameLevelData.tmx +0 -143
- package/examples/platformer/data/gameLevelData.tsx +0 -4
- package/examples/platformer/game.js +0 -147
- package/examples/platformer/gameCharacter.js +0 -309
- package/examples/platformer/gameEffects.js +0 -278
- package/examples/platformer/gameLevel.js +0 -205
- package/examples/platformer/gameLevelData.json +0 -171
- package/examples/platformer/gameObjects.js +0 -378
- package/examples/platformer/gamePlayer.js +0 -35
- package/examples/platformer/index.html +0 -9
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +0 -331
- package/examples/puzzle/index.html +0 -8
- package/examples/puzzle/tiles.png +0 -0
- package/examples/screenshot.jpg +0 -0
- package/examples/shorts/animation.js +0 -18
- package/examples/shorts/base.html +0 -54
- package/examples/shorts/blending.js +0 -14
- package/examples/shorts/box2d.js +0 -51
- package/examples/shorts/box2dCar.js +0 -59
- package/examples/shorts/box2dPool.js +0 -107
- package/examples/shorts/box2dTileLayer.js +0 -48
- package/examples/shorts/cameraDrag.js +0 -22
- package/examples/shorts/clock.js +0 -21
- package/examples/shorts/colors.js +0 -25
- package/examples/shorts/debugDraw.js +0 -37
- package/examples/shorts/empty.js +0 -30
- package/examples/shorts/flappyGame.js +0 -55
- package/examples/shorts/fontImage.js +0 -17
- package/examples/shorts/fps.js +0 -90
- package/examples/shorts/helloWorld.js +0 -11
- package/examples/shorts/hillGlideGame.js +0 -63
- package/examples/shorts/input.js +0 -64
- package/examples/shorts/landerGame.js +0 -57
- package/examples/shorts/maze.js +0 -48
- package/examples/shorts/medals.js +0 -51
- package/examples/shorts/music.js +0 -78
- package/examples/shorts/musicPlayer.js +0 -137
- package/examples/shorts/nineSlice.js +0 -40
- package/examples/shorts/parallax.js +0 -72
- package/examples/shorts/particles.js +0 -28
- package/examples/shorts/piano.js +0 -44
- package/examples/shorts/platformer.js +0 -45
- package/examples/shorts/pongGame.js +0 -41
- package/examples/shorts/postProcess.js +0 -62
- package/examples/shorts/sequencer.js +0 -124
- package/examples/shorts/shader.js +0 -29
- package/examples/shorts/shapes.js +0 -21
- package/examples/shorts/slidingPuzzle.js +0 -52
- package/examples/shorts/song.mp3 +0 -0
- package/examples/shorts/sound.js +0 -36
- package/examples/shorts/spaceGame.js +0 -58
- package/examples/shorts/spriteAtlas.js +0 -31
- package/examples/shorts/starfield.js +0 -15
- package/examples/shorts/texture.js +0 -16
- package/examples/shorts/tileLayer.js +0 -48
- package/examples/shorts/tileRaycast.js +0 -39
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +0 -63
- package/examples/shorts/timers.js +0 -53
- package/examples/shorts/topDown.js +0 -38
- package/examples/shorts/uiSystem.js +0 -61
- package/examples/shorts/video.webm +0 -0
- package/examples/shorts/videoPlayer.js +0 -34
- package/examples/starter/build.bat +0 -7
- package/examples/starter/build.mjs +0 -126
- package/examples/starter/game.js +0 -137
- package/examples/starter/index.html +0 -35
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +0 -173
- package/examples/style.css +0 -150
- package/examples/typescript/build.mjs +0 -60
- package/examples/typescript/game.js +0 -100
- package/examples/typescript/game.ts +0 -132
- package/examples/typescript/index.html +0 -10
- package/examples/typescript/tiles.png +0 -0
- package/examples/typescript/tsconfig.json +0 -17
- package/examples/uiSystem/game.js +0 -139
- package/examples/uiSystem/index.html +0 -10
- package/examples/uiSystem/tiles.png +0 -0
- package/jsconfig.json +0 -12
- package/plugins/desktop.ini +0 -2
- package/reference.md +0 -447
- package/test/math.test.mjs +0 -774
- package/test/setup.mjs +0 -22
- package/test/smoke.test.mjs +0 -258
- package/test/util.test.mjs +0 -80
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "littlejsengine",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.7",
|
|
4
4
|
"description": "LittleJS - Tiny and Fast HTML5 Game Engine",
|
|
5
5
|
"main": "dist/littlejs.esm.js",
|
|
6
6
|
"types": "dist/littlejs.d.ts",
|
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
"url": "https://github.com/KilledByAPixel/LittleJS/issues"
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/KilledByAPixel/LittleJS",
|
|
32
|
+
"files": [
|
|
33
|
+
"dist/",
|
|
34
|
+
"src/",
|
|
35
|
+
"plugins/",
|
|
36
|
+
"COPYRIGHT.txt",
|
|
37
|
+
"FAQ.md"
|
|
38
|
+
],
|
|
32
39
|
"scripts": {
|
|
33
40
|
"build": "node src/engineBuild.mjs",
|
|
34
41
|
"test": "node --test --import ./test/setup.mjs \"test/**/*.test.mjs\""
|
package/plugins/box2d.js
CHANGED
|
@@ -401,7 +401,8 @@ class Box2dObject extends EngineObject
|
|
|
401
401
|
{
|
|
402
402
|
this.pos = pos;
|
|
403
403
|
this.angle = angle;
|
|
404
|
-
|
|
404
|
+
// box2d uses reverse angle
|
|
405
|
+
this.body.SetTransform(box2d.vec2dTo(pos), -angle);
|
|
405
406
|
}
|
|
406
407
|
|
|
407
408
|
/** Sets the position
|
|
@@ -412,7 +413,7 @@ class Box2dObject extends EngineObject
|
|
|
412
413
|
/** Sets the angle
|
|
413
414
|
* @param {number} angle */
|
|
414
415
|
setAngle(angle)
|
|
415
|
-
{ this.setTransform(box2d.vec2From(this.body.GetPosition()),
|
|
416
|
+
{ this.setTransform(box2d.vec2From(this.body.GetPosition()), angle); }
|
|
416
417
|
|
|
417
418
|
/** Sets the linear velocity
|
|
418
419
|
* @param {Vector2} velocity */
|
|
@@ -524,14 +525,29 @@ class Box2dObject extends EngineObject
|
|
|
524
525
|
this.body.ApplyForce(box2d.vec2dTo(force), box2d.vec2dTo(pos));
|
|
525
526
|
}
|
|
526
527
|
|
|
527
|
-
/** Apply acceleration to this object
|
|
528
|
+
/** Apply acceleration to this object (changes velocity by acceleration,
|
|
529
|
+
* mass-independent — matches EngineObject.applyAcceleration semantics).
|
|
530
|
+
* Use applyImpulse if you want the mass-dependent velocity change
|
|
531
|
+
* Δv = impulse / mass, or applyForce for a Newton-style sustained force.
|
|
528
532
|
* @param {Vector2} acceleration
|
|
529
533
|
* @param {Vector2} [pos] */
|
|
530
534
|
applyAcceleration(acceleration, pos)
|
|
531
|
-
{
|
|
535
|
+
{
|
|
536
|
+
pos ||= this.getCenterOfMass();
|
|
537
|
+
this.setAwake();
|
|
538
|
+
const impulse = acceleration.scale(this.getMass());
|
|
539
|
+
this.body.ApplyLinearImpulse(box2d.vec2dTo(impulse), box2d.vec2dTo(pos));
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/** Apply an instantaneous linear impulse. Changes velocity immediately by
|
|
543
|
+
* impulse / mass (so heavier bodies move less for the same impulse).
|
|
544
|
+
* @param {Vector2} impulse
|
|
545
|
+
* @param {Vector2} [pos] */
|
|
546
|
+
applyImpulse(impulse, pos)
|
|
547
|
+
{
|
|
532
548
|
pos ||= this.getCenterOfMass();
|
|
533
549
|
this.setAwake();
|
|
534
|
-
this.body.ApplyLinearImpulse(box2d.vec2dTo(
|
|
550
|
+
this.body.ApplyLinearImpulse(box2d.vec2dTo(impulse), box2d.vec2dTo(pos));
|
|
535
551
|
}
|
|
536
552
|
|
|
537
553
|
/** Apply torque to this object
|
|
@@ -541,13 +557,23 @@ class Box2dObject extends EngineObject
|
|
|
541
557
|
this.setAwake();
|
|
542
558
|
this.body.ApplyTorque(torque);
|
|
543
559
|
}
|
|
544
|
-
|
|
545
|
-
/** Apply angular acceleration to this object
|
|
560
|
+
|
|
561
|
+
/** Apply angular acceleration to this object (changes angular velocity by
|
|
562
|
+
* acceleration, mass-independent — matches EngineObject semantics).
|
|
546
563
|
* @param {number} acceleration */
|
|
547
564
|
applyAngularAcceleration(acceleration)
|
|
548
565
|
{
|
|
549
566
|
this.setAwake();
|
|
550
|
-
this.body.ApplyAngularImpulse(acceleration);
|
|
567
|
+
this.body.ApplyAngularImpulse(acceleration * this.getInertia());
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/** Apply an instantaneous angular impulse. Changes angular velocity by
|
|
571
|
+
* impulse / inertia immediately.
|
|
572
|
+
* @param {number} impulse */
|
|
573
|
+
applyAngularImpulse(impulse)
|
|
574
|
+
{
|
|
575
|
+
this.setAwake();
|
|
576
|
+
this.body.ApplyAngularImpulse(impulse);
|
|
551
577
|
}
|
|
552
578
|
|
|
553
579
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -793,7 +819,7 @@ class Box2dJoint
|
|
|
793
819
|
|
|
794
820
|
/** Check if the connected bodies should collide
|
|
795
821
|
* @return {boolean} */
|
|
796
|
-
getCollideConnected() { return this.box2dJoint.
|
|
822
|
+
getCollideConnected() { return this.box2dJoint.GetCollideConnected();}
|
|
797
823
|
|
|
798
824
|
/** Check if either connected body is active
|
|
799
825
|
* @return {boolean} */
|
|
@@ -1957,6 +1983,7 @@ async function box2dInit()
|
|
|
1957
1983
|
{
|
|
1958
1984
|
if (o.body)
|
|
1959
1985
|
{
|
|
1986
|
+
// box2d uses reverse angle
|
|
1960
1987
|
o.pos = box2d.vec2From(o.body.GetPosition());
|
|
1961
1988
|
o.angle = -o.body.GetAngle();
|
|
1962
1989
|
}
|
|
@@ -1,196 +1,248 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LittleJS Medal System
|
|
3
|
-
* - Achievement/trophy system for games
|
|
4
|
-
* - Medal class with name, description, icon, and unlock tracking
|
|
5
|
-
* - Automatic saving to local storage
|
|
6
|
-
* - Visual display queue with slide-in notifications
|
|
7
|
-
* - Newgrounds API integration for online achievements
|
|
8
|
-
* - Debug mode to unlock/reset medals during development
|
|
9
|
-
* @namespace Medals
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
'use strict';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
* @
|
|
28
|
-
* @memberof
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS Medal System
|
|
3
|
+
* - Achievement/trophy system for games
|
|
4
|
+
* - Medal class with name, description, icon, and unlock tracking
|
|
5
|
+
* - Automatic saving to local storage
|
|
6
|
+
* - Visual display queue with slide-in notifications
|
|
7
|
+
* - Newgrounds API integration for online achievements
|
|
8
|
+
* - Debug mode to unlock/reset medals during development
|
|
9
|
+
* @namespace Medals
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
let debugMedals = false;
|
|
15
|
+
|
|
16
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
17
|
+
// Medals settings
|
|
18
|
+
|
|
19
|
+
/** How long to show medals for in seconds
|
|
20
|
+
* @type {number}
|
|
21
|
+
* @default
|
|
22
|
+
* @memberof Settings */
|
|
23
|
+
let medalDisplayTime = 5;
|
|
24
|
+
|
|
25
|
+
/** How quickly to slide on/off medals in seconds
|
|
26
|
+
* @type {number}
|
|
27
|
+
* @default
|
|
28
|
+
* @memberof Settings */
|
|
29
|
+
let medalDisplaySlideTime = .5;
|
|
30
|
+
|
|
31
|
+
/** Size of medal display
|
|
32
|
+
* @type {Vector2}
|
|
33
|
+
* @default Vector2(640,80)
|
|
34
|
+
* @memberof Settings */
|
|
35
|
+
let medalDisplaySize = vec2(640, 80);
|
|
36
|
+
|
|
37
|
+
/** Set to stop medals from being unlockable (like if cheats are enabled)
|
|
38
|
+
* @type {boolean}
|
|
39
|
+
* @default
|
|
40
|
+
* @memberof Settings */
|
|
41
|
+
let medalsPreventUnlock = false;
|
|
42
|
+
|
|
43
|
+
/** List of all medals
|
|
44
|
+
* @type {Object}
|
|
45
|
+
* @memberof Medals */
|
|
46
|
+
const medals = {};
|
|
47
|
+
|
|
48
|
+
// Engine internal variables not exposed to documentation
|
|
49
|
+
let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
50
|
+
|
|
51
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
52
|
+
|
|
53
|
+
/** Initialize medals with a save name used for storage
|
|
54
|
+
* - Call this after creating all medals
|
|
55
|
+
* - Checks if medals are unlocked
|
|
56
|
+
* @param {string} saveName
|
|
57
|
+
* @memberof Medals */
|
|
58
|
+
function medalsInit(saveName)
|
|
59
|
+
{
|
|
60
|
+
// check if medals are unlocked
|
|
61
|
+
medalsSaveName = saveName;
|
|
62
|
+
if (!debugMedals)
|
|
63
|
+
medalsForEach(medal=> medal.unlocked = !!localStorage[medal.storageKey()]);
|
|
64
|
+
|
|
65
|
+
// engine automatically renders medals
|
|
66
|
+
engineAddPlugin(undefined, medalsRender);
|
|
67
|
+
|
|
68
|
+
// plugin functions
|
|
69
|
+
function medalsRender()
|
|
70
|
+
{
|
|
71
|
+
if (!medalsDisplayQueue.length) return;
|
|
72
|
+
|
|
73
|
+
// update first medal in queue
|
|
74
|
+
const medal = medalsDisplayQueue[0];
|
|
75
|
+
const time = timeReal - medalsDisplayTimeLast;
|
|
76
|
+
if (!medalsDisplayTimeLast)
|
|
77
|
+
medalsDisplayTimeLast = timeReal;
|
|
78
|
+
else if (time > medalDisplayTime)
|
|
79
|
+
{
|
|
80
|
+
medalsDisplayTimeLast = 0;
|
|
81
|
+
medalsDisplayQueue.shift();
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
{
|
|
85
|
+
// slide on/off medals
|
|
86
|
+
const slideOffTime = medalDisplayTime - medalDisplaySlideTime;
|
|
87
|
+
const hidePercent =
|
|
88
|
+
time < medalDisplaySlideTime ? 1 - time / medalDisplaySlideTime :
|
|
89
|
+
time > slideOffTime ? (time - slideOffTime) / medalDisplaySlideTime : 0;
|
|
90
|
+
medal.render(hidePercent);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @callback MedalCallbackFunction - Function that processes a medal
|
|
97
|
+
* @param {Medal} medal
|
|
98
|
+
* @memberof Medals
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
/** Calls a function for each medal
|
|
102
|
+
* @param {MedalCallbackFunction} callback
|
|
103
|
+
* @memberof Medals */
|
|
104
|
+
function medalsForEach(callback)
|
|
105
|
+
{ Object.values(medals).forEach(medal=>callback(medal)); }
|
|
106
|
+
|
|
107
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Medal - Tracks an unlockable medal
|
|
111
|
+
* @memberof Medals
|
|
112
|
+
* @example
|
|
113
|
+
* // create a medal
|
|
114
|
+
* const medal_example = new Medal(0, 'Example Medal', 'More info about the medal goes here.', '🎖️');
|
|
115
|
+
*
|
|
116
|
+
* // initialize medals
|
|
117
|
+
* medalsInit('Example Game');
|
|
118
|
+
*
|
|
119
|
+
* // unlock the medal
|
|
120
|
+
* medal_example.unlock();
|
|
121
|
+
*/
|
|
122
|
+
class Medal
|
|
123
|
+
{
|
|
124
|
+
/** Create a medal object and adds it to the list of medals
|
|
125
|
+
* @param {number} id - The unique identifier of the medal
|
|
126
|
+
* @param {string} name - Name of the medal
|
|
127
|
+
* @param {string} [description] - Description of the medal
|
|
128
|
+
* @param {string} [icon] - Icon for the medal
|
|
129
|
+
* @param {string} [src] - Image location for the medal
|
|
130
|
+
*/
|
|
131
|
+
constructor(id, name, description='', icon='🏆', src)
|
|
132
|
+
{
|
|
133
|
+
ASSERT(id >= 0 && !medals[id]);
|
|
134
|
+
|
|
135
|
+
/** @property {number} - The unique identifier of the medal */
|
|
136
|
+
this.id = id;
|
|
137
|
+
|
|
138
|
+
/** @property {string} - Name of the medal */
|
|
139
|
+
this.name = name;
|
|
140
|
+
|
|
141
|
+
/** @property {string} - Description of the medal */
|
|
142
|
+
this.description = description;
|
|
143
|
+
|
|
144
|
+
/** @property {string} - Icon for the medal */
|
|
145
|
+
this.icon = icon;
|
|
146
|
+
|
|
147
|
+
/** @property {boolean} - Is the medal unlocked? */
|
|
148
|
+
this.unlocked = false;
|
|
149
|
+
|
|
150
|
+
// load the source image if provided
|
|
151
|
+
if (src)
|
|
152
|
+
(this.image = new Image).src = src;
|
|
153
|
+
|
|
154
|
+
// add this to list of medals
|
|
155
|
+
medals[id] = this;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Unlocks a medal if not already unlocked */
|
|
159
|
+
unlock()
|
|
160
|
+
{
|
|
161
|
+
if (medalsPreventUnlock || this.unlocked) return;
|
|
162
|
+
|
|
163
|
+
// save the medal
|
|
164
|
+
ASSERT(medalsSaveName, 'save name must be set');
|
|
165
|
+
localStorage[this.storageKey()] = this.unlocked = true;
|
|
166
|
+
medalsDisplayQueue.push(this);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Render a medal
|
|
170
|
+
* @param {number} [hidePercent] - How much to slide the medal off screen
|
|
171
|
+
*/
|
|
172
|
+
render(hidePercent=0)
|
|
173
|
+
{
|
|
174
|
+
const context = mainContext;
|
|
175
|
+
const width = min(medalDisplaySize.x, mainCanvas.width);
|
|
176
|
+
const height = medalDisplaySize.y;
|
|
177
|
+
const x = mainCanvas.width - width;
|
|
178
|
+
const y = -height*hidePercent;
|
|
179
|
+
const backgroundColor = hsl(0,0,.9);
|
|
180
|
+
|
|
181
|
+
// draw containing rect and clip to that region
|
|
182
|
+
context.save();
|
|
183
|
+
context.beginPath();
|
|
184
|
+
context.fillStyle = backgroundColor.toString();
|
|
185
|
+
context.strokeStyle = BLACK.toString();
|
|
186
|
+
context.lineWidth = 3;
|
|
187
|
+
context.rect(x, y, width, height);
|
|
188
|
+
context.fill();
|
|
189
|
+
context.stroke();
|
|
190
|
+
context.clip();
|
|
191
|
+
|
|
192
|
+
// draw the icon
|
|
193
|
+
const gap = vec2(.1, .05).scale(height);
|
|
194
|
+
const medalDisplayIconSize = height - 2*gap.x;
|
|
195
|
+
this.renderIcon(vec2(x + gap.x + medalDisplayIconSize/2, y + height/2), medalDisplayIconSize);
|
|
196
|
+
|
|
197
|
+
// draw the name
|
|
198
|
+
const nameSize = height*.5;
|
|
199
|
+
const descriptionSize = height*.3;
|
|
200
|
+
const pos = vec2(x + medalDisplayIconSize + 2*gap.x, y + gap.y*2 + nameSize/2);
|
|
201
|
+
const textWidth = width - medalDisplayIconSize - 3*gap.x;
|
|
202
|
+
drawTextScreen(this.name, pos, nameSize, BLACK, 0, undefined, 'left', undefined, undefined, textWidth);
|
|
203
|
+
|
|
204
|
+
// draw the description
|
|
205
|
+
pos.y = y + height - gap.y*2 - descriptionSize/2;
|
|
206
|
+
drawTextScreen(this.description, pos, descriptionSize, BLACK, 0, undefined, 'left', undefined, undefined, textWidth);
|
|
207
|
+
context.restore();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Render the icon for a medal
|
|
211
|
+
* @param {Vector2} pos - Screen space position
|
|
212
|
+
* @param {number} size - Screen space size
|
|
213
|
+
*/
|
|
214
|
+
renderIcon(pos, size)
|
|
215
|
+
{
|
|
216
|
+
// draw the image or icon
|
|
217
|
+
if (this.image)
|
|
218
|
+
mainContext.drawImage(this.image, pos.x-size/2, pos.y-size/2, size, size);
|
|
219
|
+
else
|
|
220
|
+
drawTextScreen(this.icon, pos, size*.7, BLACK);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Get local storage key used by the medal
|
|
224
|
+
storageKey() { return medalsSaveName + '_' + this.id; }
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
228
|
+
// Medals setting setters
|
|
229
|
+
|
|
230
|
+
/** Set how long to show medals for in seconds
|
|
231
|
+
* @param {number} time
|
|
232
|
+
* @memberof Settings */
|
|
233
|
+
function setMedalDisplayTime(time) { medalDisplayTime = time; }
|
|
234
|
+
|
|
235
|
+
/** Set how quickly to slide on/off medals in seconds
|
|
236
|
+
* @param {number} time
|
|
237
|
+
* @memberof Settings */
|
|
238
|
+
function setMedalDisplaySlideTime(time) { medalDisplaySlideTime = time; }
|
|
239
|
+
|
|
240
|
+
/** Set size of medal display
|
|
241
|
+
* @param {Vector2} size
|
|
242
|
+
* @memberof Settings */
|
|
243
|
+
function setMedalDisplaySize(size) { medalDisplaySize = size.copy(); }
|
|
244
|
+
|
|
245
|
+
/** Set to stop medals from being unlockable
|
|
246
|
+
* @param {boolean} preventUnlock
|
|
247
|
+
* @memberof Settings */
|
|
248
|
+
function setMedalsPreventUnlock(preventUnlock) { medalsPreventUnlock = preventUnlock; }
|