import React , { useCallback , useReducer , useRef , useEffect } from 'react' ; import { useGameLoop , useInputEvent , useScene } from 'react-phaser-fiber' ; import Ball from './Ball' ; import Block from './Block' ; import Paddle from './Paddle' ; export default function Breakout ( ) { const scene = useScene ( ) ; const paddleRef = useRef < Phaser . Physics . Arcade . Image > ( null ) ; const ballRef = useRef < Phaser . Physics . Arcade . Image > ( null ) ; const [ state , dispatch ] = useReducer ( reducer , defaultState ) ; useEffect ( ( ) => { scene . physics . world . setBoundsCollision ( true , true , true , false ) ; } , [ scene ] ) ; useGameLoop ( useCallback ( ( ) => { if ( state . blocks . length === 0 ) { if ( paddleRef . current && ballRef . current ) { ballRef . current . setVelocity ( 0 , 0 ) ; ballRef . current . setPosition ( paddleRef . current . x , paddleRef . current . y - 48 ) ; dispatch ( { type : 'RESET_GAME' } ) ; } } } , [ state . blocks . length ] ) ) ; useInputEvent ( 'pointerdown' , useCallback ( ( ) => { if ( ballRef . current && ! state . isBallActive ) { ballRef . current . setVelocity ( - 75 , - 600 ) ; dispatch ( { type : 'PLAY' } ) ; } } , [ state . isBallActive ] ) ) ; return ( < > < Paddle ref = { paddleRef } initialX = { 400 } initialY = { 700 } / > < Ball ref = { ballRef } paddleRef = { paddleRef } snapToPaddle = { ! state . isBallActive } onReset = { ( ) => { if ( ballRef . current && ballRef . current . y > 800 ) { ballRef . current . setVelocity ( 0 ) ; dispatch ( { type : 'RESET_BALL' } ) ; } } } /> { state . blocks . map ( ( { key , x , y , frame } ) => ( < Block key = { key } x = { x + 116 } y = { y + 200 } frame = { frame } onBallHit = { ( ) => { dispatch ( { type : 'BLOCK_HIT' , payload : key } ) ; } } />))} < />); } interface BreakoutState { isBallActive : boolean ; blocks : Array < { x : number ; y : number ; frame : string ; key : number ; } > ; } const defaultState = { isBallActive : false , blocks : Array . from ( { length : 60 } ) . map ( ( _ , index ) => { const blockFrames = [ 'blue1' , 'red1' , 'green1' , 'yellow1' , 'silver1' , 'purple1' , ] ; return { x : ( index % 10 ) * 64 , y : 10 * Math . floor ( index / 10 ) * 3.2 , frame : blockFrames [ Math . floor ( index / 10 ) ] , key : index , } ; } ) , } ; function reducer ( state , action ) { switch ( action . type ) { case 'RESET_GAME' : { return defaultState ; } case 'RESET_BALL' : { return { ... state , isBallActive : false , } ; } case 'PLAY' : { return { ... state , isBallActive : true , } ; } case 'BLOCK_HIT' : { return { ... state , blocks : state . blocks . filter ( block => block . key !== action . payload ) , } ; } } return state ; }