diff --git a/src/blockpuzzle/components/ArrowIcon.tsx b/src/blockpuzzle/components/ArrowIcon.tsx new file mode 100644 index 0000000..7304371 --- /dev/null +++ b/src/blockpuzzle/components/ArrowIcon.tsx @@ -0,0 +1,23 @@ +import classNames from "classnames"; + +interface IconProps { + className?: string; +} + +const ArrowIcon = ({ className }: IconProps) => { + return ( + + + + ); +}; + +export default ArrowIcon diff --git a/src/blockpuzzle/components/Game.tsx b/src/blockpuzzle/components/Game.tsx index c96286c..e8aaa3c 100644 --- a/src/blockpuzzle/components/Game.tsx +++ b/src/blockpuzzle/components/Game.tsx @@ -70,10 +70,10 @@ const Game = forwardRef(function Game(props, ref) { )) )} + )} - ); }); diff --git a/src/blockpuzzle/components/Gamepad.tsx b/src/blockpuzzle/components/Gamepad.tsx index f2e95fa..5a7281d 100644 --- a/src/blockpuzzle/components/Gamepad.tsx +++ b/src/blockpuzzle/components/Gamepad.tsx @@ -1,12 +1,14 @@ -import { useCallback, useEffect, useRef } from "react"; +import { MouseEvent, useEffect, useRef } from "react"; import { acceptedKeys, idleInput } from "../constants"; import { useGameStore } from "./GameClient"; import { GameInput } from "../types"; -import { clearInterval } from "timers"; +import ArrowIcon from "./ArrowIcon" import { timeout } from "../tools"; +import RotateIcon from "./RotateIcon"; +import React from "react"; const buttonStyle = - "border-white border-[1px] rounded aspect-square text-center align-middle w-[64px] first:mr-3 flex justify-center items-center text-[32px] active:bg-white active:text-black select-none"; + "border-white border-[1px] rounded aspect-square text-center align-middle w-[64px] first:mr-3 flex justify-center items-center text-[32px] active:bg-white active:text-black select-none group"; const isMobile = () => { return navigator.userAgent.match(/mobile|iphone|android|ipad/i); @@ -64,7 +66,7 @@ const Gamepad = () => { while (isPressed) { input(inputObj); - await timeout(33); + await timeout(16); } }, end: () => { @@ -102,7 +104,9 @@ const Gamepad = () => { }; }, [input]); - const handleClick = (inputObj: GameInput) => () => { + const handleClick = (inputObj: GameInput) => (event: MouseEvent) => { + event.stopPropagation(); + if (isMobile() && inputObj.up) { input(inputObj); } @@ -118,25 +122,25 @@ const Gamepad = () => { const downClick = handleClick({ ...idleInput, down: true }); return ( -
+
); }; -export default Gamepad; +export default React.memo(Gamepad); diff --git a/src/blockpuzzle/components/RotateIcon.tsx b/src/blockpuzzle/components/RotateIcon.tsx new file mode 100644 index 0000000..b16fd73 --- /dev/null +++ b/src/blockpuzzle/components/RotateIcon.tsx @@ -0,0 +1,32 @@ +import classNames from "classnames"; + +interface IconProps { + className?: string; +} + +const RotateIcon = ({ className }: IconProps) => { + return ( + + + + + ); +}; + +export default RotateIcon; diff --git a/src/blockpuzzle/game.ts b/src/blockpuzzle/game.ts index 75705ba..d4ae187 100644 --- a/src/blockpuzzle/game.ts +++ b/src/blockpuzzle/game.ts @@ -369,7 +369,7 @@ export function clearCompleteRows(state: State) { return { grid: newGrid, - score: state.score + scorePerRow * fullRows.length * fullRows. length, + score: state.score + state.level * scorePerRow * fullRows.length * fullRows.length, }; } diff --git a/src/blockpuzzle/store.ts b/src/blockpuzzle/store.ts index 557b3d2..e2c23ed 100644 --- a/src/blockpuzzle/store.ts +++ b/src/blockpuzzle/store.ts @@ -72,14 +72,10 @@ const store: (callbacks: GameCallbacks) => StateCreator = return spawnBag; }; - const limitedMove = throttle((input: GameInput) => get().move(input), 100, { - leading: true, - }); - - const limitedDrop = throttle(() => get().drop(), 50, { leading: true }); - const limitedRotate = throttle(() => get().rotateClockwise(), 150, { - leading: true, - }); + const limitedMove = throttle((input: GameInput) => get().move(input), 50); + + const limitedDrop = throttle(() => get().drop(), 30); + const limitedRotate = throttle(() => get().rotateClockwise(), 100); return { ...getInitialState(),