Add touch controls for mobile support
This commit is contained in:
1 parent
de29ea9c05
commit
41d1a84c76
8 files changed
+332
-24
No files matched your search
@@ -552,15 +552,19 @@ export default class BattleScene extends Phaser.Scene {
|
||||
[Button.SPEED_UP]: [keyCodes.PLUS],
|
||||
[Button.SLOW_DOWN]: [keyCodes.MINUS]
|
||||
};
|
||||
const mobileKeyConfig = {};
|
||||
this.buttonKeys = [];
|
||||
for (let b of Utils.getEnumValues(Button)) {
|
||||
const keys: Phaser.Input.Keyboard.Key[] = [];
|
||||
if (keyConfig.hasOwnProperty(b)) {
|
||||
for (let k of keyConfig[b])
|
||||
keys.push(this.input.keyboard.addKey(k));
|
||||
mobileKeyConfig[Button[b]] = keys[0];
|
||||
}
|
||||
this.buttonKeys[b] = keys;
|
||||
}
|
||||
|
||||
initTouchControls(mobileKeyConfig);
|
||||
}
|
||||
|
||||
getParty(): PlayerPokemon[] {
|
||||
|
||||
@@ -243,6 +243,8 @@ export class GameData {
|
||||
}
|
||||
|
||||
private loadSettings(): boolean {
|
||||
Object.values(Setting).map(setting => setting as Setting).forEach(setting => setSetting(this.scene, setting, settingDefaults[setting]));
|
||||
|
||||
if (!localStorage.hasOwnProperty('settings'))
|
||||
return false;
|
||||
|
||||
|
||||
+11
-3
@@ -7,7 +7,8 @@ export enum Setting {
|
||||
BGM_Volume = "BGM_VOLUME",
|
||||
SE_Volume = "SE_VOLUME",
|
||||
Show_Stats_on_Level_Up = "SHOW_LEVEL_UP_STATS",
|
||||
Window_Type = "WINDOW_TYPE"
|
||||
Window_Type = "WINDOW_TYPE",
|
||||
Touch_Controls = "TOUCH_CONTROLS"
|
||||
}
|
||||
|
||||
export interface SettingOptions {
|
||||
@@ -24,7 +25,8 @@ export const settingOptions: SettingOptions = {
|
||||
[Setting.BGM_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
||||
[Setting.SE_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'),
|
||||
[Setting.Show_Stats_on_Level_Up]: [ 'Off', 'On' ],
|
||||
[Setting.Window_Type]: new Array(4).fill(null).map((_, i) => (i + 1).toString())
|
||||
[Setting.Window_Type]: new Array(4).fill(null).map((_, i) => (i + 1).toString()),
|
||||
[Setting.Touch_Controls]: [ 'Auto', 'Disabled' ]
|
||||
};
|
||||
|
||||
export const settingDefaults: SettingDefaults = {
|
||||
@@ -33,7 +35,8 @@ export const settingDefaults: SettingDefaults = {
|
||||
[Setting.BGM_Volume]: 10,
|
||||
[Setting.SE_Volume]: 10,
|
||||
[Setting.Show_Stats_on_Level_Up]: 1,
|
||||
[Setting.Window_Type]: 1
|
||||
[Setting.Window_Type]: 1,
|
||||
[Setting.Touch_Controls]: 0
|
||||
};
|
||||
|
||||
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
|
||||
@@ -59,6 +62,11 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
|
||||
case Setting.Window_Type:
|
||||
updateWindowType(scene, parseInt(settingOptions[setting][value]));
|
||||
break;
|
||||
case Setting.Touch_Controls:
|
||||
const touchControls = document.getElementById('touchControls');
|
||||
if (touchControls)
|
||||
touchControls.classList.toggle('visible', settingOptions[setting][value] !== 'Disabled' && hasTouchscreen());
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
const keys = new Map();
|
||||
const keysDown = new Map();
|
||||
let lastTouchedId;
|
||||
|
||||
function initTouchControls(buttonMap) {
|
||||
for (const button of document.querySelectorAll('[data-key]')) {
|
||||
// @ts-ignore
|
||||
bindKey(button, button.dataset.key, buttonMap);
|
||||
}
|
||||
}
|
||||
|
||||
function hasTouchscreen() {
|
||||
return window.matchMedia('(hover: none), (pointer: coarse)').matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a keyboard event on the canvas
|
||||
*
|
||||
* @param {string} eventType Type of the keyboard event
|
||||
* @param {string} button Button to simulate
|
||||
* @param {object} buttonMap Map of buttons to key objects
|
||||
*/
|
||||
function simulateKeyboardEvent(eventType, button, buttonMap) {
|
||||
const key = buttonMap[button];
|
||||
|
||||
switch (eventType) {
|
||||
case 'keydown':
|
||||
key.onDown({});
|
||||
break;
|
||||
case 'keyup':
|
||||
key.onUp({});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a keyboard input from 'keydown' to 'keyup'
|
||||
*
|
||||
* @param {string} key Key to simulate
|
||||
* @param {object} buttonMap Map of buttons to key objects
|
||||
*/
|
||||
function simulateKeyboardInput(key, buttonMap) {
|
||||
simulateKeyboardEvent('keydown', key, buttonMap);
|
||||
window.setTimeout(() => {
|
||||
simulateKeyboardEvent('keyup', key, buttonMap);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind a node by a specific key to simulate on touch
|
||||
*
|
||||
* @param {*} node The node to bind a key to
|
||||
* @param {string} key Key to simulate
|
||||
* @param {object} buttonMap Map of buttons to key objects
|
||||
*/
|
||||
function bindKey(node, key, buttonMap) {
|
||||
keys.set(node.id, key);
|
||||
|
||||
node.addEventListener('touchstart', event => {
|
||||
event.preventDefault();
|
||||
simulateKeyboardEvent('keydown', key, buttonMap);
|
||||
keysDown.set(event.target.id, node.id);
|
||||
node.classList.add('active');
|
||||
});
|
||||
|
||||
node.addEventListener('touchend', event => {
|
||||
event.preventDefault();
|
||||
|
||||
const pressedKey = keysDown.get(event.target.id);
|
||||
if (pressedKey && keys.has(pressedKey)) {
|
||||
const key = keys.get(pressedKey);
|
||||
simulateKeyboardEvent('keyup', key, buttonMap);
|
||||
}
|
||||
|
||||
keysDown.delete(event.target.id);
|
||||
node.classList.remove('active');
|
||||
|
||||
if (lastTouchedId) {
|
||||
document.getElementById(lastTouchedId).classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Inspired by https://github.com/pulsejet/mkxp-web/blob/262a2254b684567311c9f0e135ee29f6e8c3613e/extra/js/dpad.js
|
||||
node.addEventListener('touchmove', event => {
|
||||
const { target, clientX, clientY } = event.changedTouches[0];
|
||||
const origTargetId = keysDown.get(target.id);
|
||||
const nextTargetId = document.elementFromPoint(clientX, clientY).id;
|
||||
if (origTargetId === nextTargetId)
|
||||
return;
|
||||
|
||||
if (origTargetId) {
|
||||
const key = keys.get(origTargetId);
|
||||
simulateKeyboardEvent('keyup', key, buttonMap);
|
||||
keysDown.delete(target.id);
|
||||
document.getElementById(origTargetId).classList.remove('active');
|
||||
}
|
||||
|
||||
if (keys.has(nextTargetId)) {
|
||||
const key = keys.get(nextTargetId);
|
||||
simulateKeyboardEvent('keydown', key, buttonMap);
|
||||
keysDown.set(target.id, nextTargetId);
|
||||
lastTouchedId = nextTargetId;
|
||||
document.getElementById(nextTargetId).classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -280,6 +280,9 @@ export default class UI extends Phaser.GameObjects.Container {
|
||||
if (chainMode && this.mode && !clear)
|
||||
this.modeChain.push(this.mode);
|
||||
this.mode = mode;
|
||||
const touchControls = document.getElementById('touchControls');
|
||||
if (touchControls)
|
||||
touchControls.dataset.uiMode = Mode[mode];
|
||||
this.getHandler().show(args);
|
||||
}
|
||||
resolve();
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
|
||||
const windowTypeControlColors = {
|
||||
0: [ '#706880', '#8888c8', '#484868' ],
|
||||
1: [ '#d04028', '#e0a028', '#902008' ],
|
||||
2: [ '#48b840', '#88d880', '#089040' ],
|
||||
3: [ '#2068d0', '#80b0e0', '#104888' ]
|
||||
};
|
||||
|
||||
export function addWindow(scene: BattleScene, x: number, y: number, width: number, height: number, mergeMaskTop?: boolean, mergeMaskLeft?: boolean, maskOffsetX?: number, maskOffsetY?: number): Phaser.GameObjects.NineSlice {
|
||||
const window = scene.add.nineslice(x, y, `window_${scene.windowType}`, null, width, height, 8, 8, 8, 8);
|
||||
window.setOrigin(0, 0);
|
||||
@@ -36,6 +43,9 @@ export function updateWindowType(scene: BattleScene, windowTypeIndex: integer):
|
||||
|
||||
scene.windowType = windowTypeIndex;
|
||||
|
||||
const rootStyle = document.documentElement.style;
|
||||
[ 'base', 'light', 'dark' ].map((k, i) => rootStyle.setProperty(`--color-${k}`, windowTypeControlColors[windowTypeIndex - 1][i]));
|
||||
|
||||
const windowKey = `window_${windowTypeIndex}`;
|
||||
|
||||
for (let window of windowObjects)
|
||||
|
||||
Reference in new issue
Block a user