littlejsengine 1.9.6 → 1.9.8
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/LICENSE +22 -0
- package/README.md +13 -8
- package/dist/littlejs.d.ts +85 -84
- package/dist/littlejs.esm.js +370 -390
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +365 -386
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +302 -355
- package/examples/box2d/game.js +138 -0
- package/examples/box2d/index.html +25 -0
- package/examples/box2d/scenes.js +412 -0
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +3 -3
- package/examples/breakout/index.html +1 -0
- package/examples/platformer/gameEffects.js +2 -2
- package/examples/platformer/gameLevel.js +0 -1
- package/package.json +1 -1
- package/plugins/Box2D_v2.3.1_min.wasm.js +630 -0
- package/plugins/Box2D_v2.3.1_min.wasm.wasm +0 -0
- package/plugins/box2d.js +873 -0
- package/plugins/newgrounds.js +169 -0
- package/plugins/postProcess.js +101 -0
- package/src/engine.js +45 -26
- package/src/engineAudio.js +72 -47
- package/src/engineDebug.js +68 -33
- package/src/engineDraw.js +1 -1
- package/src/engineExport.js +5 -4
- package/src/engineMedals.js +39 -171
- package/src/engineObject.js +47 -4
- package/src/engineParticles.js +3 -0
- package/src/engineRelease.js +5 -2
- package/src/engineSettings.js +8 -3
- package/src/engineUtilities.js +81 -7
- package/src/engineWebGL.js +1 -94
package/src/engineDebug.js
CHANGED
|
@@ -76,6 +76,20 @@ function debugRect(pos, size=vec2(), color='#fff', time=0, angle=0, fill=false)
|
|
|
76
76
|
debugPrimitives.push({pos, size:vec2(size), color, time:new Timer(time), angle, fill});
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/** Draw a debug poly in world space
|
|
80
|
+
* @param {Vector2} pos
|
|
81
|
+
* @param {Array} points
|
|
82
|
+
* @param {String} [color]
|
|
83
|
+
* @param {Number} [time]
|
|
84
|
+
* @param {Number} [angle]
|
|
85
|
+
* @param {Boolean} [fill]
|
|
86
|
+
* @memberof Debug */
|
|
87
|
+
function debugPoly(pos, points, color='#fff', time=0, angle=0, fill=false)
|
|
88
|
+
{
|
|
89
|
+
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
90
|
+
debugPrimitives.push({pos, points, color, time:new Timer(time), angle, fill});
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
/** Draw a debug circle in world space
|
|
80
94
|
* @param {Vector2} pos
|
|
81
95
|
* @param {Number} [radius]
|
|
@@ -85,7 +99,7 @@ function debugRect(pos, size=vec2(), color='#fff', time=0, angle=0, fill=false)
|
|
|
85
99
|
* @memberof Debug */
|
|
86
100
|
function debugCircle(pos, radius=0, color='#fff', time=0, fill=false)
|
|
87
101
|
{
|
|
88
|
-
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
102
|
+
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
89
103
|
debugPrimitives.push({pos, size:radius, color, time:new Timer(time), angle:0, fill});
|
|
90
104
|
}
|
|
91
105
|
|
|
@@ -95,7 +109,11 @@ function debugCircle(pos, radius=0, color='#fff', time=0, fill=false)
|
|
|
95
109
|
* @param {Number} [time]
|
|
96
110
|
* @param {Number} [angle]
|
|
97
111
|
* @memberof Debug */
|
|
98
|
-
function debugPoint(pos, color, time, angle)
|
|
112
|
+
function debugPoint(pos, color, time, angle)
|
|
113
|
+
{
|
|
114
|
+
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
115
|
+
debugRect(pos, undefined, color, time, angle);
|
|
116
|
+
}
|
|
99
117
|
|
|
100
118
|
/** Draw a debug line in world space
|
|
101
119
|
* @param {Vector2} posA
|
|
@@ -106,19 +124,20 @@ function debugPoint(pos, color, time, angle) {debugRect(pos, undefined, color, t
|
|
|
106
124
|
* @memberof Debug */
|
|
107
125
|
function debugLine(posA, posB, color, thickness=.1, time)
|
|
108
126
|
{
|
|
127
|
+
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
109
128
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
110
129
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
111
130
|
debugRect(posA.add(halfDelta), size, color, time, halfDelta.angle(), true);
|
|
112
131
|
}
|
|
113
132
|
|
|
114
|
-
/** Draw a debug axis aligned bounding box in world space
|
|
133
|
+
/** Draw a debug combined axis aligned bounding box in world space
|
|
115
134
|
* @param {Vector2} pA - position A
|
|
116
135
|
* @param {Vector2} sA - size A
|
|
117
136
|
* @param {Vector2} pB - position B
|
|
118
137
|
* @param {Vector2} sB - size B
|
|
119
138
|
* @param {String} [color]
|
|
120
139
|
* @memberof Debug */
|
|
121
|
-
function
|
|
140
|
+
function debugOverlap(pA, sA, pB, sB, color)
|
|
122
141
|
{
|
|
123
142
|
const minPos = vec2(min(pA.x - sA.x/2, pB.x - sB.x/2), min(pA.y - sA.y/2, pB.y - sB.y/2));
|
|
124
143
|
const maxPos = vec2(max(pA.x + sA.x/2, pB.x + sB.x/2), max(pA.y + sA.y/2, pB.y + sB.y/2));
|
|
@@ -136,7 +155,7 @@ function debugAABB(pA, sA, pB, sB, color)
|
|
|
136
155
|
* @memberof Debug */
|
|
137
156
|
function debugText(text, pos, size=1, color='#fff', time=0, angle=0, font='monospace')
|
|
138
157
|
{
|
|
139
|
-
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
158
|
+
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
140
159
|
debugPrimitives.push({text, pos, size, color, time:new Timer(time), angle, font});
|
|
141
160
|
}
|
|
142
161
|
|
|
@@ -235,7 +254,7 @@ function debugRender()
|
|
|
235
254
|
const stickScale = 1;
|
|
236
255
|
const buttonScale = .2;
|
|
237
256
|
const centerPos = cameraPos;
|
|
238
|
-
const sticks =
|
|
257
|
+
const sticks = gamepadStickData[i];
|
|
239
258
|
for (let j = sticks.length; j--;)
|
|
240
259
|
{
|
|
241
260
|
const drawPos = centerPos.add(vec2(j*stickScale*2, i*stickScale*3));
|
|
@@ -255,6 +274,7 @@ function debugRender()
|
|
|
255
274
|
}
|
|
256
275
|
}
|
|
257
276
|
|
|
277
|
+
let debugObject;
|
|
258
278
|
if (debugOverlay)
|
|
259
279
|
{
|
|
260
280
|
const saveContext = mainContext;
|
|
@@ -265,11 +285,13 @@ function debugRender()
|
|
|
265
285
|
debugRect(cameraPos, cameraSize.subtract(vec2(.1)), '#f008');
|
|
266
286
|
|
|
267
287
|
// mouse pick
|
|
268
|
-
let bestDistance = Infinity
|
|
288
|
+
let bestDistance = Infinity;
|
|
269
289
|
for (const o of engineObjects)
|
|
270
290
|
{
|
|
271
291
|
if (o.canvas || o.destroyed)
|
|
272
292
|
continue;
|
|
293
|
+
|
|
294
|
+
o.renderDebugInfo();
|
|
273
295
|
if (!o.size.x || !o.size.y)
|
|
274
296
|
continue;
|
|
275
297
|
|
|
@@ -277,33 +299,15 @@ function debugRender()
|
|
|
277
299
|
if (distance < bestDistance)
|
|
278
300
|
{
|
|
279
301
|
bestDistance = distance;
|
|
280
|
-
|
|
302
|
+
debugObject = o;
|
|
281
303
|
}
|
|
282
|
-
|
|
283
|
-
// show object info
|
|
284
|
-
const size = vec2(max(o.size.x, .2), max(o.size.y, .2));
|
|
285
|
-
const color1 = new Color(o.collideTiles?1:0, o.collideSolidObjects?1:0, o.isSolid?1:0, o.parent?.2:.5);
|
|
286
|
-
const color2 = o.parent ? new Color(1,1,1,.5) : new Color(0,0,0,.8);
|
|
287
|
-
drawRect(o.pos, size, color1, o.angle, false);
|
|
288
|
-
drawRect(o.pos, size.scale(.8), color2, o.angle, false);
|
|
289
|
-
o.parent && drawLine(o.pos, o.parent.pos, .1, new Color(0,0,1,.5), false);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (bestObject)
|
|
293
|
-
{
|
|
294
|
-
const raycastHitPos = tileCollisionRaycast(bestObject.pos, mousePos);
|
|
295
|
-
raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), new Color(0,1,1,.3));
|
|
296
|
-
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), new Color(0,0,1,.5), 0, false);
|
|
297
|
-
drawLine(mousePos, bestObject.pos, .1, raycastHitPos ? new Color(1,0,0,.5) : new Color(0,1,0,.5), false);
|
|
298
|
-
|
|
299
|
-
const debugText = 'mouse pos = ' + mousePos +
|
|
300
|
-
'\nmouse collision = ' + getTileCollisionData(mousePos) +
|
|
301
|
-
'\n\n--- object info ---\n' +
|
|
302
|
-
bestObject.toString();
|
|
303
|
-
drawTextScreen(debugText, mousePosScreen, 24, new Color, .05, undefined, 'center', 'monospace');
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
|
|
306
|
+
if (tileCollisionSize.x > 0 && tileCollisionSize.y > 0)
|
|
307
|
+
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(0,0,1,.5), 0, false);
|
|
308
|
+
mainContext = saveContext;
|
|
309
|
+
|
|
310
|
+
//glCopyToContext(mainContext = saveContext);
|
|
307
311
|
}
|
|
308
312
|
|
|
309
313
|
{
|
|
@@ -318,6 +322,7 @@ function debugRender()
|
|
|
318
322
|
const pos = worldToScreen(p.pos);
|
|
319
323
|
overlayContext.translate(pos.x|0, pos.y|0);
|
|
320
324
|
overlayContext.rotate(p.angle);
|
|
325
|
+
overlayContext.scale(1, -1);
|
|
321
326
|
overlayContext.fillStyle = overlayContext.strokeStyle = p.color;
|
|
322
327
|
|
|
323
328
|
if (p.text != undefined)
|
|
@@ -327,7 +332,20 @@ function debugRender()
|
|
|
327
332
|
overlayContext.textBaseline = 'middle';
|
|
328
333
|
overlayContext.fillText(p.text, 0, 0);
|
|
329
334
|
}
|
|
330
|
-
else if (p.
|
|
335
|
+
else if (p.points != undefined)
|
|
336
|
+
{
|
|
337
|
+
// poly
|
|
338
|
+
overlayContext.beginPath();
|
|
339
|
+
for (const point of p.points)
|
|
340
|
+
{
|
|
341
|
+
const p2 = point.scale(cameraScale).floor();
|
|
342
|
+
overlayContext.lineTo(p2.x, p2.y);
|
|
343
|
+
}
|
|
344
|
+
overlayContext.closePath();
|
|
345
|
+
p.fill && overlayContext.fill();
|
|
346
|
+
overlayContext.stroke();
|
|
347
|
+
}
|
|
348
|
+
else if (p.size == 0 || p.size.x === 0 && p.size.y === 0)
|
|
331
349
|
{
|
|
332
350
|
// point
|
|
333
351
|
overlayContext.fillRect(-pointSize/2, -1, pointSize, 3);
|
|
@@ -336,7 +354,8 @@ function debugRender()
|
|
|
336
354
|
else if (p.size.x != undefined)
|
|
337
355
|
{
|
|
338
356
|
// rect
|
|
339
|
-
const
|
|
357
|
+
const s = p.size.scale(cameraScale).floor();
|
|
358
|
+
const w = s.x, h = s.y;
|
|
340
359
|
p.fill && overlayContext.fillRect(-w/2|0, -h/2|0, w, h);
|
|
341
360
|
overlayContext.strokeRect(-w/2|0, -h/2|0, w, h);
|
|
342
361
|
}
|
|
@@ -355,6 +374,22 @@ function debugRender()
|
|
|
355
374
|
// remove expired primitives
|
|
356
375
|
debugPrimitives = debugPrimitives.filter(r=>r.time<0);
|
|
357
376
|
}
|
|
377
|
+
|
|
378
|
+
if (debugObject)
|
|
379
|
+
{
|
|
380
|
+
const saveContext = mainContext;
|
|
381
|
+
mainContext = overlayContext;
|
|
382
|
+
const raycastHitPos = tileCollisionRaycast(debugObject.pos, mousePos);
|
|
383
|
+
raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3));
|
|
384
|
+
drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5), false);
|
|
385
|
+
|
|
386
|
+
const debugText = 'mouse pos = ' + mousePos +
|
|
387
|
+
'\nmouse collision = ' + getTileCollisionData(mousePos) +
|
|
388
|
+
'\n\n--- object info ---\n' +
|
|
389
|
+
debugObject.toString();
|
|
390
|
+
drawTextScreen(debugText, mousePosScreen, 24, rgb(), .05, undefined, 'center', 'monospace');
|
|
391
|
+
mainContext = saveContext;
|
|
392
|
+
}
|
|
358
393
|
|
|
359
394
|
{
|
|
360
395
|
// draw debug overlay
|
package/src/engineDraw.js
CHANGED
|
@@ -320,7 +320,7 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, conte
|
|
|
320
320
|
context.save();
|
|
321
321
|
context.translate(pos.x+.5, pos.y+.5);
|
|
322
322
|
context.rotate(angle);
|
|
323
|
-
context.scale(mirror ? -size.x : size.x, size.y);
|
|
323
|
+
context.scale(mirror ? -size.x : size.x, -size.y);
|
|
324
324
|
drawFunction(context);
|
|
325
325
|
context.restore();
|
|
326
326
|
}
|
package/src/engineExport.js
CHANGED
|
@@ -29,13 +29,16 @@ export {
|
|
|
29
29
|
// Debug
|
|
30
30
|
ASSERT,
|
|
31
31
|
debugRect,
|
|
32
|
+
debugPoly,
|
|
32
33
|
debugCircle,
|
|
33
34
|
debugPoint,
|
|
34
35
|
debugLine,
|
|
35
|
-
|
|
36
|
+
debugOverlap,
|
|
36
37
|
debugText,
|
|
37
38
|
debugClear,
|
|
38
39
|
debugSaveCanvas,
|
|
40
|
+
debugSaveText,
|
|
41
|
+
debugSaveDataURL,
|
|
39
42
|
|
|
40
43
|
// Settings
|
|
41
44
|
cameraPos,
|
|
@@ -178,6 +181,7 @@ export {
|
|
|
178
181
|
FontImage,
|
|
179
182
|
isFullscreen,
|
|
180
183
|
toggleFullscreen,
|
|
184
|
+
getCameraSize,
|
|
181
185
|
|
|
182
186
|
// WebGL
|
|
183
187
|
glCanvas,
|
|
@@ -186,7 +190,6 @@ export {
|
|
|
186
190
|
glCompileShader,
|
|
187
191
|
glCreateProgram,
|
|
188
192
|
glCreateTexture,
|
|
189
|
-
glInitPostProcess,
|
|
190
193
|
|
|
191
194
|
// Input
|
|
192
195
|
keyIsDown,
|
|
@@ -245,7 +248,5 @@ export {
|
|
|
245
248
|
medals,
|
|
246
249
|
medalsPreventUnlock,
|
|
247
250
|
medalsInit,
|
|
248
|
-
newgroundsInit,
|
|
249
251
|
Medal,
|
|
250
|
-
Newgrounds,
|
|
251
252
|
};
|
package/src/engineMedals.js
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
11
|
/** List of all medals
|
|
12
|
-
* @type {
|
|
12
|
+
* @type {Object}
|
|
13
13
|
* @memberof Medals */
|
|
14
|
-
const medals =
|
|
14
|
+
const medals = {};
|
|
15
15
|
|
|
16
16
|
// Engine internal variables not exposed to documentation
|
|
17
17
|
let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
@@ -27,9 +27,45 @@ function medalsInit(saveName)
|
|
|
27
27
|
{
|
|
28
28
|
// check if medals are unlocked
|
|
29
29
|
medalsSaveName = saveName;
|
|
30
|
-
|
|
30
|
+
if (!debugMedals)
|
|
31
|
+
medalsForEach(medal=> medal.unlocked = (localStorage[medal.storageKey()] | 0));
|
|
32
|
+
|
|
33
|
+
// engine automatically renders medals
|
|
34
|
+
addPluginRender(function()
|
|
35
|
+
{
|
|
36
|
+
if (!medalsDisplayQueue.length)
|
|
37
|
+
return;
|
|
38
|
+
|
|
39
|
+
// update first medal in queue
|
|
40
|
+
const medal = medalsDisplayQueue[0];
|
|
41
|
+
const time = timeReal - medalsDisplayTimeLast;
|
|
42
|
+
if (!medalsDisplayTimeLast)
|
|
43
|
+
medalsDisplayTimeLast = timeReal;
|
|
44
|
+
else if (time > medalDisplayTime)
|
|
45
|
+
{
|
|
46
|
+
medalsDisplayTimeLast = 0;
|
|
47
|
+
medalsDisplayQueue.shift();
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
{
|
|
51
|
+
// slide on/off medals
|
|
52
|
+
const slideOffTime = medalDisplayTime - medalDisplaySlideTime;
|
|
53
|
+
const hidePercent =
|
|
54
|
+
time < medalDisplaySlideTime ? 1 - time / medalDisplaySlideTime :
|
|
55
|
+
time > slideOffTime ? (time - slideOffTime) / medalDisplaySlideTime : 0;
|
|
56
|
+
medal.render(hidePercent);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
31
59
|
}
|
|
32
60
|
|
|
61
|
+
/** Calls a function for each medal
|
|
62
|
+
* @param {Function} callback
|
|
63
|
+
* @memberof Medals */
|
|
64
|
+
function medalsForEach(callback)
|
|
65
|
+
{ Object.values(medals).forEach(medal=>callback(medal)); }
|
|
66
|
+
|
|
67
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
68
|
+
|
|
33
69
|
/**
|
|
34
70
|
* Medal - Tracks an unlockable medal
|
|
35
71
|
* @example
|
|
@@ -74,7 +110,6 @@ class Medal
|
|
|
74
110
|
ASSERT(medalsSaveName, 'save name must be set');
|
|
75
111
|
localStorage[this.storageKey()] = this.unlocked = 1;
|
|
76
112
|
medalsDisplayQueue.push(this);
|
|
77
|
-
newgrounds && newgrounds.unlockMedal(this.id);
|
|
78
113
|
}
|
|
79
114
|
|
|
80
115
|
/** Render a medal
|
|
@@ -122,171 +157,4 @@ class Medal
|
|
|
122
157
|
|
|
123
158
|
// Get local storage key used by the medal
|
|
124
159
|
storageKey() { return medalsSaveName + '_' + this.id; }
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// engine automatically renders medals
|
|
128
|
-
function medalsRender()
|
|
129
|
-
{
|
|
130
|
-
if (!medalsDisplayQueue.length)
|
|
131
|
-
return;
|
|
132
|
-
|
|
133
|
-
// update first medal in queue
|
|
134
|
-
const medal = medalsDisplayQueue[0];
|
|
135
|
-
const time = timeReal - medalsDisplayTimeLast;
|
|
136
|
-
if (!medalsDisplayTimeLast)
|
|
137
|
-
medalsDisplayTimeLast = timeReal;
|
|
138
|
-
else if (time > medalDisplayTime)
|
|
139
|
-
{
|
|
140
|
-
medalsDisplayTimeLast = 0;
|
|
141
|
-
medalsDisplayQueue.shift();
|
|
142
|
-
}
|
|
143
|
-
else
|
|
144
|
-
{
|
|
145
|
-
// slide on/off medals
|
|
146
|
-
const slideOffTime = medalDisplayTime - medalDisplaySlideTime;
|
|
147
|
-
const hidePercent =
|
|
148
|
-
time < medalDisplaySlideTime ? 1 - time / medalDisplaySlideTime :
|
|
149
|
-
time > slideOffTime ? (time - slideOffTime) / medalDisplaySlideTime : 0;
|
|
150
|
-
medal.render(hidePercent);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
155
|
-
|
|
156
|
-
// global Newgrounds object
|
|
157
|
-
let newgrounds;
|
|
158
|
-
|
|
159
|
-
/** This can used to enable Newgrounds functionality
|
|
160
|
-
* @param {Number} app_id - The newgrounds App ID
|
|
161
|
-
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
162
|
-
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher
|
|
163
|
-
* @memberof Medals */
|
|
164
|
-
function newgroundsInit(app_id, cipher, cryptoJS)
|
|
165
|
-
{ newgrounds = new Newgrounds(app_id, cipher, cryptoJS); }
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Newgrounds API wrapper object
|
|
169
|
-
* @example
|
|
170
|
-
* // create a newgrounds object, replace the app id with your own
|
|
171
|
-
* const app_id = '53123:1ZuSTQ9l';
|
|
172
|
-
* newgrounds = new Newgrounds(app_id);
|
|
173
|
-
*/
|
|
174
|
-
class Newgrounds
|
|
175
|
-
{
|
|
176
|
-
/** Create a newgrounds object
|
|
177
|
-
* @param {Number} app_id - The newgrounds App ID
|
|
178
|
-
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
179
|
-
* @param {Object} [cryptoJS] - An instance of CryptoJS, if there is a cipher */
|
|
180
|
-
constructor(app_id, cipher, cryptoJS)
|
|
181
|
-
{
|
|
182
|
-
ASSERT(!newgrounds && app_id>0, 'there can only be one newgrounds object');
|
|
183
|
-
ASSERT(!cipher || cryptoJS, 'must provide cryptojs if there is a cipher');
|
|
184
|
-
|
|
185
|
-
this.app_id = app_id;
|
|
186
|
-
this.cipher = cipher;
|
|
187
|
-
this.cryptoJS = cryptoJS;
|
|
188
|
-
this.host = location ? location.hostname : '';
|
|
189
|
-
|
|
190
|
-
// get session id from url search params
|
|
191
|
-
const url = new URL(location.href);
|
|
192
|
-
this.session_id = url.searchParams.get('ngio_session_id');
|
|
193
|
-
|
|
194
|
-
if (!this.session_id)
|
|
195
|
-
return; // only use newgrounds when logged in
|
|
196
|
-
|
|
197
|
-
// get medals
|
|
198
|
-
const medalsResult = this.call('Medal.getList');
|
|
199
|
-
this.medals = medalsResult ? medalsResult.result.data['medals'] : [];
|
|
200
|
-
debugMedals && console.log(this.medals);
|
|
201
|
-
for (const newgroundsMedal of this.medals)
|
|
202
|
-
{
|
|
203
|
-
const medal = medals[newgroundsMedal['id']];
|
|
204
|
-
if (medal)
|
|
205
|
-
{
|
|
206
|
-
// copy newgrounds medal data
|
|
207
|
-
medal.image = new Image;
|
|
208
|
-
medal.image.src = newgroundsMedal['icon'];
|
|
209
|
-
medal.name = newgroundsMedal['name'];
|
|
210
|
-
medal.description = newgroundsMedal['description'];
|
|
211
|
-
medal.unlocked = newgroundsMedal['unlocked'];
|
|
212
|
-
medal.difficulty = newgroundsMedal['difficulty'];
|
|
213
|
-
medal.value = newgroundsMedal['value'];
|
|
214
|
-
|
|
215
|
-
if (medal.value)
|
|
216
|
-
medal.description = medal.description + ' (' + medal.value + ')';
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// get scoreboards
|
|
221
|
-
const scoreboardResult = this.call('ScoreBoard.getBoards');
|
|
222
|
-
this.scoreboards = scoreboardResult ? scoreboardResult.result.data.scoreboards : [];
|
|
223
|
-
debugMedals && console.log(this.scoreboards);
|
|
224
|
-
|
|
225
|
-
const keepAliveMS = 5 * 60 * 1e3;
|
|
226
|
-
setInterval(()=>this.call('Gateway.ping', 0, true), keepAliveMS);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/** Send message to unlock a medal by id
|
|
230
|
-
* @param {Number} id - The medal id */
|
|
231
|
-
unlockMedal(id) { return this.call('Medal.unlock', {'id':id}, true); }
|
|
232
|
-
|
|
233
|
-
/** Send message to post score
|
|
234
|
-
* @param {Number} id - The scoreboard id
|
|
235
|
-
* @param {Number} value - The score value */
|
|
236
|
-
postScore(id, value) { return this.call('ScoreBoard.postScore', {'id':id, 'value':value}, true); }
|
|
237
|
-
|
|
238
|
-
/** Get scores from a scoreboard
|
|
239
|
-
* @param {Number} id - The scoreboard id
|
|
240
|
-
* @param {String} [user] - A user's id or name
|
|
241
|
-
* @param {Number} [social] - If true, only social scores will be loaded
|
|
242
|
-
* @param {Number} [skip] - Number of scores to skip before start
|
|
243
|
-
* @param {Number} [limit] - Number of scores to include in the list
|
|
244
|
-
* @return {Object} - The response JSON object
|
|
245
|
-
*/
|
|
246
|
-
getScores(id, user, social=0, skip=0, limit=10)
|
|
247
|
-
{ return this.call('ScoreBoard.getScores', {'id':id, 'user':user, 'social':social, 'skip':skip, 'limit':limit}); }
|
|
248
|
-
|
|
249
|
-
/** Send message to log a view */
|
|
250
|
-
logView() { return this.call('App.logView', {'host':this.host}, true); }
|
|
251
|
-
|
|
252
|
-
/** Send a message to call a component of the Newgrounds API
|
|
253
|
-
* @param {String} component - Name of the component
|
|
254
|
-
* @param {Object} [parameters] - Parameters to use for call
|
|
255
|
-
* @param {Boolean} [async] - If true, don't wait for response before continuing
|
|
256
|
-
* @return {Object} - The response JSON object
|
|
257
|
-
*/
|
|
258
|
-
call(component, parameters, async=false)
|
|
259
|
-
{
|
|
260
|
-
const call = {'component':component, 'parameters':parameters};
|
|
261
|
-
if (this.cipher)
|
|
262
|
-
{
|
|
263
|
-
// encrypt using AES-128 Base64 with cryptoJS
|
|
264
|
-
const cryptoJS = this.cryptoJS;
|
|
265
|
-
const aesKey = cryptoJS['enc']['Base64']['parse'](this.cipher);
|
|
266
|
-
const iv = cryptoJS['lib']['WordArray']['random'](16);
|
|
267
|
-
const encrypted = cryptoJS['AES']['encrypt'](JSON.stringify(call), aesKey, {'iv':iv});
|
|
268
|
-
call['secure'] = cryptoJS['enc']['Base64']['stringify'](iv.concat(encrypted['ciphertext']));
|
|
269
|
-
call['parameters'] = 0;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// build the input object
|
|
273
|
-
const input =
|
|
274
|
-
{
|
|
275
|
-
'app_id': this.app_id,
|
|
276
|
-
'session_id': this.session_id,
|
|
277
|
-
'call': call
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
// build post data
|
|
281
|
-
const formData = new FormData();
|
|
282
|
-
formData.append('input', JSON.stringify(input));
|
|
283
|
-
|
|
284
|
-
// send post data
|
|
285
|
-
const xmlHttp = new XMLHttpRequest();
|
|
286
|
-
const url = 'https://newgrounds.io/gateway_v3.php';
|
|
287
|
-
xmlHttp.open('POST', url, !debugMedals && async);
|
|
288
|
-
xmlHttp.send(formData);
|
|
289
|
-
debugMedals && console.log(xmlHttp.responseText);
|
|
290
|
-
return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
|
|
291
|
-
}
|
|
292
160
|
}
|
package/src/engineObject.js
CHANGED
|
@@ -85,6 +85,8 @@ class EngineObject
|
|
|
85
85
|
this.spawnTime = time;
|
|
86
86
|
/** @property {Array} - List of children of this object */
|
|
87
87
|
this.children = [];
|
|
88
|
+
/** @property {Boolean} - Limit object speed using linear or circular math */
|
|
89
|
+
this.clampSpeedLinear = true;
|
|
88
90
|
|
|
89
91
|
// parent child system
|
|
90
92
|
/** @property {EngineObject} - Parent of object if in local space */
|
|
@@ -133,8 +135,21 @@ class EngineObject
|
|
|
133
135
|
return;
|
|
134
136
|
|
|
135
137
|
// limit max speed to prevent missing collisions
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
if (this.clampSpeedLinear)
|
|
139
|
+
{
|
|
140
|
+
this.velocity.x = clamp(this.velocity.x, -objectMaxSpeed, objectMaxSpeed);
|
|
141
|
+
this.velocity.y = clamp(this.velocity.y, -objectMaxSpeed, objectMaxSpeed);
|
|
142
|
+
}
|
|
143
|
+
else
|
|
144
|
+
{
|
|
145
|
+
const length2 = this.velocity.lengthSquared();
|
|
146
|
+
if (length2 > objectMaxSpeed*objectMaxSpeed)
|
|
147
|
+
{
|
|
148
|
+
const s = objectMaxSpeed / length2**.5;
|
|
149
|
+
this.velocity.x *= s;
|
|
150
|
+
this.velocity.y *= s;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
138
153
|
|
|
139
154
|
// apply physics
|
|
140
155
|
const oldPos = this.pos.copy();
|
|
@@ -190,7 +205,7 @@ class EngineObject
|
|
|
190
205
|
if (o.mass) // push away if not fixed
|
|
191
206
|
o.velocity = o.velocity.subtract(velocity);
|
|
192
207
|
|
|
193
|
-
debugOverlay && debugPhysics &&
|
|
208
|
+
debugOverlay && debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
|
|
194
209
|
continue;
|
|
195
210
|
}
|
|
196
211
|
|
|
@@ -252,7 +267,7 @@ class EngineObject
|
|
|
252
267
|
else // bounce if other object is fixed
|
|
253
268
|
this.velocity.x *= -elasticity;
|
|
254
269
|
}
|
|
255
|
-
debugOverlay && debugPhysics &&
|
|
270
|
+
debugOverlay && debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f0f');
|
|
256
271
|
}
|
|
257
272
|
}
|
|
258
273
|
if (this.collideTiles)
|
|
@@ -313,6 +328,22 @@ class EngineObject
|
|
|
313
328
|
for (const child of this.children)
|
|
314
329
|
child.destroy(child.parent = 0);
|
|
315
330
|
}
|
|
331
|
+
|
|
332
|
+
/** Convert from local space to world space
|
|
333
|
+
* @param {Vector2} pos - local space point */
|
|
334
|
+
localToWorld(pos) { return this.pos.add(pos.rotate(-this.angle)); }
|
|
335
|
+
|
|
336
|
+
/** Convert from world space to local space
|
|
337
|
+
* @param {Vector2} pos - world space point */
|
|
338
|
+
worldToLocal(pos) { return pos.subtract(this.pos).rotate(this.angle); }
|
|
339
|
+
|
|
340
|
+
/** Convert from local space to world space for a vector (rotation only)
|
|
341
|
+
* @param {Vector2} vec - local space vector */
|
|
342
|
+
localToWorldVector(vec) { return vec.rotate(this.angle); }
|
|
343
|
+
|
|
344
|
+
/** Convert from world space to local space for a vector (rotation only)
|
|
345
|
+
* @param {Vector2} vec - world space vector */
|
|
346
|
+
worldToLocalVector(vec) { return vec.rotate(-this.angle); }
|
|
316
347
|
|
|
317
348
|
/** Called to check if a tile collision should be resolved
|
|
318
349
|
* @param {Number} tileData - the value of the tile at the position
|
|
@@ -399,4 +430,16 @@ class EngineObject
|
|
|
399
430
|
return text;
|
|
400
431
|
}
|
|
401
432
|
}
|
|
433
|
+
|
|
434
|
+
/** Render debug info for this object */
|
|
435
|
+
renderDebugInfo()
|
|
436
|
+
{
|
|
437
|
+
// show object info for debugging
|
|
438
|
+
const size = vec2(max(this.size.x, .2), max(this.size.y, .2));
|
|
439
|
+
const color1 = rgb(this.collideTiles?1:0, this.collideSolidObjects?1:0, this.isSolid?1:0, this.parent?.2:.5);
|
|
440
|
+
const color2 = this.parent ? rgb(1,1,1,.5) : rgb(0,0,0,.8);
|
|
441
|
+
drawRect(this.pos, size, color1, this.angle, false);
|
|
442
|
+
drawRect(this.pos, size.scale(.8), color2, this.angle, false);
|
|
443
|
+
this.parent && drawLine(this.pos, this.parent.pos, .1, rgb(0,0,1,.5), false);
|
|
444
|
+
}
|
|
402
445
|
}
|
package/src/engineParticles.js
CHANGED
|
@@ -274,6 +274,9 @@ class Particle extends EngineObject
|
|
|
274
274
|
this.localSpaceEmitter = localSpaceEmitter;
|
|
275
275
|
/** @property {Function} - Called when particle dies */
|
|
276
276
|
this.destroyCallback = destroyCallback;
|
|
277
|
+
|
|
278
|
+
// particles use circular clamped speed
|
|
279
|
+
this.clampSpeedLinear = false;
|
|
277
280
|
}
|
|
278
281
|
|
|
279
282
|
/** Render the particle, automatically called each frame, sorted by renderOrder */
|
package/src/engineRelease.js
CHANGED
|
@@ -22,10 +22,13 @@ function debugInit (){}
|
|
|
22
22
|
function debugUpdate (){}
|
|
23
23
|
function debugRender (){}
|
|
24
24
|
function debugRect (){}
|
|
25
|
+
function debugPoly (){}
|
|
25
26
|
function debugCircle (){}
|
|
26
27
|
function debugPoint (){}
|
|
27
28
|
function debugLine (){}
|
|
28
|
-
function
|
|
29
|
+
function debugOverlap (){}
|
|
29
30
|
function debugText (){}
|
|
30
31
|
function debugClear (){}
|
|
31
|
-
function debugSaveCanvas (){}
|
|
32
|
+
function debugSaveCanvas (){}
|
|
33
|
+
function debugSaveText (){}
|
|
34
|
+
function debugSaveDataURL(){}
|
package/src/engineSettings.js
CHANGED
|
@@ -26,9 +26,9 @@ let cameraScale = 32;
|
|
|
26
26
|
|
|
27
27
|
/** The max size of the canvas, centered if window is larger
|
|
28
28
|
* @type {Vector2}
|
|
29
|
-
* @default Vector2(1920,
|
|
29
|
+
* @default Vector2(1920,1080)
|
|
30
30
|
* @memberof Settings */
|
|
31
|
-
let canvasMaxSize = vec2(1920,
|
|
31
|
+
let canvasMaxSize = vec2(1920, 1080);
|
|
32
32
|
|
|
33
33
|
/** Fixed size of the canvas, if enabled canvas size never changes
|
|
34
34
|
* - you may also need to set mainCanvasSize if using screen space coords in startup
|
|
@@ -417,7 +417,12 @@ function setSoundEnable(enable) { soundEnable = enable; }
|
|
|
417
417
|
/** Set volume scale to apply to all sound, music and speech
|
|
418
418
|
* @param {Number} volume
|
|
419
419
|
* @memberof Settings */
|
|
420
|
-
function setSoundVolume(volume)
|
|
420
|
+
function setSoundVolume(volume)
|
|
421
|
+
{
|
|
422
|
+
soundVolume = volume;
|
|
423
|
+
if (soundEnable && !headlessMode && audioGainNode)
|
|
424
|
+
audioGainNode.gain.value = volume; // update gain immediatly
|
|
425
|
+
}
|
|
421
426
|
|
|
422
427
|
/** Set default range where sound no longer plays
|
|
423
428
|
* @param {Number} range
|