Changes
This commit is contained in:
@@ -7,18 +7,13 @@ const MatrixCursor = () => {
|
|||||||
const [isTouchDevice, setIsTouchDevice] = useState(false);
|
const [isTouchDevice, setIsTouchDevice] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Detect touch device - check for touch capability and if primary input is touch
|
// Detect touch device - only consider it a touch device if primary pointer is coarse (touch)
|
||||||
const checkTouchDevice = () => {
|
const checkTouchDevice = () => {
|
||||||
const hasTouchScreen = 'ontouchstart' in window ||
|
// Check if the device has a fine pointer (mouse) as primary input
|
||||||
navigator.maxTouchPoints > 0 ||
|
|
||||||
// @ts-ignore - msMaxTouchPoints is IE-specific
|
|
||||||
navigator.msMaxTouchPoints > 0;
|
|
||||||
|
|
||||||
// Also check if the device has a fine pointer (mouse)
|
|
||||||
const hasFinePrimary = window.matchMedia('(pointer: fine)').matches;
|
const hasFinePrimary = window.matchMedia('(pointer: fine)').matches;
|
||||||
|
|
||||||
// Consider it a touch device if it has touch AND doesn't have fine pointer as primary
|
// Consider it a touch device only if it doesn't have a fine pointer as primary
|
||||||
setIsTouchDevice(hasTouchScreen && !hasFinePrimary);
|
setIsTouchDevice(!hasFinePrimary);
|
||||||
};
|
};
|
||||||
|
|
||||||
checkTouchDevice();
|
checkTouchDevice();
|
||||||
|
|||||||
+11
-1
@@ -261,6 +261,16 @@ const Breakout = () => {
|
|||||||
paddleXRef.current = Math.max(0, Math.min(canvasSize.width - paddleWidth, x - paddleWidth / 2));
|
paddleXRef.current = Math.max(0, Math.min(canvasSize.width - paddleWidth, x - paddleWidth / 2));
|
||||||
}, [gameStarted, gameOver, isPaused, canvasSize.width, paddleWidth]);
|
}, [gameStarted, gameOver, isPaused, canvasSize.width, paddleWidth]);
|
||||||
|
|
||||||
|
// Mouse move handler for desktop
|
||||||
|
const handleMouseMove = useCallback((e: React.MouseEvent) => {
|
||||||
|
if (!gameStarted || gameOver || isPaused || isMobile || isTwoPlayer) return;
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
if (!canvas) return;
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const x = e.clientX - rect.left;
|
||||||
|
paddleXRef.current = Math.max(0, Math.min(canvasSize.width - paddleWidth, x - paddleWidth / 2));
|
||||||
|
}, [gameStarted, gameOver, isPaused, canvasSize.width, paddleWidth, isMobile, isTwoPlayer]);
|
||||||
|
|
||||||
const moveLeft = useCallback(() => { paddleXRef.current = Math.max(0, paddleXRef.current - 20); }, []);
|
const moveLeft = useCallback(() => { paddleXRef.current = Math.max(0, paddleXRef.current - 20); }, []);
|
||||||
const moveRight = useCallback(() => { paddleXRef.current = Math.min(canvasSize.width - paddleWidth, paddleXRef.current + 20); }, [canvasSize.width, paddleWidth]);
|
const moveRight = useCallback(() => { paddleXRef.current = Math.min(canvasSize.width - paddleWidth, paddleXRef.current + 20); }, [canvasSize.width, paddleWidth]);
|
||||||
|
|
||||||
@@ -547,7 +557,7 @@ const Breakout = () => {
|
|||||||
<div className={`flex ${isTwoPlayer ? 'gap-4' : ''}`}>
|
<div className={`flex ${isTwoPlayer ? 'gap-4' : ''}`}>
|
||||||
{/* P1 Board */}
|
{/* P1 Board */}
|
||||||
<div className="border-2 border-primary box-glow bg-background/80">
|
<div className="border-2 border-primary box-glow bg-background/80">
|
||||||
<canvas ref={canvasRef} width={canvasSize.width} height={canvasSize.height} onTouchMove={handleTouchMove} className="block" />
|
<canvas ref={canvasRef} width={canvasSize.width} height={canvasSize.height} onTouchMove={handleTouchMove} onMouseMove={handleMouseMove} className="block cursor-none" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* P2 Board */}
|
{/* P2 Board */}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ const games = [
|
|||||||
id: 'tetris',
|
id: 'tetris',
|
||||||
name: 'Tetris',
|
name: 'Tetris',
|
||||||
description: 'Classic block-stacking puzzle game',
|
description: 'Classic block-stacking puzzle game',
|
||||||
hasMultiplayer: true,
|
|
||||||
ascii: `┌────────┐
|
ascii: `┌────────┐
|
||||||
│ ▓▓ │
|
│ ▓▓ │
|
||||||
│ ▓▓ ██ │
|
│ ▓▓ ██ │
|
||||||
@@ -20,7 +19,6 @@ const games = [
|
|||||||
id: 'pacman',
|
id: 'pacman',
|
||||||
name: 'Pac-Man',
|
name: 'Pac-Man',
|
||||||
description: 'Navigate the maze, eat dots, avoid ghosts',
|
description: 'Navigate the maze, eat dots, avoid ghosts',
|
||||||
hasMultiplayer: true,
|
|
||||||
ascii: `┌────────┐
|
ascii: `┌────────┐
|
||||||
│· · ᗣ · │
|
│· · ᗣ · │
|
||||||
│ ┌─┐ ┌─┐│
|
│ ┌─┐ ┌─┐│
|
||||||
@@ -32,7 +30,6 @@ const games = [
|
|||||||
id: 'snake',
|
id: 'snake',
|
||||||
name: 'Snake',
|
name: 'Snake',
|
||||||
description: 'Eat food, grow longer, dont hit yourself',
|
description: 'Eat food, grow longer, dont hit yourself',
|
||||||
hasMultiplayer: true,
|
|
||||||
ascii: `┌────────┐
|
ascii: `┌────────┐
|
||||||
│ │
|
│ │
|
||||||
│ ●■■■ │
|
│ ●■■■ │
|
||||||
@@ -44,7 +41,6 @@ const games = [
|
|||||||
id: 'breakout',
|
id: 'breakout',
|
||||||
name: 'Breakout',
|
name: 'Breakout',
|
||||||
description: 'Break bricks with a bouncing ball',
|
description: 'Break bricks with a bouncing ball',
|
||||||
hasMultiplayer: true,
|
|
||||||
ascii: `┌────────┐
|
ascii: `┌────────┐
|
||||||
│████████│
|
│████████│
|
||||||
│▓▓▓▓▓▓▓▓│
|
│▓▓▓▓▓▓▓▓│
|
||||||
@@ -110,12 +106,6 @@ const Games = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Multiplayer Badge - using primary colors instead of purple */}
|
|
||||||
{game.hasMultiplayer && (
|
|
||||||
<span className="absolute top-3 right-3 font-pixel text-[10px] text-primary border border-primary/60 bg-primary/10 px-2 py-1 rounded-sm">
|
|
||||||
2P
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
+19
-16
@@ -339,31 +339,26 @@ const Tetris = () => {
|
|||||||
const movePlayer = useCallback((playerNum: 1 | 2, action: 'left' | 'right' | 'down' | 'rotate' | 'drop') => {
|
const movePlayer = useCallback((playerNum: 1 | 2, action: 'left' | 'right' | 'down' | 'rotate' | 'drop') => {
|
||||||
if (gameOver || isPaused || !gameStarted || gameMode !== '2p') return;
|
if (gameOver || isPaused || !gameStarted || gameMode !== '2p') return;
|
||||||
const setPlayer = playerNum === 1 ? setPlayer1 : setPlayer2;
|
const setPlayer = playerNum === 1 ? setPlayer1 : setPlayer2;
|
||||||
const player = playerNum === 1 ? player1 : player2;
|
|
||||||
const isP2 = playerNum === 2;
|
const isP2 = playerNum === 2;
|
||||||
if (player.gameOver) return;
|
|
||||||
|
|
||||||
setPlayer(prev => {
|
setPlayer(prev => {
|
||||||
|
if (prev.gameOver) return prev;
|
||||||
let newPiece = { ...prev.piece };
|
let newPiece = { ...prev.piece };
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'left':
|
case 'left':
|
||||||
newPiece.x--;
|
newPiece.x--;
|
||||||
if (!isValidMove(newPiece, prev.board)) return prev;
|
if (!isValidMove(newPiece, prev.board)) return prev;
|
||||||
playSound('hover');
|
|
||||||
return { ...prev, piece: newPiece };
|
return { ...prev, piece: newPiece };
|
||||||
case 'right':
|
case 'right':
|
||||||
newPiece.x++;
|
newPiece.x++;
|
||||||
if (!isValidMove(newPiece, prev.board)) return prev;
|
if (!isValidMove(newPiece, prev.board)) return prev;
|
||||||
playSound('hover');
|
|
||||||
return { ...prev, piece: newPiece };
|
return { ...prev, piece: newPiece };
|
||||||
case 'rotate':
|
case 'rotate':
|
||||||
newPiece.shape = rotate(prev.piece.shape);
|
newPiece.shape = rotate(prev.piece.shape);
|
||||||
if (!isValidMove(newPiece, prev.board)) return prev;
|
if (!isValidMove(newPiece, prev.board)) return prev;
|
||||||
playSound('hover');
|
|
||||||
return { ...prev, piece: newPiece };
|
return { ...prev, piece: newPiece };
|
||||||
case 'drop':
|
case 'drop':
|
||||||
while (isValidMove({ ...newPiece, y: newPiece.y + 1 }, prev.board)) newPiece.y++;
|
while (isValidMove({ ...newPiece, y: newPiece.y + 1 }, prev.board)) newPiece.y++;
|
||||||
playSound('click');
|
|
||||||
return { ...prev, piece: newPiece };
|
return { ...prev, piece: newPiece };
|
||||||
case 'down':
|
case 'down':
|
||||||
newPiece.y++;
|
newPiece.y++;
|
||||||
@@ -373,12 +368,9 @@ const Tetris = () => {
|
|||||||
const { board: clearedBoard, cleared } = clearLines(mergedBoard);
|
const { board: clearedBoard, cleared } = clearLines(mergedBoard);
|
||||||
const newScore = prev.score + (cleared > 0 ? cleared * 100 * cleared : 0);
|
const newScore = prev.score + (cleared > 0 ? cleared * 100 * cleared : 0);
|
||||||
const newLines = prev.lines + cleared;
|
const newLines = prev.lines + cleared;
|
||||||
if (cleared > 0) playSound('success');
|
|
||||||
else playSound('click');
|
|
||||||
const newTetromino = prev.nextPiece;
|
const newTetromino = prev.nextPiece;
|
||||||
const nextNext = randomTetromino(isP2, prev.nextPiece.shape);
|
const nextNext = randomTetromino(isP2, prev.nextPiece.shape);
|
||||||
if (!isValidMove(newTetromino, clearedBoard)) {
|
if (!isValidMove(newTetromino, clearedBoard)) {
|
||||||
playSound('error');
|
|
||||||
return { ...prev, board: clearedBoard, score: newScore, lines: newLines, gameOver: true };
|
return { ...prev, board: clearedBoard, score: newScore, lines: newLines, gameOver: true };
|
||||||
}
|
}
|
||||||
return { ...prev, board: clearedBoard, piece: newTetromino, nextPiece: nextNext, score: newScore, lines: newLines };
|
return { ...prev, board: clearedBoard, piece: newTetromino, nextPiece: nextNext, score: newScore, lines: newLines };
|
||||||
@@ -386,7 +378,7 @@ const Tetris = () => {
|
|||||||
}
|
}
|
||||||
return prev;
|
return prev;
|
||||||
});
|
});
|
||||||
}, [gameOver, isPaused, gameStarted, gameMode, player1, player2, isValidMove, mergePiece, clearLines, playSound]);
|
}, [gameOver, isPaused, gameStarted, gameMode, isValidMove, mergePiece, clearLines]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (gameMode !== '2p' || !gameStarted) return;
|
if (gameMode !== '2p' || !gameStarted) return;
|
||||||
@@ -599,7 +591,16 @@ const Tetris = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex gap-4 items-start">
|
<div className="flex gap-6 items-start">
|
||||||
|
{/* P1 Next Piece - Left side */}
|
||||||
|
<div className="flex flex-col items-center gap-2 min-w-[60px]">
|
||||||
|
<p className="font-pixel text-[10px] text-primary/70">P1 Next</p>
|
||||||
|
<div className="border border-primary/30 p-2 bg-background/40">
|
||||||
|
{renderNextPiece(player1.nextPiece)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* P1 Board */}
|
||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex flex-col items-center gap-2">
|
||||||
<p className="font-minecraft text-lg text-primary">P1 <span className="text-xs text-foreground/60">(WASD + Q)</span></p>
|
<p className="font-minecraft text-lg text-primary">P1 <span className="text-xs text-foreground/60">(WASD + Q)</span></p>
|
||||||
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard2P(player1, 'border-primary/20')}</div>
|
<div className="border-2 border-primary box-glow p-1 bg-background/80">{renderBoard2P(player1, 'border-primary/20')}</div>
|
||||||
@@ -607,11 +608,9 @@ const Tetris = () => {
|
|||||||
<div><p className="font-pixel text-[10px] text-foreground/60">Score</p><p className="font-minecraft text-lg text-primary">{player1.score}</p></div>
|
<div><p className="font-pixel text-[10px] text-foreground/60">Score</p><p className="font-minecraft text-lg text-primary">{player1.score}</p></div>
|
||||||
<div><p className="font-pixel text-[10px] text-foreground/60">Lines</p><p className="font-minecraft text-lg text-primary">{player1.lines}</p></div>
|
<div><p className="font-pixel text-[10px] text-foreground/60">Lines</p><p className="font-minecraft text-lg text-primary">{player1.lines}</p></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-primary/30 p-2 bg-background/40">
|
|
||||||
<p className="font-pixel text-[8px] text-foreground/40">Next</p>
|
|
||||||
{renderNextPiece(player1.nextPiece)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* P2 Board */}
|
||||||
<div className="flex flex-col items-center gap-2">
|
<div className="flex flex-col items-center gap-2">
|
||||||
<p className="font-minecraft text-lg text-secondary">P2 <span className="text-xs text-foreground/60">(Arrows + /)</span></p>
|
<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="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>
|
||||||
@@ -619,8 +618,12 @@ const Tetris = () => {
|
|||||||
<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">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><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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* P2 Next Piece - Right side */}
|
||||||
|
<div className="flex flex-col items-center gap-2 min-w-[60px]">
|
||||||
|
<p className="font-pixel text-[10px] text-secondary/70">P2 Next</p>
|
||||||
<div className="border border-secondary/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)}
|
{renderNextPiece(player2.nextPiece)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user