changed visual movement speed to be slower and made diagonal movement with arrow keys work

This commit is contained in:
2026-01-28 18:59:35 +11:00
parent f01d8de15c
commit 80e82f68a0
6 changed files with 185 additions and 142 deletions

View File

@@ -130,7 +130,8 @@ export const GAME_CONFIG = {
horizontal: 54, horizontal: 54,
vertical: 55, vertical: 55,
turning: 56 turning: 56
} },
moveDuration: 62 // Visual duration for movement in ms
}, },
ui: { ui: {

View File

@@ -111,7 +111,13 @@ export class GameInput extends Phaser.Events.EventEmitter {
Phaser.Input.Keyboard.JustDown(this.cursors.up!) || Phaser.Input.Keyboard.JustDown(this.cursors.up!) ||
Phaser.Input.Keyboard.JustDown(this.cursors.down!); Phaser.Input.Keyboard.JustDown(this.cursors.down!);
return { dx, dy, anyJustDown }; return {
dx, dy, anyJustDown,
isLeft: !!left,
isRight: !!right,
isUp: !!up,
isDown: !!down
};
} }
public cleanup() { public cleanup() {

View File

@@ -49,8 +49,8 @@ export function findPathAStar(
return true; return true;
}; };
// Use rot-js A* pathfinding with 4-directional topology // Use rot-js A* pathfinding with 8-directional topology
const astar = new ROT.Path.AStar(end.x, end.y, passableCallback, { topology: 4 }); const astar = new ROT.Path.AStar(end.x, end.y, passableCallback, { topology: 8 });
const path: Vec2[] = []; const path: Vec2[] = [];

View File

@@ -247,7 +247,7 @@ export class DungeonRenderer {
targets: this.playerSprite, targets: this.playerSprite,
x: tx, x: tx,
y: ty, y: ty,
duration: 120, duration: GAME_CONFIG.rendering.moveDuration,
ease: 'Quad.easeOut', ease: 'Quad.easeOut',
overwrite: true overwrite: true
}); });
@@ -285,7 +285,7 @@ export class DungeonRenderer {
targets: sprite, targets: sprite,
x: tx, x: tx,
y: ty, y: ty,
duration: 120, duration: GAME_CONFIG.rendering.moveDuration,
ease: 'Quad.easeOut', ease: 'Quad.easeOut',
overwrite: true overwrite: true
}); });

View File

@@ -51,6 +51,7 @@ export class GameScene extends Phaser.Scene {
public playerPath: Vec2[] = []; public playerPath: Vec2[] = [];
public awaitingPlayer = false; public awaitingPlayer = false;
private lastMoveTime = 0;
// Sub-systems // Sub-systems
public dungeonRenderer!: DungeonRenderer; public dungeonRenderer!: DungeonRenderer;
@@ -138,7 +139,7 @@ export class GameScene extends Phaser.Scene {
const dx = next.x - player.pos.x; const dx = next.x - player.pos.x;
const dy = next.y - player.pos.y; const dy = next.y - player.pos.y;
if (Math.abs(dx) + Math.abs(dy) !== 1) { if (Math.max(Math.abs(dx), Math.abs(dy)) !== 1) {
this.playerPath = []; this.playerPath = [];
return; return;
} }
@@ -156,7 +157,12 @@ export class GameScene extends Phaser.Scene {
} }
} }
if (this.time.now - this.lastMoveTime < GAME_CONFIG.rendering.moveDuration) {
return;
}
this.commitPlayerAction({ type: "move", dx, dy }); this.commitPlayerAction({ type: "move", dx, dy });
this.lastMoveTime = this.time.now;
this.playerPath.shift(); this.playerPath.shift();
return; return;
} }
@@ -164,8 +170,16 @@ export class GameScene extends Phaser.Scene {
let action: Action | null = this.playerInputHandler.handleCursorMovement(); let action: Action | null = this.playerInputHandler.handleCursorMovement();
if (action) { if (action) {
if (action.type === "move" && this.time.now - this.lastMoveTime < GAME_CONFIG.rendering.moveDuration) {
return;
}
this.playerPath = []; this.playerPath = [];
this.commitPlayerAction(action); this.commitPlayerAction(action);
if (action.type === "move") {
this.lastMoveTime = this.time.now;
}
} }
} }

View File

@@ -7,6 +7,12 @@ import type { Action, RangedWeaponItem } from "../../core/types";
export class PlayerInputHandler { export class PlayerInputHandler {
private scene: GameScene; private scene: GameScene;
// Input Chording state
private pendingDx: number = 0;
private pendingDy: number = 0;
private moveChordTime: number = 0;
private readonly CHORD_WINDOW = 40; // ms to wait for diagonal chord
constructor(scene: GameScene) { constructor(scene: GameScene) {
this.scene = scene; this.scene = scene;
} }
@@ -170,10 +176,28 @@ export class PlayerInputHandler {
} }
public handleCursorMovement(): Action | null { public handleCursorMovement(): Action | null {
const { dx, dy, anyJustDown } = this.scene.gameInput.getCursorState(); const { dx, dy, anyJustDown } = this.scene.gameInput.getCursorState() as any;
const now = this.scene.time.now;
if (anyJustDown) { if (anyJustDown) {
if (dx !== 0 || dy !== 0) { // Start or update chord
if (this.moveChordTime === 0) {
this.moveChordTime = now + this.CHORD_WINDOW;
}
if (dx !== 0) this.pendingDx = dx;
if (dy !== 0) this.pendingDy = dy;
}
if (this.moveChordTime > 0 && now >= this.moveChordTime) {
const finalDx = this.pendingDx;
const finalDy = this.pendingDy;
// Reset state
this.moveChordTime = 0;
this.pendingDx = 0;
this.pendingDy = 0;
if (finalDx !== 0 || finalDy !== 0) {
if (this.scene.targetingSystem.isActive) { if (this.scene.targetingSystem.isActive) {
this.scene.targetingSystem.cancel(); this.scene.targetingSystem.cancel();
this.scene.emitUIUpdate(); this.scene.emitUIUpdate();
@@ -181,17 +205,15 @@ export class PlayerInputHandler {
const player = this.scene.entityAccessor.getPlayer(); const player = this.scene.entityAccessor.getPlayer();
if (!player) return null; if (!player) return null;
const targetX = player.pos.x + dx; const targetX = player.pos.x + finalDx;
const targetY = player.pos.y + dy; const targetY = player.pos.y + finalDy;
const enemy = this.scene.entityAccessor.findEnemyAt(targetX, targetY); const enemy = this.scene.entityAccessor.findEnemyAt(targetX, targetY);
if (enemy) { if (enemy) {
return { type: "attack", targetId: enemy.id }; return { type: "attack", targetId: enemy.id };
} else { } else {
if (Math.abs(dx) + Math.abs(dy) === 1) { return { type: "move", dx: finalDx, dy: finalDy };
return { type: "move", dx, dy };
}
} }
} }
} }