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:
59
index.html
59
index.html
@@ -16,7 +16,13 @@
|
||||
const GameConfig = {
|
||||
initialBallSpeed: 220, // px/s — starting speed per serve
|
||||
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 = {
|
||||
@@ -99,28 +105,50 @@
|
||||
vx: 0, vy: 0, // Set on Physics.init()
|
||||
speed: 0, // Current scalar speed
|
||||
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 = {
|
||||
keys: { w: false, s: false },
|
||||
keys: { w: false, s: false, arrowUp: false, arrowDown: false },
|
||||
_handleKeyDown: null,
|
||||
_handleKeyUp: null,
|
||||
|
||||
init() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
this._handleKeyDown = (e) => {
|
||||
if (e.code === 'KeyW') { this.keys.w = true; e.preventDefault(); }
|
||||
if (e.code === 'KeyS') { this.keys.s = true; e.preventDefault(); }
|
||||
});
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.code === 'ArrowUp') { this.keys.arrowUp = true; e.preventDefault(); }
|
||||
if (e.code === 'ArrowDown') { this.keys.arrowDown = true; e.preventDefault(); }
|
||||
};
|
||||
this._handleKeyUp = (e) => {
|
||||
if (e.code === 'KeyW') this.keys.w = 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() {
|
||||
if (this.keys.w) return -1;
|
||||
if (this.keys.s) return 1;
|
||||
return 0;
|
||||
}
|
||||
cleanup() {
|
||||
document.removeEventListener('keydown', this._handleKeyDown);
|
||||
document.removeEventListener('keyup', this._handleKeyUp);
|
||||
},
|
||||
|
||||
getVerticalInput() { return this.keys.w ? -1 : this.keys.s ? 1 : 0; },
|
||||
getVerticalInput2() { return this.keys.arrowUp ? -1 : this.keys.arrowDown ? 1 : 0; }
|
||||
};
|
||||
|
||||
const Physics = {
|
||||
@@ -134,13 +162,16 @@
|
||||
GameState.paddle1.x = 30;
|
||||
GameState.paddle1.y = height / 2 - GameState.paddle1.height / 2;
|
||||
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
|
||||
this.serveBall();
|
||||
},
|
||||
|
||||
onResize(width, height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.init(width, height);
|
||||
},
|
||||
|
||||
serveBall() {
|
||||
|
||||
Reference in New Issue
Block a user