removed useless control management and kept it simple for our use case, investigating to put out button_XX()

This commit is contained in:
Greenlamp 2024-05-02 23:16:34 +02:00
parent feba8ac641
commit b108cdd4bd
3 changed files with 160 additions and 722 deletions

View File

@ -60,6 +60,7 @@ import CandyBar from './ui/candy-bar';
import { Variant, variantData } from './data/variant'; import { Variant, variantData } from './data/variant';
import { Localizable } from './plugins/i18n'; import { Localizable } from './plugins/i18n';
import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE } from './overrides'; import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE } from './overrides';
import {Button, InputHandler} from "#app/inputHandler";
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
@ -204,6 +205,7 @@ export default class BattleScene extends SceneBase {
} }
async preload() { async preload() {
this.load.scenePlugin('inputHandler', InputHandler);
if (DEBUG_RNG) { if (DEBUG_RNG) {
const scene = this; const scene = this;
const originalRealInRange = Phaser.Math.RND.realInRange; const originalRealInRange = Phaser.Math.RND.realInRange;
@ -227,7 +229,7 @@ export default class BattleScene extends SceneBase {
initGameSpeed.apply(this); initGameSpeed.apply(this);
this.gameData = new GameData(this); this.gameData = new GameData(this);
this.checkInputs(); this.listenInputs();
addUiThemeOverrides(this); addUiThemeOverrides(this);
@ -246,13 +248,20 @@ export default class BattleScene extends SceneBase {
this.ui?.update(); this.ui?.update();
} }
checkInputs() { listenInputs() {
this.inputHandler.events.on('gamepad_directiondown', (event) => { this.inputHandler.events.on('input_down', (event) => {
console.log('event:', event); const actions = this.getActionsKeyDown();
}); const [inputSuccess, vibrationLength] = actions[event.button]();
this.inputHandler.events.on('gamepad_buttondown', (event) => { if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined')
console.log('event:', event); navigator.vibrate(vibrationLength);
}); }, this);
this.inputHandler.events.on('input_up', (event) => {
const actions = this.getActionsKeyUp();
if (!actions.hasOwnProperty(event.button)) return;
const [inputSuccess, vibrationLength] = actions[event.button]();
if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined')
navigator.vibrate(vibrationLength);
}, this);
} }
launchBattle() { launchBattle() {
@ -1302,19 +1311,19 @@ export default class BattleScene extends SceneBase {
button_touch() { button_touch() {
const inputSuccess = this.ui.processInput(Button.SUBMIT) || this.ui.processInput(Button.ACTION); const inputSuccess = this.ui.processInput(Button.SUBMIT) || this.ui.processInput(Button.ACTION);
this.setLastProcessedMovementTime(Button.SUBMIT); this.setLastProcessedMovementTime(Button.SUBMIT);
return inputSuccess; return [inputSuccess, 0];
} }
button_action() { button_action() {
const inputSuccess = this.ui.processInput(Button.ACTION); const inputSuccess = this.ui.processInput(Button.ACTION);
this.setLastProcessedMovementTime(Button.ACTION); this.setLastProcessedMovementTime(Button.ACTION);
return inputSuccess; return [inputSuccess, 0];
} }
button_cancel() { button_cancel() {
const inputSuccess = this.ui.processInput(Button.CANCEL); const inputSuccess = this.ui.processInput(Button.CANCEL);
this.setLastProcessedMovementTime(Button.CANCEL); this.setLastProcessedMovementTime(Button.CANCEL);
return inputSuccess; return [inputSuccess, 0];
} }
button_stats(pressed = true) { button_stats(pressed = true) {
@ -1326,6 +1335,7 @@ export default class BattleScene extends SceneBase {
for (let p of this.getField().filter(p => p?.isActive(true))) for (let p of this.getField().filter(p => p?.isActive(true)))
p.toggleStats(false); p.toggleStats(false);
} }
return [0, 0];
} }
button_menu() { button_menu() {
@ -1360,7 +1370,7 @@ export default class BattleScene extends SceneBase {
default: default:
return; return;
} }
return inputSuccess; return [inputSuccess, 0];
} }
button_cycle_option(button) { button_cycle_option(button) {
@ -1369,7 +1379,7 @@ export default class BattleScene extends SceneBase {
inputSuccess = this.ui.processInput(button); inputSuccess = this.ui.processInput(button);
this.setLastProcessedMovementTime(button); this.setLastProcessedMovementTime(button);
} }
return inputSuccess; return [inputSuccess, 0];
} }
button_speed_up() { button_speed_up() {
@ -1378,6 +1388,7 @@ export default class BattleScene extends SceneBase {
if (this.ui?.getMode() === Mode.SETTINGS) if (this.ui?.getMode() === Mode.SETTINGS)
(this.ui.getHandler() as SettingsUiHandler).show([]); (this.ui.getHandler() as SettingsUiHandler).show([]);
} }
return [0, 0];
} }
button_speed_down() { button_speed_down() {
@ -1386,71 +1397,35 @@ export default class BattleScene extends SceneBase {
if (this.ui?.getMode() === Mode.SETTINGS) if (this.ui?.getMode() === Mode.SETTINGS)
(this.ui.getHandler() as SettingsUiHandler).show([]); (this.ui.getHandler() as SettingsUiHandler).show([]);
} }
return [0, 0];
} }
key_down(button) { getActionsKeyDown() {
switch(button) { const actions = {};
case Button.UP: actions[Button.UP] = () => this.button_up();
this.button_up(); actions[Button.DOWN] = () => this.button_down();
break actions[Button.LEFT] = () => this.button_left();
case Button.DOWN: actions[Button.RIGHT] = () => this.button_right();
this.button_down(); actions[Button.SUBMIT] = () => this.button_touch();
break actions[Button.ACTION] = () => this.button_action();
case Button.LEFT: actions[Button.CANCEL] = () => this.button_cancel();
this.button_left(); actions[Button.MENU] = () => this.button_menu();
break actions[Button.STATS] = () => this.button_stats(true);
case Button.RIGHT: actions[Button.CYCLE_SHINY] = () => this.button_cycle_option(Button.CYCLE_SHINY);
this.button_right(); actions[Button.CYCLE_FORM] = () => this.button_cycle_option(Button.CYCLE_FORM);
break actions[Button.CYCLE_GENDER] = () => this.button_cycle_option(Button.CYCLE_GENDER);
case Button.SUBMIT: actions[Button.CYCLE_ABILITY] = () => this.button_cycle_option(Button.CYCLE_ABILITY);
this.button_touch(); actions[Button.CYCLE_NATURE] = () => this.button_cycle_option(Button.CYCLE_NATURE);
break actions[Button.CYCLE_VARIANT] = () => this.button_cycle_option(Button.CYCLE_VARIANT);
case Button.ACTION: actions[Button.SPEED_UP] = () => this.button_speed_up();
this.button_action(); actions[Button.SLOW_DOWN] = () => this.button_speed_down();
break return actions;
case Button.CANCEL:
this.button_cancel();
break
case Button.MENU:
this.button_menu();
break;
case Button.STATS:
this.button_stats(true);
break
case Button.CYCLE_SHINY:
this.button_cycle_option(Button.CYCLE_SHINY);
break;
case Button.CYCLE_FORM:
this.button_cycle_option(Button.CYCLE_FORM);
break;
case Button.CYCLE_GENDER:
this.button_cycle_option(Button.CYCLE_GENDER);
break;
case Button.CYCLE_ABILITY:
this.button_cycle_option(Button.CYCLE_ABILITY);
break;
case Button.CYCLE_NATURE:
this.button_cycle_option(Button.CYCLE_NATURE);
break;
case Button.CYCLE_VARIANT:
this.button_cycle_option(Button.CYCLE_VARIANT);
break;
case Button.SPEED_UP:
this.button_speed_up();
break
case Button.SLOW_DOWN:
this.button_speed_down();
break
}
} }
key_up(button) { getActionsKeyUp() {
switch(button) { const actions = {};
case Button.STATS: actions[Button.STATS] = () => this.button_stats(false);
this.button_stats(false); return actions;
break
}
} }

View File

@ -28,80 +28,58 @@ export enum Button {
} }
export class InputHandler extends Phaser.Plugins.ScenePlugin { export class InputHandler extends Phaser.Plugins.ScenePlugin {
game: Phaser.Game; private game: Phaser.Game;
private buttonKeys;
private gamepads;
private scene;
private isButtonPressing;
constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) {
super(scene, pluginManager, pluginKey); super(scene, pluginManager, pluginKey);
this.game = pluginManager.game; this.game = pluginManager.game;
this.scene = scene; this.scene = scene;
// Keys object to store Phaser key objects. We'll check these during update // Keys object to store Phaser key objects. We'll check these during update
this.keys = {}; this.buttonKeys = {};
this.players = [];
this.gamepads = []; this.gamepads = [];
this.isButtonPressing = false;
this.dpadMappings = {
'UP': 12,
'DOWN': 13,
'LEFT': 14,
'RIGHT': 15
};
} }
boot() { boot() {
this.eventEmitter = this.systems.events; this.eventEmitter = this.systems.events;
this.events = new Phaser.Events.EventEmitter(); this.events = new Phaser.Events.EventEmitter();
this.game.events.on(Phaser.Core.Events.PRE_STEP, this.preupdate, this);
// Handle the game losing focus
this.game.events.on(Phaser.Core.Events.BLUR, () => {
this.loseFocus()
});
if (typeof this.systems.input.gamepad !== 'undefined') { if (typeof this.systems.input.gamepad !== 'undefined') {
this.systems.input.gamepad.on('connected', function (thisGamepad) { this.systems.input.gamepad.on('connected', function (thisGamepad) {
this.refreshGamepads(); this.refreshGamepads();
this.setupGamepad(thisGamepad); this.setupGamepad(thisGamepad);
}, this); }, this);
}
// Check to see if the gamepad has already been setup by the browser // Check to see if the gamepad has already been setup by the browser
this.systems.input.gamepad.refreshPads(); this.systems.input.gamepad.refreshPads();
if (this.systems.input.gamepad.total) { if (this.systems.input.gamepad.total) {
this.refreshGamepads(); this.refreshGamepads();
for (const thisGamepad of this.gamepads) { for (const thisGamepad of this.gamepads) {
console.log('thisGamepad', thisGamepad);
this.systems.input.gamepad.emit('connected', thisGamepad); this.systems.input.gamepad.emit('connected', thisGamepad);
} }
} }
this.systems.input.gamepad.on('down', this.gamepadButtonDown, this); this.systems.input.gamepad.on('down', this.gamepadButtonDown, this);
this.systems.input.gamepad.on('up', this.gamepadButtonUp, this); this.systems.input.gamepad.on('up', this.gamepadButtonUp, this);
}
// Keyboard // Keyboard
// this.systems.input.keyboard.on('keydown', this.keyboardKeyDown, this); this.setupKeyboardControls();
// this.systems.input.keyboard.on('keyup', this.keyboardKeyUp, this);
console.log('==[input handler initialized');
} }
setupGamepad(thisGamepad) { setupGamepad(thisGamepad) {
console.log('gamepad on');
this.eventEmitter.emit('inputHandler', {
device: 'gamepad',
id: thisGamepad.id,
action: 'Connected'
});
this.events.emit('gamepad_connected', thisGamepad);
if (typeof this.players[thisGamepad.index] === 'undefined') {
this.addPlayer();
}
let gamepadID = thisGamepad.id.toLowerCase(); let gamepadID = thisGamepad.id.toLowerCase();
let mappedPad = this.mapGamepad(gamepadID); const mappedPad = this.mapGamepad(gamepadID);
this.players[thisGamepad.index].gamepadMapping = mappedPad.gamepadMapping; this.player = {
this.players[thisGamepad.index].interaction_mapped.gamepadType = mappedPad.padType; 'mapping': mappedPad.gamepadMapping,
for (let thisButton in this.players[thisGamepad.index].gamepadMapping) {
this.players[thisGamepad.index].buttons_mapped[thisButton] = 0;
} }
} }
refreshGamepads() { refreshGamepads() {
// Sometimes, gamepads are undefined. For some reason. // Sometimes, gamepads are undefined. For some reason.
this.gamepads = this.systems.input.gamepad.gamepads.filter(function (el) { this.gamepads = this.systems.input.gamepad.gamepads.filter(function (el) {
@ -110,528 +88,109 @@ export class InputHandler extends Phaser.Plugins.ScenePlugin {
for (const [index, thisGamepad] of this.gamepads.entries()) { for (const [index, thisGamepad] of this.gamepads.entries()) {
thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier
/**
* Some cheap gamepads use the first axis as a dpad, in which case we won't have the dpad buttons 12-15
*/
thisGamepad.fakedpad = thisGamepad.buttons.length < 15;
} }
} }
preupdate() { getActionGamepadMapping() {
// this.setupControls(); const gamepadMapping = {};
// this.checkInputGamepad(); gamepadMapping[this.player.mapping.LC_N] = Button.UP;
// this.checkInputKeyboard(); gamepadMapping[this.player.mapping.LC_S] = Button.DOWN;
gamepadMapping[this.player.mapping.LC_W] = Button.LEFT;
gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT;
gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT;
gamepadMapping[this.player.mapping.RC_S] = Button.ACTION;
gamepadMapping[this.player.mapping.RC_E] = Button.CANCEL;
gamepadMapping[this.player.mapping.SELECT] = Button.STATS;
gamepadMapping[this.player.mapping.START] = Button.MENU;
gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY;
gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM;
gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER;
gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY;
gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE;
gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT;
gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP;
gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN;
return gamepadMapping;
} }
/**
* Function to run when the game loses focus
* We want to fake releasing the buttons here, so that they're not stuck down without an off event when focus returns to the game
*/
loseFocus() {
// Loop through defined keys and reset them
for (let thisKey in this.keys) {
this.keys[thisKey].reset();
}
}
/**
* Add a new player object to the players array
* @param {number} index Player index - if a player object at this index already exists, it will be returned instead of creating a new player object
* @param {number} numberOfButtons The number of buttons to assign to the player object. Defaults to 16. Fewer than 16 is not recommended, as gamepad DPads typically map to buttons 12-15
*/
addPlayer(index= 0, numberOfButtons=16) {
if (typeof this.players[index] !== 'undefined') {
return this.players[index];
} else {
// Set up player object
let newPlayer = this.setupControls(numberOfButtons);
// Add helper functions to the player object
this.addPlayerHelperFunctions(newPlayer);
// Push new player to players array
this.players.push(newPlayer);
this.players[this.players.length - 1].index = this.players.length - 1;
return this.players[this.players.length - 1];
}
}
/**
* Add helper functions to the player object
* @param {*} player
*/
addPlayerHelperFunctions(player) {
/**
* Pass a button name, or an array of button names to check if any were pressed in this update step.
* This will only fire once per button press. If you need to check for a button being held down, use isDown instead.
* Returns the name of the matched button(s), in case you need it.
*/
player.interaction.isPressed = (button) => {
button = (typeof button === 'string') ? Array(button) : button;
let matchedButtons = button.filter(x => player.interaction.pressed.includes(x))
return matchedButtons.length ? matchedButtons : false;
}
/**
* Pass a button name, or an array of button names to check if any are currently pressed in this update step.
* This differs from the isPressed function in that it will return true if the button is currently pressed, even if it was pressed in a previous update step.
* Returns the name of the matched button(s), in case you need it.
*/
player.interaction.isDown = (button) => {
button = (typeof button === 'string') ? Array(button) : button;
let matchedButtons = button.filter(x => player.buttons[x])
let matchedDirections = button.filter(x => player.direction[x])
let matchedAll = [...matchedButtons, ...matchedDirections];
return matchedAll.length ? matchedAll : false;
}
/**
* Pass a button name, or an array of button names to check if any are currently pressed in this update step.
* Similar to Phaser's keyboard plugin, the checkDown function can accept a 'duration' parameter, and will only register a press once every X milliseconds.
* Returns the name of the matched button(s)
*
* @param {string|array} button Array of buttons to check
* @param {number} duration The duration which must have elapsed before this button is considered as being down.
* @param {boolean} includeFirst - When true, the initial press of the button will be included in the results. Defaults to false.
*/
player.interaction.checkDown = (button, duration, includeFirst) => {
if (includeFirst === undefined) { includeFirst = false; }
if (duration === undefined) { duration = 0; }
let matchedButtons = [];
let downButtons = player.interaction.isDown(button)
console.log('downButtons:', downButtons);
if (downButtons.length) {
for (let thisButton of downButtons) {
if (typeof player.timers[thisButton]._tick === 'undefined') {
player.timers[thisButton]._tick = 0;
if (includeFirst) {
matchedButtons.push(thisButton);
}
}
let t = Phaser.Math.Snap.Floor(this.scene.sys.time.now - player.timers[thisButton].pressed, duration);
if (t > player.timers[thisButton]._tick) {
this.game.events.once(Phaser.Core.Events.POST_STEP, ()=>{
player.timers[thisButton]._tick = t;
});
matchedButtons.push(thisButton);
}
}
}
return matchedButtons.length ? matchedButtons : false;
}
/**
* Mapped version of the checkDown version - resolves mapped button names and calls the checkDown function
*/
player.interaction_mapped.checkDown = (button, duration, includeFirst) => {
if (includeFirst === undefined) { includeFirst = false; }
let unmappedButtons = [];
// Resolve the unmapped button names to a new array
for (let thisButton of button) {
let unmappedButton = this.getUnmappedButton(player, thisButton);
if (unmappedButton) {
unmappedButtons.push(unmappedButton)
}
}
let downButtons = player.interaction.checkDown(unmappedButtons, duration, includeFirst);
return downButtons.length ? downButtons.map(x => this.getMappedButton(player, x)) : false;
}
/**
* The previous functions are specific to the interaction and interaction_mapped definition of buttons.
* In general you would pick a definition scheme and query that object (interaction or interaction_mapped), just for ease though, we'll add some functions that accept either type of convention
*/
/**
* Pass a button name, or an array of button names to check if any were pressed in this update step.
* This will only fire once per button press. If you need to check for a button being held down, use isDown instead.
* Returns the name of the matched button(s), in case you need it.
*/
player.isPressed = (button) => {
let interaction = player.interaction.isPressed(button) || [];
let interaction_mapped = player.interaction_mapped.isPressed(button) || [];
let matchedButtons = [...interaction, ...interaction_mapped];
return matchedButtons.length ? matchedButtons : false
}
/**
* Pass a button name, or an array of button names to check if any are currently pressed in this update step.
* This differs from the isPressed function in that it will return true if the button is currently pressed, even if it was pressed in a previous update step.
* Returns the name of the button(s), in case you need it.
*/
player.isDown = (button) => {
let interaction = player.interaction.isDown(button) || [];
let interaction_mapped = player.interaction_mapped.isDown(button) || [];
let matchedButtons = [...interaction, ...interaction_mapped];
return matchedButtons.length ? matchedButtons : false
}
/**
* Pass a button name, or an array of button names to check if any were released in this update step.
* Returns the name of the matched button(s), in case you need it.
*/
player.isReleased = (button) => {
let interaction = player.interaction.isReleased(button) || [];
let interaction_mapped = player.interaction_mapped.isReleased(button) || [];
let matchedButtons = [...interaction, ...interaction_mapped];
return matchedButtons.length ? matchedButtons : false
}
/**
* Pass a button name, or an array of button names to check if any are currently pressed in this update step.
* Similar to Phaser's keyboard plugin, the checkDown function can accept a 'duration' parameter, and will only register a press once every X milliseconds.
* Returns the name of the matched button(s)
*
* @param {string|array} button Array of buttons to check
* @param {number} - The duration which must have elapsed before this button is considered as being down.
*/
player.checkDown = (button, duration, includeFirst) => {
if (includeFirst === undefined) { includeFirst = false; }
let interaction = player.interaction.checkDown(button, duration, includeFirst) || [];
let interaction_mapped = player.interaction_mapped.checkDown(button, duration, includeFirst) || [];
let matchedButtons = [...interaction, ...interaction_mapped];
return matchedButtons.length ? matchedButtons : false
}
player.setDevice = (device) => {
if (player.interaction.device != device) {
this.eventEmitter.emit('inputHandler', { device: device, player: player.index, action: 'Device Changed' });
this.events.emit('device_changed', { player: player.index, device: device });
}
player.interaction.device = device;
return this;
}
return this;
}
/**
* Returns a struct to hold input control information
* Set up a struct for each player in the game
* Direction and Buttons contain the input from the devices
* The keys struct contains arrays of keyboard characters that will trigger the action
*/
setupControls(numberOfButtons = 16) {
let controls = this.getBaseControls();
// Add buttons
for (let i = 0; i <= numberOfButtons; i++) {
controls.buttons['B' + i] = 0;
controls.keys['B' + i] = [];
}
// Add timers
for (let i = 0; i <= numberOfButtons; i++) {
controls.timers['B' + i] = {
'pressed': 0,
'released': 0,
'duration': 0
};
}
for (let thisDirection of ['UP', 'DOWN', 'LEFT', 'RIGHT', 'ALT_UP', 'ALT_DOWN', 'ALT_LEFT', 'ALT_RIGHT']) {
controls.timers[thisDirection] = {
'pressed': 0,
'released': 0,
'duration': 0
};
}
controls.setPosition = function(x,y) {
this.position.x = x;
this.position.y = y;
}
return controls;
}
getBaseControls() {
return {
'direction': {
'UP': 0,
'DOWN': 0,
'LEFT': 0,
'RIGHT': 0,
},
'direction_secondary': {
'UP': 0,
'DOWN': 0,
'LEFT': 0,
'RIGHT': 0,
},
'buttons': {
},
'keys': {
},
'timers': {
},
'position': {x:0,y:0},
'interaction': {
'buffer': [],
'pressed': [],
'released': [],
'last': '',
'lastPressed': '',
'lastReleased': '',
'device': '',
},
'interaction_mapped': {
'pressed': [],
'released': [],
'last': '',
'lastPressed': '',
'lastReleased': '',
'gamepadType': '',
},
'buttons_mapped': {
}
}
}
// Gamepad functions
/**
* When a gamepad button is pressed down, this function will emit a inputHandler event in the global registry.
* The event contains a reference to the player assigned to the gamepad, and passes a mapped action and value
* @param {number} index Button index
* @param {number} value Button value
* @param {Phaser.Input.Gamepad.Button} button Phaser Button object
*/
gamepadButtonDown(pad, button, value) { gamepadButtonDown(pad, button, value) {
this.players[pad.index].setDevice('gamepad'); const actionMapping = this.getActionGamepadMapping();
this.players[pad.index].buttons.TIMESTAMP = this.scene.sys.time.now; const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index];
this.eventEmitter.emit('inputHandler', { if (buttonDown !== undefined && !this.isButtonPressing) {
device: 'gamepad', this.isButtonPressing = true;
value: value, this.events.emit('input_down', {
player: pad.index, controller_type: 'gamepad',
action: 'B' + button.index, button: buttonDown,
state: 'DOWN'
}); });
this.events.emit('gamepad_buttondown', {
player: pad.index,
button: `B${button.index}`
});
// Buttons
if (![12, 13, 14, 15].includes(button.index)) {
let playerAction = 'B' + button.index;
// Update the last button state
this.players[pad.index].interaction.pressed.push(playerAction);
this.players[pad.index].interaction.last = playerAction;
this.players[pad.index].interaction.lastPressed = playerAction;
this.players[pad.index].interaction.buffer.push(playerAction);
// Update timers
this.players[pad.index].timers[playerAction].pressed = this.scene.sys.time.now;
this.players[pad.index].timers[playerAction].released = 0;
this.players[pad.index].timers[playerAction].duration = 0;
// Update mapped button object
let mappedButton = this.getMappedButton(this.players[pad.index], button.index);
if (typeof mappedButton !== "undefined") {
this.players[pad.index].interaction_mapped.pressed.push(mappedButton);
this.players[pad.index].interaction_mapped.last = mappedButton;
this.players[pad.index].interaction_mapped.lastPressed = mappedButton;
}
}
// DPad
else {
let dpadMapping = this.dpadMappings;
let direction = Object.keys(dpadMapping).find(key => dpadMapping[key] == button.index);
this.eventEmitter.emit('inputHandler', {
device: 'gamepad',
value: 1,
player: pad.index,
action: direction,
state: 'DOWN'
});
this.events.emit('gamepad_directiondown', { player: pad.index, button: direction });
this.players[pad.index].interaction.pressed.push(direction);
this.players[pad.index].interaction.last = direction;
this.players[pad.index].interaction.lastPressed = direction;
this.players[pad.index].interaction.buffer.push(direction);
this.players[pad.index].direction.TIMESTAMP = this.scene.sys.time.now;
// Update timers
this.players[pad.index].timers[direction].pressed = this.scene.sys.time.now;
this.players[pad.index].timers[direction].released = 0;
this.players[pad.index].timers[direction].duration = 0;
// Update mapped button object
let mappedButton = this.getMappedButton(this.players[pad.index], button.index);
if (typeof mappedButton !== "undefined") {
this.players[pad.index].interaction_mapped.pressed.push(mappedButton);
this.players[pad.index].interaction_mapped.last = mappedButton;
this.players[pad.index].interaction_mapped.lastPressed = mappedButton;
} }
} }
}
/**
* Given a player and a button ID, return the mapped button name, e.g. 0 = 'RC_S' (Right cluster, South - X on an xbox gamepad)
* @param {*} player
* @param {*} buttonID
*/
getMappedButton(player, buttonID) {
buttonID = buttonID.toString().replace(/\D/g, '');
return Object.keys(player.gamepadMapping).find(key => player.gamepadMapping[key] == buttonID);
}
/**
* When a gamepad button is released, this function will emit a inputHandler event in the global registry.
* The event contains a reference to the player assigned to the gamepad, and passes a mapped action and value
* @param {number} index Button index
* @param {number} value Button value
* @param {Phaser.Input.Gamepad.Button} button Phaser Button object
*/
gamepadButtonUp(pad, button, value) { gamepadButtonUp(pad, button, value) {
this.players[pad.index].setDevice('gamepad'); const actionMapping = this.getActionGamepadMapping();
this.players[pad.index].buttons.TIMESTAMP = this.scene.sys.time.now; const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index];
if (buttonUp !== undefined && this.isButtonPressing) {
this.eventEmitter.emit('inputHandler', { this.isButtonPressing = false;
device: 'gamepad', this.events.emit('input_up', {
value: value, controller_type: 'gamepad',
player: pad.index, button: buttonUp,
action: 'B' + button.index,
state: 'UP'
}); });
this.events.emit('gamepad_buttonup', { }
player: pad.index, }
button: `B${button.index}`
setupKeyboardControls() {
const keyCodes = Phaser.Input.Keyboard.KeyCodes;
const keyConfig = {
[Button.UP]: [keyCodes.UP, keyCodes.W],
[Button.DOWN]: [keyCodes.DOWN, keyCodes.S],
[Button.LEFT]: [keyCodes.LEFT, keyCodes.A],
[Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D],
[Button.SUBMIT]: [keyCodes.ENTER],
[Button.ACTION]: [keyCodes.SPACE, keyCodes.ENTER, keyCodes.Z],
[Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X],
[Button.MENU]: [keyCodes.ESC, keyCodes.M],
[Button.STATS]: [keyCodes.SHIFT, keyCodes.C],
[Button.CYCLE_SHINY]: [keyCodes.R],
[Button.CYCLE_FORM]: [keyCodes.F],
[Button.CYCLE_GENDER]: [keyCodes.G],
[Button.CYCLE_ABILITY]: [keyCodes.E],
[Button.CYCLE_NATURE]: [keyCodes.N],
[Button.CYCLE_VARIANT]: [keyCodes.V],
[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.systems.input.keyboard.addKey(k, false));
mobileKeyConfig[Button[b]] = keys[0];
}
this.buttonKeys[b] = keys;
}
initTouchControls(mobileKeyConfig);
this.listenInputKeyboard();
}
listenInputKeyboard() {
this.buttonKeys.forEach((row, index) => {
for (const key of row) {
key.on('down', (event) => {
this.events.emit('input_down', {
controller_type: 'keyboard',
button: index,
}); });
// Buttons
if (![12, 13, 14, 15].includes(button.index)) {
let playerAction = 'B' + button.index;
// Update the last button state
this.players[pad.index].interaction.released.push(playerAction);
this.players[pad.index].interaction.lastReleased = playerAction;
// Update timers
this.players[pad.index].timers[playerAction].released = this.scene.sys.time.now;
this.players[pad.index].timers[playerAction].duration = this.players[pad.index].timers[playerAction].released - this.players[pad.index].timers[playerAction].pressed;
delete this.players[pad.index].timers[playerAction]._tick;
// Update mapped button object
let mappedButton = this.getMappedButton(this.players[pad.index], button.index);
if (typeof mappedButton !== "undefined") {
this.players[pad.index].interaction_mapped.released = mappedButton;
this.players[pad.index].interaction_mapped.lastReleased = mappedButton;
}
}
// DPad
else {
let dpadMapping = this.dpadMappings;
let direction = Object.keys(dpadMapping).find(key => dpadMapping[key] == button.index);
this.eventEmitter.emit('inputHandler', {
device: 'gamepad',
value: 1,
player: pad.index,
action: direction,
state: 'UP'
}); });
this.events.emit('gamepad_directionup', { key.on('up', () => {
player: pad.index, this.events.emit('input_up', {
button: direction controller_type: 'keyboard',
button: index,
});
}); });
this.players[pad.index].interaction.released.push(direction);
this.players[pad.index].interaction.lastReleased = direction;
// Update timers
this.players[pad.index].timers[direction].released = this.scene.sys.time.now;
this.players[pad.index].timers[direction].duration = this.players[pad.index].timers[direction].released - this.players[pad.index].timers[direction].pressed;
delete this.players[pad.index].timers[direction]._tick;
// Update mapped button object
let mappedButton = this.getMappedButton(this.players[pad.index], button.index);
if (typeof mappedButton !== "undefined") {
this.players[pad.index].interaction_mapped.released = mappedButton;
this.players[pad.index].interaction_mapped.lastReleased = mappedButton;
} }
} })
}
// setupControls() {
// const keyCodes = Phaser.Input.Keyboard.KeyCodes;
// const keyConfig = {
// [Button.UP]: [keyCodes.UP, keyCodes.W],
// [Button.DOWN]: [keyCodes.DOWN, keyCodes.S],
// [Button.LEFT]: [keyCodes.LEFT, keyCodes.A],
// [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D],
// [Button.SUBMIT]: [keyCodes.ENTER],
// [Button.ACTION]: [keyCodes.SPACE, keyCodes.ENTER, keyCodes.Z],
// [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X],
// [Button.MENU]: [keyCodes.ESC, keyCodes.M],
// [Button.STATS]: [keyCodes.SHIFT, keyCodes.C],
// [Button.CYCLE_SHINY]: [keyCodes.R],
// [Button.CYCLE_FORM]: [keyCodes.F],
// [Button.CYCLE_GENDER]: [keyCodes.G],
// [Button.CYCLE_ABILITY]: [keyCodes.E],
// [Button.CYCLE_NATURE]: [keyCodes.N],
// [Button.CYCLE_VARIANT]: [keyCodes.V],
// [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, false));
// mobileKeyConfig[Button[b]] = keys[0];
// }
// this.buttonKeys[b] = keys;
// }
//
// initTouchControls(mobileKeyConfig);
// }
checkInputKeyboard() {
// this.buttonKeys.forEach((row, index) => {
// for (const key of row) {
// key.on('down', () => {
// if (!this.isButtonPressing) {
// this.isButtonPressing = true;
// this.key_down(index);
// }
// });
// key.on('up', () => {
// if (this.isButtonPressing) {
// this.isButtonPressing = false;
// this.key_up(index);
// }
// });
// }
// })
} }
mapGamepad(id) { mapGamepad(id) {
@ -648,97 +207,6 @@ export class InputHandler extends Phaser.Plugins.ScenePlugin {
padConfig = pad_dualshock; padConfig = pad_dualshock;
} }
console.log('padConfig:', padConfig);
return padConfig; return padConfig;
} }
checkInputGamepad() {
// this.input.gamepad.once('connected', function (pad) {
// const gamepadID = pad.id.toLowerCase();
// this.scene.mappedPad = this.scene.mapGamepad(gamepadID);
// });
// this.input.gamepad.on('down', function (gamepad, button) {
// if (!this.scene.mappedPad) return;
// let inputSuccess;
// let vibrationLength;
// switch(button.index) {
// case this.scene.mappedPad.gamepadMapping.LC_N:
// [inputSuccess, vibrationLength] = this.scene.button_up();
// break;
// case this.scene.mappedPad.gamepadMapping.LC_S:
// [inputSuccess, vibrationLength] = this.scene.button_down();
// break;
// case this.scene.mappedPad.gamepadMapping.LC_W:
// [inputSuccess, vibrationLength] = this.scene.button_left();
// break
// case this.scene.mappedPad.gamepadMapping.LC_E:
// [inputSuccess, vibrationLength] = this.scene.button_right();
// break
// case this.scene.mappedPad.gamepadMapping.TOUCH:
// inputSuccess = this.scene.button_touch();
// break
// case this.scene.mappedPad.gamepadMapping.RC_S:
// inputSuccess = this.scene.button_action();
// break;
// case this.scene.mappedPad.gamepadMapping.RC_E:
// inputSuccess = this.scene.button_cancel();
// break
// case this.scene.mappedPad.gamepadMapping.SELECT:
// this.scene.button_stats(true);
// break
// case this.scene.mappedPad.gamepadMapping.START:
// inputSuccess = this.scene.button_menu();
// break
// case this.scene.mappedPad.gamepadMapping.RB:
// inputSuccess = this.scene.button_cycle_option(Button.CYCLE_SHINY);
// break
// case this.scene.mappedPad.gamepadMapping.LB:
// inputSuccess = this.scene.button_cycle_option(Button.CYCLE_FORM);
// break
// case this.scene.mappedPad.gamepadMapping.LT:
// inputSuccess = this.scene.button_cycle_option(Button.CYCLE_GENDER);
// break
// case this.scene.mappedPad.gamepadMapping.RT:
// inputSuccess = this.scene.button_cycle_option(Button.CYCLE_ABILITY);
// break;
// case this.scene.mappedPad.gamepadMapping.RC_W:
// inputSuccess = this.scene.button_cycle_option(Button.CYCLE_NATURE);
// break
// case this.scene.mappedPad.gamepadMapping.RC_N:
// inputSuccess = this.scene.button_cycle_option(Button.CYCLE_VARIANT);
// break
// case this.scene.mappedPad.gamepadMapping.LS:
// this.scene.button_speed_up();
// break
// case this.scene.mappedPad.gamepadMapping.RS:
// this.scene.button_speed_down();
// break
// }
// if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined')
// navigator.vibrate(vibrationLength);
// });
//
// this.input.gamepad.on('up', function (gamepad, button) {
// switch(button.index) {
// case this.scene.mappedPad.gamepadMapping.SELECT:
// this.scene.button_stats(false);
// break
// }
// });
}
/**
* Get player object
* @param {number} index Player index
*/
getPlayer(index) {
return typeof this.players[index] !== 'undefined' ? this.players[index] : ''
}
destroy() {
this.shutdown();
this.scene = undefined;
}
} }

View File

@ -8,7 +8,6 @@ import InputTextPlugin from 'phaser3-rex-plugins/plugins/inputtext-plugin.js';
import BBCodeText from 'phaser3-rex-plugins/plugins/bbcodetext'; import BBCodeText from 'phaser3-rex-plugins/plugins/bbcodetext';
import TransitionImagePackPlugin from 'phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js'; import TransitionImagePackPlugin from 'phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js';
import { LoadingScene } from './loading-scene'; import { LoadingScene } from './loading-scene';
import {InputHandler} from "./inputHandler";
const config: Phaser.Types.Core.GameConfig = { const config: Phaser.Types.Core.GameConfig = {
type: Phaser.WEBGL, type: Phaser.WEBGL,
@ -36,10 +35,6 @@ const config: Phaser.Types.Core.GameConfig = {
key: 'rexUI', key: 'rexUI',
plugin: UIPlugin, plugin: UIPlugin,
mapping: 'rexUI' mapping: 'rexUI'
}, {
key: 'inputHandler',
plugin: InputHandler,
mapping: 'inputHandler'
}] }]
}, },
input: { input: {