littlejsengine 1.14.8 → 1.14.10
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.esm.js +70 -29
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +70 -29
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +60 -26
- package/examples/platformer/gameEffects.js +6 -2
- package/examples/platformer/gameLevel.js +1 -7
- package/examples/shorts/blending.js +1 -1
- package/examples/shorts/box2dCar.js +2 -1
- package/examples/shorts/particles.js +10 -10
- package/examples/shorts/pongGame.js +0 -1
- package/examples/shorts/uiSystem.js +0 -4
- package/package.json +1 -1
- package/plugins/uiSystem.js +3 -2
- package/src/engine.js +1 -1
- package/src/engineDebug.js +10 -3
- package/src/engineInput.js +49 -22
- package/src/engineSettings.js +6 -0
package/dist/littlejs.release.js
CHANGED
|
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
|
|
|
33
33
|
* @type {string}
|
|
34
34
|
* @default
|
|
35
35
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.14.
|
|
36
|
+
const engineVersion = '1.14.10';
|
|
37
37
|
|
|
38
38
|
/** Frames per second to update
|
|
39
39
|
* @type {number}
|
|
@@ -1932,6 +1932,12 @@ let touchGamepadEnable = false;
|
|
|
1932
1932
|
* @memberof Settings */
|
|
1933
1933
|
let touchGamepadAnalog = true;
|
|
1934
1934
|
|
|
1935
|
+
/** Number of buttons on touch gamepad
|
|
1936
|
+
* @type {number}
|
|
1937
|
+
* @default
|
|
1938
|
+
* @memberof Settings */
|
|
1939
|
+
let touchGamepadButtonCount = 4;
|
|
1940
|
+
|
|
1935
1941
|
/** Size of virtual gamepad for touch devices in pixels
|
|
1936
1942
|
* @type {number}
|
|
1937
1943
|
* @default
|
|
@@ -3962,7 +3968,7 @@ function inputInit()
|
|
|
3962
3968
|
function onMouseLeave()
|
|
3963
3969
|
{
|
|
3964
3970
|
// set mouse position and delta when leaving canvas
|
|
3965
|
-
mousePosScreen = vec2(
|
|
3971
|
+
mousePosScreen = vec2(-1);
|
|
3966
3972
|
mouseDeltaScreen = vec2(0);
|
|
3967
3973
|
}
|
|
3968
3974
|
}
|
|
@@ -4017,10 +4023,12 @@ function gamepadsUpdate()
|
|
|
4017
4023
|
const data = inputData[1] || (inputData[1] = []);
|
|
4018
4024
|
for (let i=10; i--;)
|
|
4019
4025
|
{
|
|
4020
|
-
const
|
|
4021
|
-
|
|
4022
|
-
data[j] = touchGamepadButtons[i] ? wasDown ? 1 : 3 : wasDown ? 4 : 0;
|
|
4026
|
+
const wasDown = gamepadIsDown(i,0);
|
|
4027
|
+
data[i] = touchGamepadButtons[i] ? wasDown ? 1 : 3 : wasDown ? 4 : 0;
|
|
4023
4028
|
}
|
|
4029
|
+
|
|
4030
|
+
// disable normal gamepads when touch gamepad is active
|
|
4031
|
+
return;
|
|
4024
4032
|
}
|
|
4025
4033
|
|
|
4026
4034
|
// return if gamepads are disabled or not supported
|
|
@@ -4095,6 +4103,15 @@ const isTouchDevice = !headlessMode && window.ontouchstart !== undefined;
|
|
|
4095
4103
|
// touch gamepad internal variables
|
|
4096
4104
|
let touchGamepadTimer = new Timer, touchGamepadButtons = [], touchGamepadStick = vec2();
|
|
4097
4105
|
|
|
4106
|
+
function touchGamepadButtonCenter()
|
|
4107
|
+
{
|
|
4108
|
+
// draw right face buttons
|
|
4109
|
+
let center = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
4110
|
+
if (touchGamepadButtonCount <= 2)
|
|
4111
|
+
center.x += touchGamepadSize/2;
|
|
4112
|
+
return center;
|
|
4113
|
+
}
|
|
4114
|
+
|
|
4098
4115
|
// enable touch input mouse passthrough
|
|
4099
4116
|
function touchInputInit()
|
|
4100
4117
|
{
|
|
@@ -4142,8 +4159,8 @@ function touchInputInit()
|
|
|
4142
4159
|
// set was touching
|
|
4143
4160
|
wasTouching = touching;
|
|
4144
4161
|
|
|
4145
|
-
// prevent default handling like copy
|
|
4146
|
-
if (inputPreventDefault && document.hasFocus()
|
|
4162
|
+
// prevent default handling like copy, magnifier lens, and scrolling
|
|
4163
|
+
if (inputPreventDefault && document.hasFocus() && e.cancelable)
|
|
4147
4164
|
e.preventDefault();
|
|
4148
4165
|
|
|
4149
4166
|
// must return true so the document will get focus
|
|
@@ -4172,25 +4189,36 @@ function touchInputInit()
|
|
|
4172
4189
|
|
|
4173
4190
|
// get center of left and right sides
|
|
4174
4191
|
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
4175
|
-
const buttonCenter =
|
|
4192
|
+
const buttonCenter = touchGamepadButtonCenter();
|
|
4176
4193
|
const startCenter = mainCanvasSize.scale(.5);
|
|
4177
4194
|
|
|
4178
4195
|
// check each touch point
|
|
4179
4196
|
for (const touch of e.touches)
|
|
4180
4197
|
{
|
|
4181
4198
|
const touchPos = mouseEventToScreen(vec2(touch.clientX, touch.clientY));
|
|
4182
|
-
if (
|
|
4199
|
+
if (stickCenter.distance(touchPos) < touchGamepadSize)
|
|
4183
4200
|
{
|
|
4184
4201
|
// virtual analog stick
|
|
4185
4202
|
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
4186
4203
|
}
|
|
4187
|
-
else if (
|
|
4204
|
+
else if (buttonCenter.distance(touchPos) < touchGamepadSize)
|
|
4188
4205
|
{
|
|
4189
4206
|
// virtual face buttons
|
|
4190
|
-
|
|
4191
|
-
|
|
4207
|
+
let button = buttonCenter.subtract(touchPos).direction();
|
|
4208
|
+
button = mod(button+2, 4);
|
|
4209
|
+
if (touchGamepadButtonCount === 1)
|
|
4210
|
+
button = 0;
|
|
4211
|
+
else if (touchGamepadButtonCount === 2)
|
|
4212
|
+
{
|
|
4213
|
+
const delta = buttonCenter.subtract(touchPos);
|
|
4214
|
+
button = -delta.x < delta.y ? 1 : 0;
|
|
4215
|
+
}
|
|
4216
|
+
// fix button locations (swap 2 and 3 to match gamepad layout)
|
|
4217
|
+
button = button === 3 ? 2 : button === 2 ? 3 : button;
|
|
4218
|
+
if (button < touchGamepadButtonCount)
|
|
4219
|
+
touchGamepadButtons[button] = 1;
|
|
4192
4220
|
}
|
|
4193
|
-
else if (
|
|
4221
|
+
else if (startCenter.distance(touchPos) < touchGamepadSize && !wasTouching)
|
|
4194
4222
|
{
|
|
4195
4223
|
// virtual start button in center
|
|
4196
4224
|
touchGamepadButtons[9] = 1;
|
|
@@ -4221,11 +4249,10 @@ function touchGamepadRender()
|
|
|
4221
4249
|
// draw left analog stick
|
|
4222
4250
|
context.fillStyle = touchGamepadStick.lengthSquared() > 0 ? '#fff' : '#000';
|
|
4223
4251
|
context.beginPath();
|
|
4224
|
-
|
|
4225
|
-
const leftCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
4252
|
+
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
4226
4253
|
if (touchGamepadAnalog) // draw circle shaped gamepad
|
|
4227
4254
|
{
|
|
4228
|
-
context.arc(
|
|
4255
|
+
context.arc(stickCenter.x, stickCenter.y, touchGamepadSize/2, 0, 9);
|
|
4229
4256
|
context.fill();
|
|
4230
4257
|
context.stroke();
|
|
4231
4258
|
}
|
|
@@ -4234,21 +4261,27 @@ function touchGamepadRender()
|
|
|
4234
4261
|
for (let i=10; i--;)
|
|
4235
4262
|
{
|
|
4236
4263
|
const angle = i*PI/4;
|
|
4237
|
-
context.arc(
|
|
4238
|
-
i%2 && context.arc(
|
|
4264
|
+
context.arc(stickCenter.x, stickCenter.y,touchGamepadSize*.6, angle + PI/8, angle + PI/8);
|
|
4265
|
+
i%2 && context.arc(stickCenter.x, stickCenter.y, touchGamepadSize*.33, angle, angle);
|
|
4239
4266
|
i===1 && context.fill();
|
|
4240
4267
|
}
|
|
4241
4268
|
context.stroke();
|
|
4242
4269
|
}
|
|
4243
4270
|
|
|
4244
4271
|
// draw right face buttons
|
|
4245
|
-
const
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4272
|
+
const buttonCenter = touchGamepadButtonCenter();
|
|
4273
|
+
const buttonSize = touchGamepadButtonCount > 1 ? touchGamepadSize/4 : touchGamepadSize/2;
|
|
4274
|
+
for (let i=0; i<touchGamepadButtonCount; i++)
|
|
4275
|
+
{
|
|
4276
|
+
let j = mod(i-1, 4);
|
|
4277
|
+
let button = touchGamepadButtonCount > 2 ?
|
|
4278
|
+
j : min(j, touchGamepadButtonCount-1);
|
|
4279
|
+
// fix button locations (swap 2 and 3 to match gamepad layout)
|
|
4280
|
+
button = button === 3 ? 2 : button === 2 ? 3 : button;
|
|
4281
|
+
const pos = buttonCenter.add(vec2().setDirection(j, touchGamepadSize/2));
|
|
4282
|
+
context.fillStyle = touchGamepadButtons[button] ? '#fff' : '#000';
|
|
4250
4283
|
context.beginPath();
|
|
4251
|
-
context.arc(pos.x, pos.y,
|
|
4284
|
+
context.arc(pos.x, pos.y, buttonSize, 0,9);
|
|
4252
4285
|
context.fill();
|
|
4253
4286
|
context.stroke();
|
|
4254
4287
|
}
|
|
@@ -7604,7 +7637,7 @@ class UIObject
|
|
|
7604
7637
|
const mouseDown = mouseIsDown(0);
|
|
7605
7638
|
const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
|
|
7606
7639
|
if (!uiSystem.hoverObject)
|
|
7607
|
-
if (mousePress || !mouseDown
|
|
7640
|
+
if (mousePress || isActive || (!mouseDown && !isTouchDevice))
|
|
7608
7641
|
{
|
|
7609
7642
|
const size = this.size.add(vec2(isTouchDevice && this.extraTouchSize || 0));
|
|
7610
7643
|
if (isOverlapping(this.pos, size, mousePosScreen))
|
|
@@ -7636,7 +7669,8 @@ class UIObject
|
|
|
7636
7669
|
}
|
|
7637
7670
|
}
|
|
7638
7671
|
}
|
|
7639
|
-
if (isActive
|
|
7672
|
+
if (isActive)
|
|
7673
|
+
if (!mouseDown || (this.dragActivate && !this.isHoverObject()))
|
|
7640
7674
|
{
|
|
7641
7675
|
this.onRelease();
|
|
7642
7676
|
if (this.soundRelease)
|
|
@@ -36,7 +36,11 @@ export const persistentParticleDestroyCallback = (particle)=>
|
|
|
36
36
|
// copy particle to tile layer on death
|
|
37
37
|
LJS.ASSERT(!particle.tileInfo, 'quick draw to tile layer uses canvas 2d so must be untextured');
|
|
38
38
|
if (particle.groundObject)
|
|
39
|
+
{
|
|
39
40
|
GameLevel.foregroundTileLayer.drawTile(particle.pos, particle.size, particle.tileInfo, particle.color, particle.angle, particle.mirror);
|
|
41
|
+
// update WebGL texture
|
|
42
|
+
GameLevel.foregroundTileLayer.useWebGL();
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
export function makeBlood(pos, amount) { makeDebris(pos, hsl(0,1,.5), amount, .1, 0); }
|
|
@@ -83,7 +87,7 @@ export function explosion(pos, radius=3)
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
// update WebGL texture
|
|
86
|
-
GameLevel.
|
|
90
|
+
GameLevel.foregroundTileLayer.useWebGL();
|
|
87
91
|
|
|
88
92
|
// kill/push objects
|
|
89
93
|
LJS.engineObjectsCallback(pos, radius*3, (o)=>
|
|
@@ -159,7 +163,7 @@ export function destroyTile(pos, makeSound = 1, cleanup = 1)
|
|
|
159
163
|
for (let i=-1;i<=1;++i)
|
|
160
164
|
for (let j=-1;j<=1;++j)
|
|
161
165
|
GameLevel.decorateTile(pos.add(vec2(i,j)));
|
|
162
|
-
|
|
166
|
+
layer.useWebGL();
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
return true;
|
|
@@ -14,7 +14,6 @@ import * as GameEffects from './gameEffects.js';
|
|
|
14
14
|
import * as Game from './game.js';
|
|
15
15
|
const {vec2, hsl, tile} = LJS;
|
|
16
16
|
|
|
17
|
-
export const useWebGLTileLayers = true;
|
|
18
17
|
export const tileType_ladder = -1;
|
|
19
18
|
export const tileType_empty = 0;
|
|
20
19
|
export const tileType_solid = 1;
|
|
@@ -138,7 +137,7 @@ function loadLevelData()
|
|
|
138
137
|
for (pos.x=levelSize.x; pos.x--;)
|
|
139
138
|
for (pos.y=levelSize.y; pos.y--;)
|
|
140
139
|
decorateTile(pos, layer);
|
|
141
|
-
|
|
140
|
+
tileLayers[layer].useWebGL();
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
|
|
@@ -204,9 +203,4 @@ export function getCameraTarget()
|
|
|
204
203
|
// camera is above player
|
|
205
204
|
const offset = 100/LJS.cameraScale*LJS.percent(LJS.mainCanvasSize.y, 300, 600);
|
|
206
205
|
return Game.player.pos.add(vec2(0, offset));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function updateWebGL(layer)
|
|
210
|
-
{
|
|
211
|
-
layer.useWebGL(useWebGLTileLayers);
|
|
212
206
|
}
|
|
@@ -38,7 +38,8 @@ class CarObject extends Box2dObject
|
|
|
38
38
|
|
|
39
39
|
// car controls - use mouse, arrow keys, or A/D to drive
|
|
40
40
|
const maxSpeed = 40;
|
|
41
|
-
const input =
|
|
41
|
+
const input = mouseIsDown(0) ? 1 :
|
|
42
|
+
mouseIsDown(2) ? -1 : keyDirection().x ;
|
|
42
43
|
let s = this.wheels[0].motorJoint.getMotorSpeed();
|
|
43
44
|
s = input ? clamp(s - input, -maxSpeed, maxSpeed) : 0;
|
|
44
45
|
this.wheels[0].motorJoint.setMotorSpeed(s);
|
|
@@ -9,20 +9,20 @@ function gameInit()
|
|
|
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
|
}
|
package/package.json
CHANGED
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))
|
|
@@ -316,7 +316,8 @@ class UIObject
|
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
|
-
if (isActive
|
|
319
|
+
if (isActive)
|
|
320
|
+
if (!mouseDown || (this.dragActivate && !this.isHoverObject()))
|
|
320
321
|
{
|
|
321
322
|
this.onRelease();
|
|
322
323
|
if (this.soundRelease)
|
package/src/engine.js
CHANGED
package/src/engineDebug.js
CHANGED
|
@@ -455,7 +455,8 @@ function debugRender()
|
|
|
455
455
|
{
|
|
456
456
|
overlayContext.fillText(`${engineName} v${engineVersion}`, x, y += h/2 );
|
|
457
457
|
overlayContext.fillText('Time: ' + formatTime(time), x, y += h);
|
|
458
|
-
overlayContext.fillText('FPS: ' + averageFPS.toFixed(1)
|
|
458
|
+
overlayContext.fillText('FPS: ' + averageFPS.toFixed(1) + (glEnable?' WebGL':' Canvas2D'),
|
|
459
|
+
x, y += h);
|
|
459
460
|
overlayContext.fillText('Objects: ' + engineObjects.length, x, y += h);
|
|
460
461
|
overlayContext.fillText('Draw Count: ' + drawCount, x, y += h);
|
|
461
462
|
overlayContext.fillText('---------', x, y += h);
|
|
@@ -474,12 +475,18 @@ function debugRender()
|
|
|
474
475
|
overlayContext.fillText('6: Toggle Video Capture', x, y += h);
|
|
475
476
|
|
|
476
477
|
let keysPressed = '';
|
|
478
|
+
let mousePressed = '';
|
|
477
479
|
for (const i in inputData[0])
|
|
478
480
|
{
|
|
479
|
-
if (keyIsDown(i, 0))
|
|
481
|
+
if (!keyIsDown(i, 0))
|
|
482
|
+
continue;
|
|
483
|
+
if (parseInt(i) < 3)
|
|
484
|
+
mousePressed += i + ' ' ;
|
|
485
|
+
else if (keyIsDown(i, 0))
|
|
480
486
|
keysPressed += i + ' ' ;
|
|
481
487
|
}
|
|
482
|
-
|
|
488
|
+
mousePressed && overlayContext.fillText('Mouse: ' + mousePressed, x, y += h);
|
|
489
|
+
keysPressed && overlayContext.fillText('Keys: ' + keysPressed, x, y += h);
|
|
483
490
|
|
|
484
491
|
let buttonsPressed = '';
|
|
485
492
|
if (inputData[1])
|
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/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
|