feat(02-01): extend GameConfig, GameState, and Input for two-player support

- Add WIN_SCORE, AI_EASY, AI_MEDIUM, AI_HARD to GameConfig
- Add paddle2, score1, score2, mode, difficulty, gameState, winner to GameState
- Replace anonymous Input handlers with named refs + cleanup() method
- Add Input.getVerticalInput2() for ArrowUp/ArrowDown keys
- Position paddle2 on right side in Physics.init()
- Update Physics.onResize() to call init() for full repositioning
This commit is contained in:
Dabit
2026-03-10 21:05:13 +01:00
parent 8029a383e3
commit a2f0bc391b

View File

@@ -16,7 +16,13 @@
const GameConfig = { const GameConfig = {
initialBallSpeed: 220, // px/s — starting speed per serve initialBallSpeed: 220, // px/s — starting speed per serve
speedIncrement: 18, // px/s added per paddle hit speedIncrement: 18, // px/s added per paddle hit
paddleSpeed: 400 // px/s — Player 1 paddle movement paddleSpeed: 400, // px/s — Player 1 paddle movement
WIN_SCORE: 7,
AI_EASY: { speed: 200, reactionDelay: 0.3, errorMargin: 20 },
AI_MEDIUM: { speed: 320, reactionDelay: 0.1, errorMargin: 5 },
AI_HARD: { speed: 400, reactionDelay: 0.05, errorMargin: 2 }
}; };
const Renderer = { const Renderer = {
@@ -99,28 +105,50 @@
vx: 0, vy: 0, // Set on Physics.init() vx: 0, vy: 0, // Set on Physics.init()
speed: 0, // Current scalar speed speed: 0, // Current scalar speed
color: '#fff' color: '#fff'
} },
paddle2: {
x: 0, y: 0, // Set on Physics.init()
width: 12, height: 80,
speed: 400,
color: '#fff'
},
score1: 0,
score2: 0,
mode: null, // null = mode select screen; 'ai' = Solo vs AI; '2p' = 2-Player local
difficulty: 'medium', // 'easy', 'medium', 'hard'
gameState: 'modeSelect',// 'modeSelect', 'diffSelect', 'playing', 'scored', 'gameover'
winner: null // null, 'player1', 'player2', 'ai'
}; };
const Input = { const Input = {
keys: { w: false, s: false }, keys: { w: false, s: false, arrowUp: false, arrowDown: false },
_handleKeyDown: null,
_handleKeyUp: null,
init() { init() {
document.addEventListener('keydown', (e) => { this._handleKeyDown = (e) => {
if (e.code === 'KeyW') { this.keys.w = true; e.preventDefault(); } if (e.code === 'KeyW') { this.keys.w = true; e.preventDefault(); }
if (e.code === 'KeyS') { this.keys.s = true; e.preventDefault(); } if (e.code === 'KeyS') { this.keys.s = true; e.preventDefault(); }
}); if (e.code === 'ArrowUp') { this.keys.arrowUp = true; e.preventDefault(); }
document.addEventListener('keyup', (e) => { if (e.code === 'ArrowDown') { this.keys.arrowDown = true; e.preventDefault(); }
};
this._handleKeyUp = (e) => {
if (e.code === 'KeyW') this.keys.w = false; if (e.code === 'KeyW') this.keys.w = false;
if (e.code === 'KeyS') this.keys.s = false; if (e.code === 'KeyS') this.keys.s = false;
}); if (e.code === 'ArrowUp') this.keys.arrowUp = false;
if (e.code === 'ArrowDown') this.keys.arrowDown = false;
};
document.addEventListener('keydown', this._handleKeyDown);
document.addEventListener('keyup', this._handleKeyUp);
}, },
getVerticalInput() { cleanup() {
if (this.keys.w) return -1; document.removeEventListener('keydown', this._handleKeyDown);
if (this.keys.s) return 1; document.removeEventListener('keyup', this._handleKeyUp);
return 0; },
}
getVerticalInput() { return this.keys.w ? -1 : this.keys.s ? 1 : 0; },
getVerticalInput2() { return this.keys.arrowUp ? -1 : this.keys.arrowDown ? 1 : 0; }
}; };
const Physics = { const Physics = {
@@ -134,13 +162,16 @@
GameState.paddle1.x = 30; GameState.paddle1.x = 30;
GameState.paddle1.y = height / 2 - GameState.paddle1.height / 2; GameState.paddle1.y = height / 2 - GameState.paddle1.height / 2;
GameState.paddle1.speed = GameConfig.paddleSpeed; GameState.paddle1.speed = GameConfig.paddleSpeed;
// Position paddle2 on right side, vertically centered
GameState.paddle2.x = width - 30 - GameState.paddle2.width;
GameState.paddle2.y = height / 2 - GameState.paddle2.height / 2;
GameState.paddle2.speed = GameConfig.paddleSpeed;
// Serve ball from center // Serve ball from center
this.serveBall(); this.serveBall();
}, },
onResize(width, height) { onResize(width, height) {
this.width = width; this.init(width, height);
this.height = height;
}, },
serveBall() { serveBall() {