Changes
This commit is contained in:
+22
-3
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useSettings } from '@/contexts/SettingsContext';
|
||||
import { useAchievements } from '@/contexts/AchievementsContext';
|
||||
@@ -8,6 +9,7 @@ import { Maximize2, Minimize2 } from 'lucide-react';
|
||||
import { useBrowserFullscreen } from '@/hooks/useGameDimensions';
|
||||
import GameTouchButton from '@/components/GameTouchButton';
|
||||
import { MobileControlsDock, MobileControlsSpacer } from '@/components/MobileControlsDock';
|
||||
import MatrixCursor from '@/components/MatrixCursor';
|
||||
|
||||
const PADDLE_HEIGHT = 14;
|
||||
const BRICK_ROWS = 6;
|
||||
@@ -132,6 +134,15 @@ const Breakout = () => {
|
||||
if (gameStarted && isMobile && !isFullscreen) { setIsFullscreen(true); enterFullscreen(); }
|
||||
}, [gameStarted, isMobile, isFullscreen, enterFullscreen]);
|
||||
|
||||
// Prevent page scroll while in fullscreen mode (portal overlays the viewport)
|
||||
useEffect(() => {
|
||||
if (typeof document === 'undefined') return;
|
||||
if (!isFullscreen) return;
|
||||
const prevOverflow = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
return () => { document.body.style.overflow = prevOverflow; };
|
||||
}, [isFullscreen]);
|
||||
|
||||
const toggleFullscreen = async () => {
|
||||
if (!isFullscreen) { setIsFullscreen(true); await enterFullscreen(); }
|
||||
else { setIsFullscreen(false); await exitFullscreen(); }
|
||||
@@ -183,7 +194,8 @@ const Breakout = () => {
|
||||
}, []);
|
||||
|
||||
const resetBall = useCallback((ballRefToReset: React.MutableRefObject<{x: number, y: number, dx: number, dy: number}>, paddleRefToReset: React.MutableRefObject<number>, lvl: number) => {
|
||||
const speed = 2.5 + lvl * 0.3;
|
||||
// Slower base speed for classic Breakout feel (was 2.5)
|
||||
const speed = 1.8 + lvl * 0.2;
|
||||
ballRefToReset.current = { x: canvasSize.width / 2, y: canvasSize.height - 60, dx: (Math.random() > 0.5 ? 1 : -1) * speed, dy: -speed };
|
||||
paddleRefToReset.current = canvasSize.width / 2 - paddleWidth / 2;
|
||||
}, [canvasSize.width, canvasSize.height, paddleWidth]);
|
||||
@@ -538,9 +550,11 @@ const Breakout = () => {
|
||||
|
||||
if (showGlitchCrash) return <GlitchCrash onComplete={() => window.location.reload()} />;
|
||||
|
||||
return (
|
||||
const gameUi = (
|
||||
<motion.div ref={gameRef} tabIndex={0} initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.5 }}
|
||||
className={`flex flex-col outline-none ${isFullscreen ? 'fixed inset-0 z-50 bg-background p-4' : 'h-full'}`}>
|
||||
className={`flex flex-col outline-none ${isFullscreen ? 'fixed inset-0 z-[100] bg-background p-4 w-screen h-screen' : 'h-full'}`}>
|
||||
{/* Render cursor inside portal for fullscreen */}
|
||||
{isFullscreen && <MatrixCursor />}
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<Link to="/games" className="font-pixel text-sm text-foreground/50 hover:text-primary transition-colors">{'<'} Back</Link>
|
||||
@@ -712,6 +726,11 @@ const Breakout = () => {
|
||||
)}
|
||||
</motion.div>
|
||||
);
|
||||
|
||||
// Portal to body for true fullscreen, escaping MainLayout transforms
|
||||
return isFullscreen && typeof document !== 'undefined'
|
||||
? createPortal(gameUi, document.body)
|
||||
: gameUi;
|
||||
};
|
||||
|
||||
export default Breakout;
|
||||
|
||||
Reference in New Issue
Block a user