littlejsengine 1.18.4 → 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/README.md +19 -1
- package/dist/littlejs.d.ts +349 -54
- package/dist/littlejs.esm.js +1469 -448
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1438 -436
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1438 -436
- package/package.json +8 -1
- package/plugins/box2d.js +32 -7
- package/{src/engineMedals.js → plugins/medalSystem.js} +248 -196
- package/plugins/pathFinder.js +758 -0
- package/plugins/pluginExport.js +19 -0
- package/plugins/tween.js +1 -1
- package/plugins/tweenSystem.js +509 -0
- package/plugins/uiSystem.js +150 -11
- package/src/engine.js +2 -141
- package/src/engineAudio.js +8 -5
- package/src/engineBuild.mjs +4 -2
- package/src/engineDebug.js +1 -1
- package/src/engineDraw.js +21 -3
- package/src/engineExport.js +12 -12
- package/src/engineInput.js +1 -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 +0 -47
- package/src/engineUtilities.js +7 -2
- package/src/engineWebGL.js +34 -7
- package/src/jsconfig.json +3 -1
- package/.github/workflows/test.yml +0 -17
- package/AI.md +0 -173
- 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 -62
- 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/textureWrapped.js +0 -12
- 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/tween.js +0 -24
- package/examples/shorts/uiSystem.js +0 -61
- package/examples/shorts/video.webm +0 -0
- package/examples/shorts/videoPlayer.js +0 -34
- package/examples/shorts.js +0 -743
- 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/tweenSystem/game.js +0 -171
- package/examples/tweenSystem/index.html +0 -10
- package/examples/tweenSystem/tiles.png +0 -0
- 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 -448
- package/test/math.test.mjs +0 -774
- package/test/setup.mjs +0 -22
- package/test/smoke.test.mjs +0 -274
- package/test/tween.test.mjs +0 -576
- 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
|
@@ -525,14 +525,29 @@ class Box2dObject extends EngineObject
|
|
|
525
525
|
this.body.ApplyForce(box2d.vec2dTo(force), box2d.vec2dTo(pos));
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
-
/** 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.
|
|
529
532
|
* @param {Vector2} acceleration
|
|
530
533
|
* @param {Vector2} [pos] */
|
|
531
534
|
applyAcceleration(acceleration, pos)
|
|
532
|
-
{
|
|
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
|
+
{
|
|
533
548
|
pos ||= this.getCenterOfMass();
|
|
534
549
|
this.setAwake();
|
|
535
|
-
this.body.ApplyLinearImpulse(box2d.vec2dTo(
|
|
550
|
+
this.body.ApplyLinearImpulse(box2d.vec2dTo(impulse), box2d.vec2dTo(pos));
|
|
536
551
|
}
|
|
537
552
|
|
|
538
553
|
/** Apply torque to this object
|
|
@@ -542,13 +557,23 @@ class Box2dObject extends EngineObject
|
|
|
542
557
|
this.setAwake();
|
|
543
558
|
this.body.ApplyTorque(torque);
|
|
544
559
|
}
|
|
545
|
-
|
|
546
|
-
/** 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).
|
|
547
563
|
* @param {number} acceleration */
|
|
548
564
|
applyAngularAcceleration(acceleration)
|
|
549
565
|
{
|
|
550
566
|
this.setAwake();
|
|
551
|
-
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);
|
|
552
577
|
}
|
|
553
578
|
|
|
554
579
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -794,7 +819,7 @@ class Box2dJoint
|
|
|
794
819
|
|
|
795
820
|
/** Check if the connected bodies should collide
|
|
796
821
|
* @return {boolean} */
|
|
797
|
-
getCollideConnected() { return this.box2dJoint.
|
|
822
|
+
getCollideConnected() { return this.box2dJoint.GetCollideConnected();}
|
|
798
823
|
|
|
799
824
|
/** Check if either connected body is active
|
|
800
825
|
* @return {boolean} */
|
|
@@ -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; }
|