added back repeated input feature on keeping down a key

This commit is contained in:
Greenlamp 2024-05-03 14:34:24 +02:00
parent 4f4f4e035a
commit 23fe290c57
2 changed files with 83 additions and 47 deletions

View File

@ -170,11 +170,6 @@ export default class BattleScene extends SceneBase {
private bgmResumeTimer: Phaser.Time.TimerEvent; private bgmResumeTimer: Phaser.Time.TimerEvent;
private bgmCache: Set<string> = new Set(); private bgmCache: Set<string> = new Set();
private playTimeTimer: Phaser.Time.TimerEvent; private playTimeTimer: Phaser.Time.TimerEvent;
private lastProcessedButtonPressTimes: Map<Button, number> = new Map();
// movementButtonLock ensures only a single movement key is firing repeated inputs
// (i.e. by holding down a button) at a time
private movementButtonLock: Button;
public rngCounter: integer = 0; public rngCounter: integer = 0;
public rngSeedOverride: string = ''; public rngSeedOverride: string = '';
@ -248,7 +243,7 @@ export default class BattleScene extends SceneBase {
this.ui?.update(); this.ui?.update();
} }
listenInputs() { listenInputs(): void {
this.inputController.events.on('input_down', (event) => { this.inputController.events.on('input_down', (event) => {
const actions = this.getActionsKeyDown(); const actions = this.getActionsKeyDown();
if (!actions.hasOwnProperty(event.button)) return; if (!actions.hasOwnProperty(event.button)) return;
@ -1281,45 +1276,41 @@ export default class BattleScene extends SceneBase {
return biomes[Utils.randSeedInt(biomes.length)]; return biomes[Utils.randSeedInt(biomes.length)];
} }
buttonDirection(direction) { buttonDirection(direction): Array<boolean | number> {
const inputSuccess = this.ui.processInput(direction); const inputSuccess = this.ui.processInput(direction);
const vibrationLength = 5; const vibrationLength = 5;
this.setLastProcessedMovementTime(direction);
return [inputSuccess, vibrationLength]; return [inputSuccess, vibrationLength];
} }
buttonAb(button) { buttonAb(button): Array<boolean | number> {
const inputSuccess = this.ui.processInput(button); const inputSuccess = this.ui.processInput(button);
this.setLastProcessedMovementTime(button);
return [inputSuccess, 0]; return [inputSuccess, 0];
} }
buttonTouch() { buttonTouch(): Array<boolean | number> {
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);
return [inputSuccess, 0]; return [inputSuccess, 0];
} }
buttonStats(pressed = true) { buttonStats(pressed = true): Array<boolean | number> {
if (pressed) { if (pressed) {
for (let p of this.getField().filter(p => p?.isActive(true))) for (let p of this.getField().filter(p => p?.isActive(true)))
p.toggleStats(true); p.toggleStats(true);
this.setLastProcessedMovementTime(Button.STATS);
} else { } else {
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]; return [true, 0];
} }
buttonMenu() { buttonMenu(): Array<boolean | number> {
let inputSuccess; let inputSuccess;
if (this.disableMenu) if (this.disableMenu)
return [0, 0]; return [true, 0];
switch (this.ui?.getMode()) { switch (this.ui?.getMode()) {
case Mode.MESSAGE: case Mode.MESSAGE:
if (!(this.ui.getHandler() as MessageUiHandler).pendingPrompt) if (!(this.ui.getHandler() as MessageUiHandler).pendingPrompt)
return [0, 0]; return [true, 0];
case Mode.TITLE: case Mode.TITLE:
case Mode.COMMAND: case Mode.COMMAND:
case Mode.FIGHT: case Mode.FIGHT:
@ -1342,23 +1333,21 @@ export default class BattleScene extends SceneBase {
inputSuccess = true; inputSuccess = true;
break; break;
default: default:
return [0, 0]; return [true, 0];
} }
return [inputSuccess, 0]; return [inputSuccess, 0];
} }
buttonCycleOption(button) { buttonCycleOption(button): Array<boolean | number> {
let inputSuccess; let inputSuccess;
if (this.ui?.getHandler() instanceof StarterSelectUiHandler) { if (this.ui?.getHandler() instanceof StarterSelectUiHandler) {
inputSuccess = this.ui.processInput(button); inputSuccess = this.ui.processInput(button);
this.setLastProcessedMovementTime(button);
} }
return [inputSuccess, 0]; return [inputSuccess, 0];
} }
buttonSpeedChange(up= true) { buttonSpeedChange(up= true): Array<boolean | number> {
if (up) { if (up) {
console.log('speed up');
if (this.gameSpeed < 5) { if (this.gameSpeed < 5) {
this.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) + 1); this.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) + 1);
if (this.ui?.getMode() === Mode.SETTINGS) if (this.ui?.getMode() === Mode.SETTINGS)
@ -1367,7 +1356,6 @@ export default class BattleScene extends SceneBase {
return [0, 0]; return [0, 0];
} }
if (this.gameSpeed > 1) { if (this.gameSpeed > 1) {
console.log('speed down');
this.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) - 1, 0)); this.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) - 1, 0));
if (this.ui?.getMode() === Mode.SETTINGS) if (this.ui?.getMode() === Mode.SETTINGS)
(this.ui.getHandler() as SettingsUiHandler).show([]); (this.ui.getHandler() as SettingsUiHandler).show([]);
@ -1403,12 +1391,6 @@ export default class BattleScene extends SceneBase {
return actions; return actions;
} }
setLastProcessedMovementTime(button: Button) {
this.lastProcessedButtonPressTimes.set(button, this.time.now);
this.movementButtonLock = button;
}
isBgmPlaying(): boolean { isBgmPlaying(): boolean {
return this.bgm && this.bgm.isPlaying; return this.bgm && this.bgm.isPlaying;
} }

View File

@ -1,4 +1,4 @@
import Phaser from "phaser"; import Phaser, { Time } from "phaser";
import * as Utils from "./utils"; import * as Utils from "./utils";
import {initTouchControls} from './touch-controls'; import {initTouchControls} from './touch-controls';
import pad_generic from "#app/configs/pad_generic"; import pad_generic from "#app/configs/pad_generic";
@ -26,27 +26,41 @@ export enum Button {
SPEED_UP, SPEED_UP,
SLOW_DOWN SLOW_DOWN
} }
const repeatInputDelayMillis = 250;
export class InputsController extends Phaser.Plugins.ScenePlugin { export class InputsController extends Phaser.Plugins.ScenePlugin {
private game: Phaser.Game; private game: Phaser.Game;
private buttonKeys; private buttonKeys: Phaser.Input.Keyboard.Key[][];
private gamepads; private gamepads: Array<string> = new Array();
private scene; private scene: Phaser.Scene;
private isButtonPressing;
// buttonLock ensures only a single movement key is firing repeated inputs
// (i.e. by holding down a button) at a time
private buttonLock: Button;
private interactions: Map<Button, Map<string, boolean>> = new Map();
private time: Time;
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 this.time = this.scene.time;
this.buttonKeys = {}; this.buttonKeys = [];
this.gamepads = [];
this.isButtonPressing = false; for (const b of Utils.getEnumValues(Button)) {
this.interactions[b] = {
pressTime: false,
isPressed: false,
}
}
delete this.interactions[Button.MENU];
delete this.interactions[Button.SUBMIT];
} }
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.STEP, this.update, this);
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) {
@ -59,7 +73,6 @@ export class InputsController extends Phaser.Plugins.ScenePlugin {
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);
} }
} }
@ -72,6 +85,19 @@ export class InputsController extends Phaser.Plugins.ScenePlugin {
this.setupKeyboardControls(); this.setupKeyboardControls();
} }
update() {
for (const b of Utils.getEnumValues(Button)) {
if (!this.interactions.hasOwnProperty(b)) continue;
if (this.repeatInputDurationJustPassed(b)) {
this.events.emit('input_down', {
controller_type: 'keyboard',
button: b,
});
this.setLastProcessedMovementTime(b);
}
}
}
setupGamepad(thisGamepad) { setupGamepad(thisGamepad) {
let gamepadID = thisGamepad.id.toLowerCase(); let gamepadID = thisGamepad.id.toLowerCase();
const mappedPad = this.mapGamepad(gamepadID); const mappedPad = this.mapGamepad(gamepadID);
@ -116,24 +142,24 @@ export class InputsController extends Phaser.Plugins.ScenePlugin {
gamepadButtonDown(pad, button, value) { gamepadButtonDown(pad, button, value) {
const actionMapping = this.getActionGamepadMapping(); const actionMapping = this.getActionGamepadMapping();
const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index];
if (buttonDown !== undefined && !this.isButtonPressing) { if (buttonDown !== undefined) {
this.isButtonPressing = true;
this.events.emit('input_down', { this.events.emit('input_down', {
controller_type: 'gamepad', controller_type: 'gamepad',
button: buttonDown, button: buttonDown,
}); });
this.setLastProcessedMovementTime(buttonDown);
} }
} }
gamepadButtonUp(pad, button, value) { gamepadButtonUp(pad, button, value) {
const actionMapping = this.getActionGamepadMapping(); const actionMapping = this.getActionGamepadMapping();
const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index];
if (buttonUp !== undefined && this.isButtonPressing) { if (buttonUp !== undefined) {
this.isButtonPressing = false;
this.events.emit('input_up', { this.events.emit('input_up', {
controller_type: 'gamepad', controller_type: 'gamepad',
button: buttonUp, button: buttonUp,
}); });
this.delLastProcessedMovementTime(buttonUp);
} }
} }
@ -159,8 +185,7 @@ export class InputsController extends Phaser.Plugins.ScenePlugin {
[Button.SLOW_DOWN]: [keyCodes.MINUS] [Button.SLOW_DOWN]: [keyCodes.MINUS]
}; };
const mobileKeyConfig = {}; const mobileKeyConfig = {};
this.buttonKeys = []; for (const b of Utils.getEnumValues(Button)) {
for (let b of Utils.getEnumValues(Button)) {
const keys: Phaser.Input.Keyboard.Key[] = []; const keys: Phaser.Input.Keyboard.Key[] = [];
if (keyConfig.hasOwnProperty(b)) { if (keyConfig.hasOwnProperty(b)) {
for (let k of keyConfig[b]) for (let k of keyConfig[b])
@ -177,17 +202,19 @@ export class InputsController extends Phaser.Plugins.ScenePlugin {
listenInputKeyboard() { listenInputKeyboard() {
this.buttonKeys.forEach((row, index) => { this.buttonKeys.forEach((row, index) => {
for (const key of row) { for (const key of row) {
key.on('down', (event) => { key.on('down', () => {
this.events.emit('input_down', { this.events.emit('input_down', {
controller_type: 'keyboard', controller_type: 'keyboard',
button: index, button: index,
}); });
this.setLastProcessedMovementTime(index);
}); });
key.on('up', () => { key.on('up', () => {
this.events.emit('input_up', { this.events.emit('input_up', {
controller_type: 'keyboard', controller_type: 'keyboard',
button: index, button: index,
}); });
this.delLastProcessedMovementTime(index);
}); });
} }
}) })
@ -209,4 +236,31 @@ export class InputsController extends Phaser.Plugins.ScenePlugin {
return padConfig; return padConfig;
} }
/**
* repeatInputDurationJustPassed returns true if @param button has been held down long
* enough to fire a repeated input. A button must claim the buttonLock before
* firing a repeated input - this is to prevent multiple buttons from firing repeatedly.
*/
repeatInputDurationJustPassed(button: Button): boolean {
if (this.buttonLock === null || this.buttonLock !== button) {
return false;
}
if (this.time.now - this.interactions[button].pressTime >= repeatInputDelayMillis) {
this.buttonLock = null;
return true;
}
}
setLastProcessedMovementTime(button: Button) {
if (!this.interactions.hasOwnProperty(button)) return;
this.buttonLock = button;
this.interactions[button].pressTime = this.time.now;
}
delLastProcessedMovementTime(button: Button) {
if (!this.interactions.hasOwnProperty(button)) return;
this.buttonLock = null;
this.interactions[button].pressTime = null;
}
} }