littlejsengine 1.14.9 → 1.14.11
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/dist/littlejs.d.ts +12 -11
- package/dist/littlejs.esm.js +121 -73
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +120 -73
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +102 -56
- package/examples/index.html +52 -47
- package/examples/platformer/gameCharacter.js +6 -2
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +7 -5
- package/examples/shorts/blending.js +1 -1
- package/examples/shorts/landerGame.js +26 -2
- package/examples/shorts/music.js +3 -2
- package/examples/shorts/particles.js +11 -11
- package/examples/shorts/pongGame.js +0 -1
- package/examples/shorts/raycasting.js +4 -1
- package/examples/shorts/slidingPuzzle.js +13 -5
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/uiSystem.js +0 -4
- package/examples/uiSystem/game.js +4 -4
- package/package.json +1 -1
- package/plugins/box2d.js +1 -1
- package/plugins/newgrounds.js +4 -4
- package/plugins/uiSystem.js +1 -1
- package/reference.md +0 -2
- package/src/engine.js +20 -12
- package/src/engineDebug.js +19 -17
- package/src/engineExport.js +1 -0
- package/src/engineInput.js +49 -22
- package/src/engineRelease.js +1 -0
- package/src/engineSettings.js +6 -0
- package/src/engineTileLayer.js +7 -1
- package/src/engineUtilities.js +12 -14
package/examples/shorts/music.js
CHANGED
|
@@ -48,7 +48,6 @@ function gameInit()
|
|
|
48
48
|
|
|
49
49
|
// stop button
|
|
50
50
|
stopButton = new UIButton(vec2(90, 30), vec2(140, 50), 'Stop');
|
|
51
|
-
musicPlayer.addChild(stopButton);
|
|
52
51
|
stopButton.onClick = ()=>
|
|
53
52
|
{
|
|
54
53
|
if (!musicInstance)
|
|
@@ -57,10 +56,11 @@ function gameInit()
|
|
|
57
56
|
// stop sound
|
|
58
57
|
musicInstance.stop();
|
|
59
58
|
};
|
|
59
|
+
musicPlayer.addChild(stopButton);
|
|
60
60
|
|
|
61
61
|
// progress bar and scrollbar for seeking
|
|
62
62
|
progressBar = new UIScrollbar(vec2(0, 100), vec2(400, 30), 0, 'Progress');
|
|
63
|
-
|
|
63
|
+
progressBar.disabledColor = RED;
|
|
64
64
|
progressBar.onChange = ()=>
|
|
65
65
|
{
|
|
66
66
|
// control music seek position
|
|
@@ -73,6 +73,7 @@ function gameInit()
|
|
|
73
73
|
if (!wasPlaying)
|
|
74
74
|
musicInstance.pause();
|
|
75
75
|
};
|
|
76
|
+
musicPlayer.addChild(progressBar);
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
function gameUpdate()
|
|
@@ -4,25 +4,25 @@ function gameInit()
|
|
|
4
4
|
|
|
5
5
|
// fire
|
|
6
6
|
new ParticleEmitter(
|
|
7
|
-
vec2(-5,-2), 0,
|
|
7
|
+
vec2(-5,-2), 0, // pos, angle
|
|
8
8
|
2, 0, 200, PI, // emitSize, emitTime, emitRate, emitCone
|
|
9
9
|
tile(0), // tileInfo
|
|
10
10
|
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
11
11
|
rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
|
|
12
|
-
.7, 2, 0, .2, .05,
|
|
13
|
-
.9, 1, -1, PI, .05,
|
|
14
|
-
.5, 0, 1, 0
|
|
12
|
+
.7, 2, 0, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
13
|
+
.9, 1, -1, PI, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
14
|
+
.5, 0, 1, 0 // randomness, collide, additive, colorLinear
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
// smoke
|
|
18
18
|
new ParticleEmitter(
|
|
19
|
-
vec2(5,-2), 0,
|
|
20
|
-
3, 0, 100, PI,
|
|
21
|
-
tile(0),
|
|
22
|
-
hsl(0,0,0,.5), hsl(0,0,1,.5),
|
|
19
|
+
vec2(5,-2), 0, // pos, angle
|
|
20
|
+
3, 0, 100, PI, // emitSize, emitTime, emitRate, emitCone
|
|
21
|
+
tile(0), // tileInfo
|
|
22
|
+
hsl(0,0,0,.5), hsl(0,0,1,.5), // colorStartA, colorStartB
|
|
23
23
|
hsl(0,0,0,0), hsl(0,0,1,0), // colorEndA, colorEndB
|
|
24
|
-
1, 1, 5, .2, .01,
|
|
25
|
-
.85, 1, -1, PI, .3,
|
|
26
|
-
.5, 0, 0, 1
|
|
24
|
+
1, 1, 5, .2, .01, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
25
|
+
.85, 1, -1, PI, .3, // damp, angleDamp, gravity, particleCone, fade
|
|
26
|
+
.5, 0, 0, 1 // randomness, collide, additive, colorLinear
|
|
27
27
|
);
|
|
28
28
|
}
|
|
@@ -31,7 +31,10 @@ function gameUpdate()
|
|
|
31
31
|
playerAngle += mouseDelta.x * .003;
|
|
32
32
|
|
|
33
33
|
// update player movement, prevent walking through walls
|
|
34
|
-
|
|
34
|
+
let velocity = keyDirection();
|
|
35
|
+
if (velocity.y && mouseIsDown(0))
|
|
36
|
+
velocity.y = 1; // forward movement with mouse
|
|
37
|
+
velocity = velocity.rotate(playerAngle).scale(.1);
|
|
35
38
|
const newPos = playerPos.add(velocity);
|
|
36
39
|
if (!levelTest(newPos.x, newPos.y))
|
|
37
40
|
playerPos = newPos;
|
|
@@ -6,27 +6,35 @@ class PuzzlePiece extends EngineObject
|
|
|
6
6
|
{
|
|
7
7
|
constructor(gridPos, size)
|
|
8
8
|
{
|
|
9
|
-
const
|
|
9
|
+
const x = gridPos.x, y = gridPos.y;
|
|
10
|
+
const color = rgb(x/(gridSize.x-1), y/(gridSize.y-1), 1);
|
|
10
11
|
super(gridPos.multiply(size), size, 0, 0, color);
|
|
11
12
|
this.gridPos = gridPos;
|
|
12
|
-
this.text =
|
|
13
|
+
this.text = x + y*gridSize.x;
|
|
14
|
+
this.moveTimer = new Timer;
|
|
15
|
+
this.lastPos = this.pos;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
update()
|
|
16
19
|
{
|
|
20
|
+
const deltaX = emptyGridPos.x - this.gridPos.x;
|
|
21
|
+
const deltaY = emptyGridPos.y - this.gridPos.y;
|
|
17
22
|
if (mouseWasPressed(0) && isOverlapping(this.pos, this.size, mousePos))
|
|
18
|
-
if (abs(
|
|
23
|
+
if (abs(deltaX) + abs(deltaY) === 1)
|
|
19
24
|
{
|
|
20
25
|
// swap with empty space when clicked on
|
|
26
|
+
this.lastPos = this.pos;
|
|
21
27
|
this.pos = emptyGridPos.multiply(this.size);
|
|
22
28
|
[emptyGridPos, this.gridPos] = [this.gridPos, emptyGridPos];
|
|
29
|
+
this.moveTimer.set(.2);
|
|
23
30
|
}
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
render()
|
|
27
34
|
{
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
const pos = this.lastPos.lerp(this.pos, this.moveTimer.getPercent());
|
|
36
|
+
drawRect(pos, this.size, this.color);
|
|
37
|
+
drawTextOverlay(this.text, pos, 2.5, BLACK);
|
|
30
38
|
}
|
|
31
39
|
}
|
|
32
40
|
|
|
@@ -41,14 +41,14 @@ function createUI()
|
|
|
41
41
|
uiMenu.addChild(uiBackground);
|
|
42
42
|
|
|
43
43
|
// example large text
|
|
44
|
-
const textTitle = new LJS.UIText(vec2(0,-220), vec2(500,
|
|
44
|
+
const textTitle = new LJS.UIText(vec2(0,-220), vec2(500, 120), 'Test Title');
|
|
45
45
|
uiMenu.addChild(textTitle);
|
|
46
46
|
textTitle.textColor = LJS.RED;
|
|
47
47
|
textTitle.lineWidth = 4;
|
|
48
48
|
textTitle.lineColor = LJS.BLUE;
|
|
49
49
|
|
|
50
50
|
// example multiline text
|
|
51
|
-
const textTest = new LJS.UIText(vec2(-60,-120), vec2(
|
|
51
|
+
const textTest = new LJS.UIText(vec2(-60,-120), vec2(350, 60), 'Test Text\nSecond text line.')
|
|
52
52
|
uiMenu.addChild(textTest);
|
|
53
53
|
|
|
54
54
|
// example tile image
|
|
@@ -63,7 +63,7 @@ function createUI()
|
|
|
63
63
|
// example button
|
|
64
64
|
const button1 = new LJS.UIButton(vec2(0,140), vec2(350, 50), 'Test Button');
|
|
65
65
|
uiMenu.addChild(button1);
|
|
66
|
-
button1.onClick = ()=>
|
|
66
|
+
button1.onClick = ()=> LOG('Button 1 clicked');
|
|
67
67
|
|
|
68
68
|
// example checkbox
|
|
69
69
|
const checkbox = new LJS.UICheckbox(vec2(-140,-20), vec2(40));
|
|
@@ -71,7 +71,7 @@ function createUI()
|
|
|
71
71
|
checkbox.onChange = ()=> button1.disabled = checkbox.checked;
|
|
72
72
|
|
|
73
73
|
// text attached to checkbox
|
|
74
|
-
const checkboxText = new LJS.UIText(vec2(170,0), vec2(300,
|
|
74
|
+
const checkboxText = new LJS.UIText(vec2(170,0), vec2(300, 60), 'Test Checkbox');
|
|
75
75
|
checkbox.addChild(checkboxText);
|
|
76
76
|
|
|
77
77
|
// exit button
|
package/package.json
CHANGED
package/plugins/box2d.js
CHANGED
package/plugins/newgrounds.js
CHANGED
|
@@ -76,7 +76,7 @@ class NewgroundsPlugin
|
|
|
76
76
|
// get medals
|
|
77
77
|
const medalsResult = this.call('Medal.getList');
|
|
78
78
|
this.medals = medalsResult ? medalsResult.result.data['medals'] : [];
|
|
79
|
-
debugMedals &&
|
|
79
|
+
debugMedals && LOG(this.medals);
|
|
80
80
|
for (const newgroundsMedal of this.medals)
|
|
81
81
|
{
|
|
82
82
|
const medal = medals[newgroundsMedal['id']];
|
|
@@ -99,7 +99,7 @@ class NewgroundsPlugin
|
|
|
99
99
|
// get scoreboards
|
|
100
100
|
const scoreboardResult = this.call('ScoreBoard.getBoards');
|
|
101
101
|
this.scoreboards = scoreboardResult ? scoreboardResult.result.data.scoreboards : [];
|
|
102
|
-
debugMedals &&
|
|
102
|
+
debugMedals && LOG(this.scoreboards);
|
|
103
103
|
|
|
104
104
|
// keep the session alive with a ping every minute
|
|
105
105
|
const keepAliveMS = 60 * 1e3;
|
|
@@ -168,10 +168,10 @@ class NewgroundsPlugin
|
|
|
168
168
|
try { xmlHttp.send(formData); }
|
|
169
169
|
catch(e)
|
|
170
170
|
{
|
|
171
|
-
debugMedals &&
|
|
171
|
+
debugMedals && LOG('newgrounds call failed', e);
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
174
|
-
debugMedals &&
|
|
174
|
+
debugMedals && LOG(xmlHttp.responseText);
|
|
175
175
|
return xmlHttp.responseText && JSON.parse(xmlHttp.responseText);
|
|
176
176
|
}
|
|
177
177
|
}
|
package/plugins/uiSystem.js
CHANGED
|
@@ -284,7 +284,7 @@ class UIObject
|
|
|
284
284
|
const mouseDown = mouseIsDown(0);
|
|
285
285
|
const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
|
|
286
286
|
if (!uiSystem.hoverObject)
|
|
287
|
-
if (mousePress || !mouseDown
|
|
287
|
+
if (mousePress || isActive || (!mouseDown && !isTouchDevice))
|
|
288
288
|
{
|
|
289
289
|
const size = this.size.add(vec2(isTouchDevice && this.extraTouchSize || 0));
|
|
290
290
|
if (isOverlapping(this.pos, size, mousePosScreen))
|
package/reference.md
CHANGED
|
@@ -77,7 +77,6 @@ Vector2.normalize(length=1) // Normalize this vector to length
|
|
|
77
77
|
Vector2.clampLength(length=1) // Clamp this vector to length
|
|
78
78
|
Vector2.dot(v) // Dot product with vector
|
|
79
79
|
Vector2.cross(v) // Cross product with vector
|
|
80
|
-
Vector2.invert() // Invert this vector
|
|
81
80
|
Vector2.floor() // Floor this vector
|
|
82
81
|
Vector2.area() // Get area covered by this vector as a rectangle
|
|
83
82
|
Vector2.lerp(v, percent) // Interpolate between vectors
|
|
@@ -442,7 +441,6 @@ debug // Is debug enabled?
|
|
|
442
441
|
debugPointSize = .5 // Size to render debug points by default
|
|
443
442
|
debugKey = 'Escape' // Key code used to toggle debug mode
|
|
444
443
|
debugOverlay // True if the debug overlay is active
|
|
445
|
-
enableAsserts // True if asserts are enabled
|
|
446
444
|
showWatermark // True if watermark with FPS should be show
|
|
447
445
|
```
|
|
448
446
|
|
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {string}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.14.
|
|
33
|
+
const engineVersion = '1.14.11';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -119,12 +119,12 @@ function engineAddPlugin(updateFunction, renderFunction)
|
|
|
119
119
|
* @example
|
|
120
120
|
* // Basic engine startup
|
|
121
121
|
* engineInit(
|
|
122
|
-
* () => {
|
|
123
|
-
* () => { updateGameLogic(); },
|
|
124
|
-
* () => { updateUI(); },
|
|
125
|
-
* () => { drawBackground(); },
|
|
126
|
-
* () => { drawHUD(); },
|
|
127
|
-
* ['tiles.png', 'tilesLevel.png']
|
|
122
|
+
* () => { LOG('Game initialized!'); }, // gameInit
|
|
123
|
+
* () => { updateGameLogic(); }, // gameUpdate
|
|
124
|
+
* () => { updateUI(); }, // gameUpdatePost
|
|
125
|
+
* () => { drawBackground(); }, // gameRender
|
|
126
|
+
* () => { drawHUD(); }, // gameRenderPost
|
|
127
|
+
* ['tiles.png', 'tilesLevel.png'] // images to load
|
|
128
128
|
* );
|
|
129
129
|
* @memberof Engine */
|
|
130
130
|
async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
@@ -170,16 +170,20 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
170
170
|
if (!debugSpeedUp)
|
|
171
171
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp min framerate
|
|
172
172
|
|
|
173
|
+
let wasUpdated = false;
|
|
173
174
|
if (paused)
|
|
174
175
|
{
|
|
176
|
+
// update everything except the game and objects
|
|
177
|
+
wasUpdated = true;
|
|
175
178
|
updateCanvas();
|
|
179
|
+
inputUpdate();
|
|
180
|
+
pluginUpdateList.forEach(f=>f());
|
|
176
181
|
|
|
177
182
|
// update object transforms even when paused
|
|
178
183
|
for (const o of engineObjects)
|
|
179
184
|
o.parent || o.updateTransforms();
|
|
180
185
|
|
|
181
|
-
|
|
182
|
-
pluginUpdateList.forEach(f=>f());
|
|
186
|
+
// do post update
|
|
183
187
|
debugUpdate();
|
|
184
188
|
gameUpdatePost();
|
|
185
189
|
inputUpdatePost();
|
|
@@ -196,12 +200,13 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
196
200
|
}
|
|
197
201
|
|
|
198
202
|
// update multiple frames if necessary in case of slow framerate
|
|
199
|
-
for (;frameTimeBufferMS >= 0; frameTimeBufferMS -= 1e3 / frameRate)
|
|
203
|
+
for (; frameTimeBufferMS >= 0; frameTimeBufferMS -= 1e3 / frameRate)
|
|
200
204
|
{
|
|
201
205
|
// increment frame and update time
|
|
202
206
|
time = frame++ / frameRate;
|
|
203
207
|
|
|
204
208
|
// update game and objects
|
|
209
|
+
wasUpdated = true;
|
|
205
210
|
updateCanvas();
|
|
206
211
|
inputUpdate();
|
|
207
212
|
gameUpdate();
|
|
@@ -212,7 +217,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
212
217
|
debugUpdate();
|
|
213
218
|
gameUpdatePost();
|
|
214
219
|
inputUpdatePost();
|
|
215
|
-
|
|
216
220
|
if (debugVideoCaptureIsActive())
|
|
217
221
|
renderFrame();
|
|
218
222
|
}
|
|
@@ -229,6 +233,10 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
229
233
|
{
|
|
230
234
|
if (headlessMode) return;
|
|
231
235
|
|
|
236
|
+
// canvas must be updated before rendering
|
|
237
|
+
if (!wasUpdated)
|
|
238
|
+
updateCanvas();
|
|
239
|
+
|
|
232
240
|
// render sort then render while removing destroyed objects
|
|
233
241
|
enginePreRender();
|
|
234
242
|
gameRender();
|
|
@@ -388,7 +396,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
388
396
|
promises.push(new Promise(resolve =>
|
|
389
397
|
{
|
|
390
398
|
let t = 0;
|
|
391
|
-
|
|
399
|
+
LOG(`${engineName} Engine v${engineVersion}`);
|
|
392
400
|
updateSplash();
|
|
393
401
|
function updateSplash()
|
|
394
402
|
{
|
package/src/engineDebug.js
CHANGED
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
* @memberof Debug */
|
|
17
17
|
const debug = true;
|
|
18
18
|
|
|
19
|
-
/** True if asserts are enabled
|
|
20
|
-
* @type {boolean}
|
|
21
|
-
* @default
|
|
22
|
-
* @memberof Debug */
|
|
23
|
-
const enableAsserts = true;
|
|
24
|
-
|
|
25
19
|
/** Size to render debug points by default
|
|
26
20
|
* @type {number}
|
|
27
21
|
* @default
|
|
@@ -52,15 +46,16 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
|
|
|
52
46
|
///////////////////////////////////////////////////////////////////////////////
|
|
53
47
|
// Debug helper functions
|
|
54
48
|
|
|
55
|
-
/** Asserts if the expression is false, does
|
|
49
|
+
/** Asserts if the expression is false, does nothing in release builds
|
|
56
50
|
* @param {boolean} assert
|
|
57
51
|
* @param {...Object} [output] - error message output
|
|
58
52
|
* @memberof Debug */
|
|
59
|
-
function ASSERT(assert, ...output)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
function ASSERT(assert, ...output) { console.assert(assert, ...output); }
|
|
54
|
+
|
|
55
|
+
/** Log to console if debug is enabled, does nothing in release builds
|
|
56
|
+
* @param {...Object} [output] - message output
|
|
57
|
+
* @memberof Debug */
|
|
58
|
+
function LOG(...output) { console.log(...output); }
|
|
64
59
|
|
|
65
60
|
/** Draw a debug rectangle in world space
|
|
66
61
|
* @param {Vector2} pos
|
|
@@ -455,7 +450,8 @@ function debugRender()
|
|
|
455
450
|
{
|
|
456
451
|
overlayContext.fillText(`${engineName} v${engineVersion}`, x, y += h/2 );
|
|
457
452
|
overlayContext.fillText('Time: ' + formatTime(time), x, y += h);
|
|
458
|
-
overlayContext.fillText('FPS: ' + averageFPS.toFixed(1)
|
|
453
|
+
overlayContext.fillText('FPS: ' + averageFPS.toFixed(1) + (glEnable?' WebGL':' Canvas2D'),
|
|
454
|
+
x, y += h);
|
|
459
455
|
overlayContext.fillText('Objects: ' + engineObjects.length, x, y += h);
|
|
460
456
|
overlayContext.fillText('Draw Count: ' + drawCount, x, y += h);
|
|
461
457
|
overlayContext.fillText('---------', x, y += h);
|
|
@@ -474,12 +470,18 @@ function debugRender()
|
|
|
474
470
|
overlayContext.fillText('6: Toggle Video Capture', x, y += h);
|
|
475
471
|
|
|
476
472
|
let keysPressed = '';
|
|
473
|
+
let mousePressed = '';
|
|
477
474
|
for (const i in inputData[0])
|
|
478
475
|
{
|
|
479
|
-
if (keyIsDown(i, 0))
|
|
476
|
+
if (!keyIsDown(i, 0))
|
|
477
|
+
continue;
|
|
478
|
+
if (parseInt(i) < 3)
|
|
479
|
+
mousePressed += i + ' ' ;
|
|
480
|
+
else if (keyIsDown(i, 0))
|
|
480
481
|
keysPressed += i + ' ' ;
|
|
481
482
|
}
|
|
482
|
-
|
|
483
|
+
mousePressed && overlayContext.fillText('Mouse: ' + mousePressed, x, y += h);
|
|
484
|
+
keysPressed && overlayContext.fillText('Keys: ' + keysPressed, x, y += h);
|
|
483
485
|
|
|
484
486
|
let buttonsPressed = '';
|
|
485
487
|
if (inputData[1])
|
|
@@ -547,7 +549,7 @@ function debugVideoCaptureStart()
|
|
|
547
549
|
}
|
|
548
550
|
|
|
549
551
|
// start recording
|
|
550
|
-
|
|
552
|
+
LOG('Video capture started.');
|
|
551
553
|
debugVideoCapture.start();
|
|
552
554
|
debugVideoCaptureTimer = new Timer(0);
|
|
553
555
|
|
|
@@ -574,7 +576,7 @@ function debugVideoCaptureStop()
|
|
|
574
576
|
return; // not recording
|
|
575
577
|
|
|
576
578
|
// stop recording
|
|
577
|
-
|
|
579
|
+
LOG(`Video capture ended. ${debugVideoCaptureTimer.get().toFixed(2)} seconds recorded.`);
|
|
578
580
|
debugVideoCapture.stop();
|
|
579
581
|
debugVideoCapture = 0;
|
|
580
582
|
debugVideoCaptureIcon.style.display = 'none';
|
package/src/engineExport.js
CHANGED
package/src/engineInput.js
CHANGED
|
@@ -278,7 +278,7 @@ function inputInit()
|
|
|
278
278
|
function onMouseLeave()
|
|
279
279
|
{
|
|
280
280
|
// set mouse position and delta when leaving canvas
|
|
281
|
-
mousePosScreen = vec2(
|
|
281
|
+
mousePosScreen = vec2(-1);
|
|
282
282
|
mouseDeltaScreen = vec2(0);
|
|
283
283
|
}
|
|
284
284
|
}
|
|
@@ -333,10 +333,12 @@ function gamepadsUpdate()
|
|
|
333
333
|
const data = inputData[1] || (inputData[1] = []);
|
|
334
334
|
for (let i=10; i--;)
|
|
335
335
|
{
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
data[j] = touchGamepadButtons[i] ? wasDown ? 1 : 3 : wasDown ? 4 : 0;
|
|
336
|
+
const wasDown = gamepadIsDown(i,0);
|
|
337
|
+
data[i] = touchGamepadButtons[i] ? wasDown ? 1 : 3 : wasDown ? 4 : 0;
|
|
339
338
|
}
|
|
339
|
+
|
|
340
|
+
// disable normal gamepads when touch gamepad is active
|
|
341
|
+
return;
|
|
340
342
|
}
|
|
341
343
|
|
|
342
344
|
// return if gamepads are disabled or not supported
|
|
@@ -411,6 +413,15 @@ const isTouchDevice = !headlessMode && window.ontouchstart !== undefined;
|
|
|
411
413
|
// touch gamepad internal variables
|
|
412
414
|
let touchGamepadTimer = new Timer, touchGamepadButtons = [], touchGamepadStick = vec2();
|
|
413
415
|
|
|
416
|
+
function touchGamepadButtonCenter()
|
|
417
|
+
{
|
|
418
|
+
// draw right face buttons
|
|
419
|
+
let center = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
420
|
+
if (touchGamepadButtonCount <= 2)
|
|
421
|
+
center.x += touchGamepadSize/2;
|
|
422
|
+
return center;
|
|
423
|
+
}
|
|
424
|
+
|
|
414
425
|
// enable touch input mouse passthrough
|
|
415
426
|
function touchInputInit()
|
|
416
427
|
{
|
|
@@ -458,8 +469,8 @@ function touchInputInit()
|
|
|
458
469
|
// set was touching
|
|
459
470
|
wasTouching = touching;
|
|
460
471
|
|
|
461
|
-
// prevent default handling like copy
|
|
462
|
-
if (inputPreventDefault && document.hasFocus()
|
|
472
|
+
// prevent default handling like copy, magnifier lens, and scrolling
|
|
473
|
+
if (inputPreventDefault && document.hasFocus() && e.cancelable)
|
|
463
474
|
e.preventDefault();
|
|
464
475
|
|
|
465
476
|
// must return true so the document will get focus
|
|
@@ -488,25 +499,36 @@ function touchInputInit()
|
|
|
488
499
|
|
|
489
500
|
// get center of left and right sides
|
|
490
501
|
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
491
|
-
const buttonCenter =
|
|
502
|
+
const buttonCenter = touchGamepadButtonCenter();
|
|
492
503
|
const startCenter = mainCanvasSize.scale(.5);
|
|
493
504
|
|
|
494
505
|
// check each touch point
|
|
495
506
|
for (const touch of e.touches)
|
|
496
507
|
{
|
|
497
508
|
const touchPos = mouseEventToScreen(vec2(touch.clientX, touch.clientY));
|
|
498
|
-
if (
|
|
509
|
+
if (stickCenter.distance(touchPos) < touchGamepadSize)
|
|
499
510
|
{
|
|
500
511
|
// virtual analog stick
|
|
501
512
|
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
502
513
|
}
|
|
503
|
-
else if (
|
|
514
|
+
else if (buttonCenter.distance(touchPos) < touchGamepadSize)
|
|
504
515
|
{
|
|
505
516
|
// virtual face buttons
|
|
506
|
-
|
|
507
|
-
|
|
517
|
+
let button = buttonCenter.subtract(touchPos).direction();
|
|
518
|
+
button = mod(button+2, 4);
|
|
519
|
+
if (touchGamepadButtonCount === 1)
|
|
520
|
+
button = 0;
|
|
521
|
+
else if (touchGamepadButtonCount === 2)
|
|
522
|
+
{
|
|
523
|
+
const delta = buttonCenter.subtract(touchPos);
|
|
524
|
+
button = -delta.x < delta.y ? 1 : 0;
|
|
525
|
+
}
|
|
526
|
+
// fix button locations (swap 2 and 3 to match gamepad layout)
|
|
527
|
+
button = button === 3 ? 2 : button === 2 ? 3 : button;
|
|
528
|
+
if (button < touchGamepadButtonCount)
|
|
529
|
+
touchGamepadButtons[button] = 1;
|
|
508
530
|
}
|
|
509
|
-
else if (
|
|
531
|
+
else if (startCenter.distance(touchPos) < touchGamepadSize && !wasTouching)
|
|
510
532
|
{
|
|
511
533
|
// virtual start button in center
|
|
512
534
|
touchGamepadButtons[9] = 1;
|
|
@@ -537,11 +559,10 @@ function touchGamepadRender()
|
|
|
537
559
|
// draw left analog stick
|
|
538
560
|
context.fillStyle = touchGamepadStick.lengthSquared() > 0 ? '#fff' : '#000';
|
|
539
561
|
context.beginPath();
|
|
540
|
-
|
|
541
|
-
const leftCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
562
|
+
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
542
563
|
if (touchGamepadAnalog) // draw circle shaped gamepad
|
|
543
564
|
{
|
|
544
|
-
context.arc(
|
|
565
|
+
context.arc(stickCenter.x, stickCenter.y, touchGamepadSize/2, 0, 9);
|
|
545
566
|
context.fill();
|
|
546
567
|
context.stroke();
|
|
547
568
|
}
|
|
@@ -550,21 +571,27 @@ function touchGamepadRender()
|
|
|
550
571
|
for (let i=10; i--;)
|
|
551
572
|
{
|
|
552
573
|
const angle = i*PI/4;
|
|
553
|
-
context.arc(
|
|
554
|
-
i%2 && context.arc(
|
|
574
|
+
context.arc(stickCenter.x, stickCenter.y,touchGamepadSize*.6, angle + PI/8, angle + PI/8);
|
|
575
|
+
i%2 && context.arc(stickCenter.x, stickCenter.y, touchGamepadSize*.33, angle, angle);
|
|
555
576
|
i===1 && context.fill();
|
|
556
577
|
}
|
|
557
578
|
context.stroke();
|
|
558
579
|
}
|
|
559
580
|
|
|
560
581
|
// draw right face buttons
|
|
561
|
-
const
|
|
562
|
-
|
|
582
|
+
const buttonCenter = touchGamepadButtonCenter();
|
|
583
|
+
const buttonSize = touchGamepadButtonCount > 1 ? touchGamepadSize/4 : touchGamepadSize/2;
|
|
584
|
+
for (let i=0; i<touchGamepadButtonCount; i++)
|
|
563
585
|
{
|
|
564
|
-
|
|
565
|
-
|
|
586
|
+
let j = mod(i-1, 4);
|
|
587
|
+
let button = touchGamepadButtonCount > 2 ?
|
|
588
|
+
j : min(j, touchGamepadButtonCount-1);
|
|
589
|
+
// fix button locations (swap 2 and 3 to match gamepad layout)
|
|
590
|
+
button = button === 3 ? 2 : button === 2 ? 3 : button;
|
|
591
|
+
const pos = buttonCenter.add(vec2().setDirection(j, touchGamepadSize/2));
|
|
592
|
+
context.fillStyle = touchGamepadButtons[button] ? '#fff' : '#000';
|
|
566
593
|
context.beginPath();
|
|
567
|
-
context.arc(pos.x, pos.y,
|
|
594
|
+
context.arc(pos.x, pos.y, buttonSize, 0,9);
|
|
568
595
|
context.fill();
|
|
569
596
|
context.stroke();
|
|
570
597
|
}
|
package/src/engineRelease.js
CHANGED
package/src/engineSettings.js
CHANGED
|
@@ -222,6 +222,12 @@ let touchGamepadEnable = false;
|
|
|
222
222
|
* @memberof Settings */
|
|
223
223
|
let touchGamepadAnalog = true;
|
|
224
224
|
|
|
225
|
+
/** Number of buttons on touch gamepad
|
|
226
|
+
* @type {number}
|
|
227
|
+
* @default
|
|
228
|
+
* @memberof Settings */
|
|
229
|
+
let touchGamepadButtonCount = 4;
|
|
230
|
+
|
|
225
231
|
/** Size of virtual gamepad for touch devices in pixels
|
|
226
232
|
* @type {number}
|
|
227
233
|
* @default
|
package/src/engineTileLayer.js
CHANGED
|
@@ -108,6 +108,12 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
108
108
|
const tileLayer = new TileCollisionLayer(vec2(), levelSize, tileInfo, layerRenderOrder);
|
|
109
109
|
tileLayers[layerIndex] = tileLayer;
|
|
110
110
|
|
|
111
|
+
// apply layer color
|
|
112
|
+
const layerColor = dataLayer.color || WHITE;
|
|
113
|
+
if (dataLayer.tintcolor)
|
|
114
|
+
layerColor.setHex(dataLayer.tintcolor);
|
|
115
|
+
ASSERT(isColor(layerColor), 'layer color is not a color');
|
|
116
|
+
|
|
111
117
|
for (let x=levelSize.x; x--;)
|
|
112
118
|
for (let y=levelSize.y; y--;)
|
|
113
119
|
{
|
|
@@ -115,7 +121,7 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
115
121
|
const data = dataLayer.data[x + y*levelSize.x];
|
|
116
122
|
if (data)
|
|
117
123
|
{
|
|
118
|
-
const layerData = new TileLayerData(data-1);
|
|
124
|
+
const layerData = new TileLayerData(data-1, 0, false, layerColor);
|
|
119
125
|
tileLayer.setData(pos, layerData);
|
|
120
126
|
|
|
121
127
|
// set collision for top layer
|