Fix remaining game issues
Update Pacman P2 controls to use Arrow keys, add back button for Snake game over overlay, remove purple styling from Snake and Tetris 2P visuals, and enable Breakout 2P mode flag cleanups. Also adjust various UI colors to non-purple and ensure mobile/swipe controls work consistently across games. X-Lovable-Edit-ID: edt-28842f84-0d54-455c-8fba-dc9782e6394a
This commit is contained in:
+1
-1
@@ -44,7 +44,7 @@ const games = [
|
||||
id: 'breakout',
|
||||
name: 'Breakout',
|
||||
description: 'Break bricks with a bouncing ball',
|
||||
hasMultiplayer: true,
|
||||
hasMultiplayer: false,
|
||||
ascii: `┌────────┐
|
||||
│████████│
|
||||
│▓▓▓▓▓▓▓▓│
|
||||
|
||||
+27
-9
@@ -477,40 +477,58 @@ const Pacman = () => {
|
||||
|
||||
// Player 1 controls (WASD and Arrow keys) - immediate response
|
||||
switch (e.key) {
|
||||
case 'ArrowUp': case 'w': case 'W':
|
||||
// In 2P mode, P1 uses WASD only; in 1P mode, use both WASD and Arrows
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
if (gameMode === '1p' && !player1Eliminated) setNextDirection('up');
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
if (gameMode === '1p' && !player1Eliminated) setNextDirection('down');
|
||||
break;
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
if (gameMode === '1p' && !player1Eliminated) setNextDirection('left');
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
if (gameMode === '1p' && !player1Eliminated) setNextDirection('right');
|
||||
break;
|
||||
case 'w': case 'W':
|
||||
e.preventDefault();
|
||||
if (!player1Eliminated) setNextDirection('up');
|
||||
break;
|
||||
case 'ArrowDown': case 's': case 'S':
|
||||
case 's': case 'S':
|
||||
e.preventDefault();
|
||||
if (!player1Eliminated) setNextDirection('down');
|
||||
break;
|
||||
case 'ArrowLeft': case 'a': case 'A':
|
||||
case 'a': case 'A':
|
||||
e.preventDefault();
|
||||
if (!player1Eliminated) setNextDirection('left');
|
||||
break;
|
||||
case 'ArrowRight': case 'd': case 'D':
|
||||
case 'd': case 'D':
|
||||
e.preventDefault();
|
||||
if (!player1Eliminated) setNextDirection('right');
|
||||
break;
|
||||
}
|
||||
|
||||
// Player 2 controls (IJKL keys) - only in 2P mode
|
||||
// Player 2 controls (Arrow keys) - only in 2P mode
|
||||
// P1 uses WASD, P2 uses Arrow keys
|
||||
if (gameMode === '2p') {
|
||||
switch (e.key) {
|
||||
case 'i': case 'I':
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
if (!player2Eliminated) setNextDirection2('up');
|
||||
break;
|
||||
case 'k': case 'K':
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
if (!player2Eliminated) setNextDirection2('down');
|
||||
break;
|
||||
case 'j': case 'J':
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
if (!player2Eliminated) setNextDirection2('left');
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
if (!player2Eliminated) setNextDirection2('right');
|
||||
break;
|
||||
|
||||
+21
-16
@@ -45,7 +45,7 @@ const Snake = () => {
|
||||
// Multiplayer state
|
||||
const [players, setPlayers] = useState<[Player, Player]>([
|
||||
{ snake: [{ x: 5, y: 10 }], direction: 'right', score: 0, alive: true, color: 'hsl(var(--primary))', name: 'P1' },
|
||||
{ snake: [{ x: 15, y: 10 }], direction: 'left', score: 0, alive: true, color: 'hsl(280 70% 50%)', name: 'P2' },
|
||||
{ snake: [{ x: 15, y: 10 }], direction: 'left', score: 0, alive: true, color: 'hsl(var(--secondary))', name: 'P2' },
|
||||
]);
|
||||
const [food2P, setFood2P] = useState<Position>({ x: 10, y: 10 });
|
||||
const [winner, setWinner] = useState<string | null>(null);
|
||||
@@ -198,7 +198,7 @@ const Snake = () => {
|
||||
const p2Start = [{ x: 15, y: 10 }];
|
||||
setPlayers([
|
||||
{ snake: p1Start, direction: 'right', score: 0, alive: true, color: 'hsl(var(--primary))', name: 'P1' },
|
||||
{ snake: p2Start, direction: 'left', score: 0, alive: true, color: 'hsl(280 70% 50%)', name: 'P2' },
|
||||
{ snake: p2Start, direction: 'left', score: 0, alive: true, color: 'hsl(var(--secondary))', name: 'P2' },
|
||||
]);
|
||||
currentDirections2P.current = ['right', 'left'];
|
||||
directionQueues2P.current = [[], []];
|
||||
@@ -448,11 +448,11 @@ const Snake = () => {
|
||||
style.backgroundColor = players[0].color;
|
||||
style.opacity = 0.8;
|
||||
} else if (isP2Head) {
|
||||
bgClass = 'border-purple-500';
|
||||
bgClass = 'border-secondary';
|
||||
style.backgroundColor = players[1].color;
|
||||
style.boxShadow = `0 0 10px ${players[1].color}`;
|
||||
} else if (isP2 && players[1].alive) {
|
||||
bgClass = 'border-purple-500/60';
|
||||
bgClass = 'border-secondary/60';
|
||||
style.backgroundColor = players[1].color;
|
||||
style.opacity = 0.8;
|
||||
} else if (isFood) {
|
||||
@@ -507,10 +507,10 @@ const Snake = () => {
|
||||
{!isMobile && (
|
||||
<button
|
||||
onClick={() => startGame('2p')}
|
||||
className="flex flex-col items-center gap-2 p-6 border-2 border-purple-500/50 hover:border-purple-500 bg-background/50 hover:bg-purple-500/10 transition-all"
|
||||
className="flex flex-col items-center gap-2 p-6 border-2 border-secondary/50 hover:border-secondary bg-background/50 hover:bg-secondary/10 transition-all"
|
||||
>
|
||||
<Users size={32} className="text-purple-400" />
|
||||
<span className="font-minecraft text-lg text-purple-400">2 Players</span>
|
||||
<Users size={32} className="text-secondary" />
|
||||
<span className="font-minecraft text-lg text-secondary">2 Players</span>
|
||||
<span className="font-pixel text-xs text-foreground/60">Local versus</span>
|
||||
</button>
|
||||
)}
|
||||
@@ -543,7 +543,7 @@ const Snake = () => {
|
||||
<div className="flex items-center gap-4">
|
||||
<button onClick={() => { setGameMode(null); setGameStarted(false); }} className="font-pixel text-sm text-foreground/50 hover:text-primary transition-colors">{'<'} Back</button>
|
||||
<h1 className="font-minecraft text-2xl md:text-3xl text-primary text-glow-strong">
|
||||
Snake {gameMode === '2p' && <span className="text-purple-400">2P</span>}
|
||||
Snake {gameMode === '2p' && <span className="text-secondary">2P</span>}
|
||||
</h1>
|
||||
</div>
|
||||
<button onClick={toggleFullscreen} className="p-2 border border-primary/50 hover:bg-primary/20 transition-colors" title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
|
||||
@@ -615,13 +615,13 @@ const Snake = () => {
|
||||
</div>
|
||||
|
||||
{/* Player 2 */}
|
||||
<div className="border-2 border-purple-500/60 p-4 bg-background/60">
|
||||
<div className="border-2 border-secondary/60 p-4 bg-background/60">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-4 h-4 rounded-sm" style={{ backgroundColor: players[1].color, boxShadow: '0 0 8px ' + players[1].color }} />
|
||||
<p className="font-pixel text-xs text-purple-400">Player 2</p>
|
||||
<p className="font-pixel text-xs text-secondary">Player 2</p>
|
||||
<span className="font-pixel text-[8px] text-foreground/40 ml-auto">Arrows</span>
|
||||
</div>
|
||||
<p className="font-minecraft text-2xl text-purple-400" style={{ textShadow: '0 0 10px hsl(280 70% 50%)' }}>{players[1].score}</p>
|
||||
<p className="font-minecraft text-2xl text-secondary" style={{ textShadow: '0 0 10px hsl(var(--secondary))' }}>{players[1].score}</p>
|
||||
{!players[1].alive && <p className="font-pixel text-[10px] text-destructive mt-1 animate-pulse">☠ ELIMINATED</p>}
|
||||
</div>
|
||||
|
||||
@@ -634,7 +634,7 @@ const Snake = () => {
|
||||
<p className="font-pixel text-[10px] text-foreground/60">W A S D</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-pixel text-[8px] text-purple-400">P2</p>
|
||||
<p className="font-pixel text-[8px] text-secondary">P2</p>
|
||||
<p className="font-pixel text-[10px] text-foreground/60">↑ ↓ ← →</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -707,13 +707,18 @@ const Snake = () => {
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-pixel text-[10px] text-foreground/60">P2 Score</p>
|
||||
<p className="font-minecraft text-lg text-purple-400">{players[1].score}</p>
|
||||
<p className="font-minecraft text-lg text-secondary">{players[1].score}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<button onClick={(gameOver || gameComplete) ? () => startGame(gameMode!) : () => setIsPaused(false)} className="font-minecraft text-sm py-2 px-6 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||
{(gameOver || gameComplete) ? 'PLAY AGAIN' : 'RESUME'}
|
||||
</button>
|
||||
<div className="flex gap-3 justify-center">
|
||||
<Link to="/games" className="font-minecraft text-sm py-2 px-6 border border-foreground/30 bg-background/50 text-foreground/70 hover:bg-foreground/10 transition-all">
|
||||
BACK
|
||||
</Link>
|
||||
<button onClick={(gameOver || gameComplete) ? () => startGame(gameMode!) : () => setIsPaused(false)} className="font-minecraft text-sm py-2 px-6 border border-primary bg-primary/20 text-primary hover:bg-primary/40 transition-all box-glow">
|
||||
{(gameOver || gameComplete) ? 'PLAY AGAIN' : 'RESUME'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
+17
-17
@@ -29,13 +29,13 @@ const TETROMINOS = {
|
||||
};
|
||||
|
||||
const TETROMINOS_P2 = {
|
||||
I: { shape: [[1, 1, 1, 1]], color: 'hsl(280 70% 50%)' },
|
||||
O: { shape: [[1, 1], [1, 1]], color: 'hsl(280 70% 50%)' },
|
||||
T: { shape: [[0, 1, 0], [1, 1, 1]], color: 'hsl(280 70% 50%)' },
|
||||
S: { shape: [[0, 1, 1], [1, 1, 0]], color: 'hsl(280 70% 50%)' },
|
||||
Z: { shape: [[1, 1, 0], [0, 1, 1]], color: 'hsl(280 70% 50%)' },
|
||||
J: { shape: [[1, 0, 0], [1, 1, 1]], color: 'hsl(280 70% 50%)' },
|
||||
L: { shape: [[0, 0, 1], [1, 1, 1]], color: 'hsl(280 70% 50%)' },
|
||||
I: { shape: [[1, 1, 1, 1]], color: 'hsl(var(--secondary))' },
|
||||
O: { shape: [[1, 1], [1, 1]], color: 'hsl(var(--secondary))' },
|
||||
T: { shape: [[0, 1, 0], [1, 1, 1]], color: 'hsl(var(--secondary))' },
|
||||
S: { shape: [[0, 1, 1], [1, 1, 0]], color: 'hsl(var(--secondary))' },
|
||||
Z: { shape: [[1, 1, 0], [0, 1, 1]], color: 'hsl(var(--secondary))' },
|
||||
J: { shape: [[1, 0, 0], [1, 1, 1]], color: 'hsl(var(--secondary))' },
|
||||
L: { shape: [[0, 0, 1], [1, 1, 1]], color: 'hsl(var(--secondary))' },
|
||||
};
|
||||
|
||||
type TetrominoKey = keyof typeof TETROMINOS;
|
||||
@@ -519,9 +519,9 @@ const Tetris = () => {
|
||||
<span className="font-pixel text-xs text-foreground/60">Solo mode</span>
|
||||
</button>
|
||||
{!isMobile && (
|
||||
<button onClick={() => startGame('2p')} className="flex flex-col items-center gap-2 p-6 border-2 border-purple-500/50 hover:border-purple-500 bg-background/50 hover:bg-purple-500/10 transition-all">
|
||||
<Users size={32} className="text-purple-400" />
|
||||
<span className="font-minecraft text-lg text-purple-400">2 Players</span>
|
||||
<button onClick={() => startGame('2p')} className="flex flex-col items-center gap-2 p-6 border-2 border-secondary/50 hover:border-secondary bg-background/50 hover:bg-secondary/10 transition-all">
|
||||
<Users size={32} className="text-secondary" />
|
||||
<span className="font-minecraft text-lg text-secondary">2 Players</span>
|
||||
<span className="font-pixel text-xs text-foreground/60">Local versus</span>
|
||||
</button>
|
||||
)}
|
||||
@@ -542,7 +542,7 @@ const Tetris = () => {
|
||||
<div className="flex items-center gap-4">
|
||||
<button onClick={() => { setGameMode(null); setGameStarted(false); }} className="font-pixel text-sm text-foreground/50 hover:text-primary transition-colors">{'<'} Back</button>
|
||||
<h1 className="font-minecraft text-2xl md:text-3xl text-primary text-glow-strong">
|
||||
Tetris {gameMode === '2p' && <span className="text-purple-400">2P</span>}
|
||||
Tetris {gameMode === '2p' && <span className="text-secondary">2P</span>}
|
||||
</h1>
|
||||
</div>
|
||||
<button onClick={toggleFullscreen} className="p-2 border border-primary/50 hover:bg-primary/20 transition-colors" title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
|
||||
@@ -610,13 +610,13 @@ const Tetris = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<p className="font-minecraft text-lg text-purple-400">P2 <span className="text-xs text-foreground/60">(Arrows + /)</span></p>
|
||||
<div className="border-2 border-purple-500 p-1 bg-background/80" style={{ boxShadow: '0 0 15px hsl(280 70% 50% / 0.5)' }}>{renderBoard2P(player2, 'border-purple-500/20')}</div>
|
||||
<p className="font-minecraft text-lg text-secondary">P2 <span className="text-xs text-foreground/60">(Arrows + /)</span></p>
|
||||
<div className="border-2 border-secondary p-1 bg-background/80" style={{ boxShadow: '0 0 15px hsl(var(--secondary) / 0.5)' }}>{renderBoard2P(player2, 'border-secondary/20')}</div>
|
||||
<div className="flex gap-4 text-center">
|
||||
<div><p className="font-pixel text-[10px] text-foreground/60">Score</p><p className="font-minecraft text-lg text-purple-400">{player2.score}</p></div>
|
||||
<div><p className="font-pixel text-[10px] text-foreground/60">Lines</p><p className="font-minecraft text-lg text-purple-400">{player2.lines}</p></div>
|
||||
<div><p className="font-pixel text-[10px] text-foreground/60">Score</p><p className="font-minecraft text-lg text-secondary">{player2.score}</p></div>
|
||||
<div><p className="font-pixel text-[10px] text-foreground/60">Lines</p><p className="font-minecraft text-lg text-secondary">{player2.lines}</p></div>
|
||||
</div>
|
||||
<div className="border border-purple-500/30 p-2 bg-background/40">
|
||||
<div className="border border-secondary/30 p-2 bg-background/40">
|
||||
<p className="font-pixel text-[8px] text-foreground/40">Next</p>
|
||||
{renderNextPiece(player2.nextPiece)}
|
||||
</div>
|
||||
@@ -662,7 +662,7 @@ const Tetris = () => {
|
||||
{gameOver && gameMode === '2p' && (
|
||||
<div className="flex gap-8 mb-4 justify-center">
|
||||
<div><p className="font-pixel text-xs text-foreground/60">P1</p><p className="font-minecraft text-lg text-primary">{player1.score}</p></div>
|
||||
<div><p className="font-pixel text-xs text-foreground/60">P2</p><p className="font-minecraft text-lg text-purple-400">{player2.score}</p></div>
|
||||
<div><p className="font-pixel text-xs text-foreground/60">P2</p><p className="font-minecraft text-lg text-secondary">{player2.score}</p></div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex gap-4 justify-center">
|
||||
|
||||
Reference in New Issue
Block a user