Fixed targetPreview
This commit is contained in:
parent
986555a368
commit
b3695916a0
15 changed files with 237 additions and 302 deletions
|
@ -1,23 +1,22 @@
|
||||||
import { Position, MouseCursor } from "../../interfaces/frontend"
|
import { MouseCursor } from "../../interfaces/frontend"
|
||||||
|
import { count } from "./Gamefield"
|
||||||
import { borderCN, cornerCN, fieldIndex } from "@lib/utils/helpers"
|
import { borderCN, cornerCN, fieldIndex } from "@lib/utils/helpers"
|
||||||
import { CSSProperties, Dispatch, SetStateAction } from "react"
|
import { CSSProperties, Dispatch, SetStateAction } from "react"
|
||||||
|
|
||||||
type TilesType = {
|
type TilesType = {
|
||||||
key: number
|
key: number
|
||||||
isGameTile: boolean
|
isGameTile: boolean
|
||||||
classNameString: string
|
className: string
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
}
|
}
|
||||||
|
|
||||||
function BorderTiles({
|
function BorderTiles({
|
||||||
props: { count, settingTarget, setMouseCursor, setLastLeftTile },
|
props: { settingTarget, setMouseCursor },
|
||||||
}: {
|
}: {
|
||||||
props: {
|
props: {
|
||||||
count: number
|
|
||||||
settingTarget: (isGameTile: boolean, x: number, y: number) => void
|
settingTarget: (isGameTile: boolean, x: number, y: number) => void
|
||||||
setMouseCursor: Dispatch<SetStateAction<MouseCursor>>
|
setMouseCursor: Dispatch<SetStateAction<MouseCursor>>
|
||||||
setLastLeftTile: Dispatch<SetStateAction<Position>>
|
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
let tilesProperties: TilesType[] = []
|
let tilesProperties: TilesType[] = []
|
||||||
|
@ -31,10 +30,10 @@ function BorderTiles({
|
||||||
const classNames = ["border-tile"]
|
const classNames = ["border-tile"]
|
||||||
if (borderType) classNames.push("edge", borderType)
|
if (borderType) classNames.push("edge", borderType)
|
||||||
if (isGameTile) classNames.push("game-tile")
|
if (isGameTile) classNames.push("game-tile")
|
||||||
const classNameString = classNames.join(" ")
|
const className = classNames.join(" ")
|
||||||
tilesProperties.push({
|
tilesProperties.push({
|
||||||
key,
|
key,
|
||||||
classNameString,
|
className,
|
||||||
isGameTile,
|
isGameTile,
|
||||||
x: x + 1,
|
x: x + 1,
|
||||||
y: y + 1,
|
y: y + 1,
|
||||||
|
@ -44,17 +43,16 @@ function BorderTiles({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{tilesProperties.map(({ key, classNameString, isGameTile, x, y }) => {
|
{tilesProperties.map(({ key, className, isGameTile, x, y }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={key}
|
key={key}
|
||||||
className={classNameString}
|
className={className}
|
||||||
style={{ "--x": x, "--y": y } as CSSProperties}
|
style={{ "--x": x, "--y": y } as CSSProperties}
|
||||||
onClick={() => settingTarget(isGameTile, x, y)}
|
onClick={() => settingTarget(isGameTile, x, y)}
|
||||||
onMouseEnter={() =>
|
onMouseEnter={() =>
|
||||||
setMouseCursor({ x, y, shouldShow: isGameTile })
|
setMouseCursor({ x, y, shouldShow: isGameTile })
|
||||||
}
|
}
|
||||||
onMouseLeave={() => setLastLeftTile({ x, y })}
|
|
||||||
></div>
|
></div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -1,35 +1,98 @@
|
||||||
// import Bluetooth from './Bluetooth'
|
// import Bluetooth from './Bluetooth'
|
||||||
// import FogImages from './FogImages'
|
// import FogImages from './FogImages'
|
||||||
|
import { Hit, MouseCursor, Target } from "../../interfaces/frontend"
|
||||||
import Labeling from "./Labeling"
|
import Labeling from "./Labeling"
|
||||||
import Ships from "./Ships"
|
import Ships from "./Ships"
|
||||||
import useGameEvent from "@hooks/useGameEvent"
|
import BorderTiles from "@components/Gamefield/BorderTiles"
|
||||||
import { CSSProperties } from "react"
|
import EventBar from "@components/Gamefield/EventBar"
|
||||||
|
import HitElems from "@components/Gamefield/HitElems"
|
||||||
|
import Targets from "@components/Gamefield/Targets"
|
||||||
|
import {
|
||||||
|
hitReducer,
|
||||||
|
initlialTarget,
|
||||||
|
initlialTargetPreview,
|
||||||
|
initlialMouseCursor,
|
||||||
|
overlapsWithAnyBorder,
|
||||||
|
isHit,
|
||||||
|
composeTargetTiles,
|
||||||
|
} from "@lib/utils/helpers"
|
||||||
|
import { CSSProperties, useCallback } from "react"
|
||||||
|
import { useEffect, useReducer, useState } from "react"
|
||||||
|
|
||||||
|
export const count = 12
|
||||||
|
|
||||||
function Gamefield() {
|
function Gamefield() {
|
||||||
const count = 12
|
const [target, setTarget] = useState<Target>(initlialTarget)
|
||||||
const { BorderTiles, HitElems, Targets, EventBar } = useGameEvent(count)
|
const [targetPreview, setTargetPreview] = useState<Target>(
|
||||||
|
initlialTargetPreview
|
||||||
|
)
|
||||||
|
const [mouseCursor, setMouseCursor] =
|
||||||
|
useState<MouseCursor>(initlialMouseCursor)
|
||||||
|
const [hits, DispatchHits] = useReducer(hitReducer, [] as Hit[])
|
||||||
|
const [mode, setMode] = useState(0)
|
||||||
|
|
||||||
|
const settingTarget = useCallback(
|
||||||
|
(isGameTile: boolean, x: number, y: number) => {
|
||||||
|
if (!isGameTile || isHit(x, y, hits).length) return
|
||||||
|
setTarget((t) => {
|
||||||
|
if (t.x === x && t.y === y && t.show) {
|
||||||
|
DispatchHits({
|
||||||
|
type: "fireMissile",
|
||||||
|
payload: { hit: (x + y) % 2 !== 0, x, y },
|
||||||
|
})
|
||||||
|
return { preview: false, show: false, x, y }
|
||||||
|
} else {
|
||||||
|
const target = { show: true, x, y }
|
||||||
|
if (overlapsWithAnyBorder(target, mode)) return t
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[hits, mode]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(1)
|
||||||
|
const { x, y, show } = target
|
||||||
|
const { shouldShow, ...position } = mouseCursor
|
||||||
|
if (!shouldShow || overlapsWithAnyBorder(position, mode))
|
||||||
|
setTargetPreview((e) => ({ ...e, show: false }))
|
||||||
|
else {
|
||||||
|
console.log(2, position)
|
||||||
|
setTargetPreview({
|
||||||
|
...position,
|
||||||
|
show: !show || x !== position.x || y !== position.y,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [mode, mouseCursor, target])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="gamefield">
|
<div id="gamefield">
|
||||||
{/* <Bluetooth /> */}
|
{/* <Bluetooth /> */}
|
||||||
<div id="game-frame" style={{ "--i": count } as CSSProperties}>
|
<div
|
||||||
|
id="game-frame"
|
||||||
|
style={{ "--i": count } as CSSProperties}
|
||||||
|
onMouseLeave={() =>
|
||||||
|
setMouseCursor((e) => ({ ...e, shouldShow: false }))
|
||||||
|
}
|
||||||
|
>
|
||||||
{/* Bordes */}
|
{/* Bordes */}
|
||||||
<BorderTiles />
|
<BorderTiles props={{ settingTarget, setMouseCursor }} />
|
||||||
|
|
||||||
{/* Collumn lettes and row numbers */}
|
{/* Collumn lettes and row numbers */}
|
||||||
<Labeling count={count} />
|
<Labeling count={count} />
|
||||||
|
|
||||||
{/* Ships */}
|
{/* Ships */}
|
||||||
<Ships />
|
<Ships />
|
||||||
|
<HitElems hits={hits} />
|
||||||
<HitElems />
|
|
||||||
|
|
||||||
{/* Fog images */}
|
{/* Fog images */}
|
||||||
{/* <FogImages /> */}
|
{/* <FogImages /> */}
|
||||||
<Targets />
|
|
||||||
|
<Targets props={{ target, targetPreview, mode, hits }} />
|
||||||
{/* <span id='dev-debug' style={{gridArea: '1 / 12 / 1 / 15', backgroundColor: 'red', zIndex: 3} as CSSProperties}>Debug</span> */}
|
{/* <span id='dev-debug' style={{gridArea: '1 / 12 / 1 / 15', backgroundColor: 'red', zIndex: 3} as CSSProperties}>Debug</span> */}
|
||||||
</div>
|
</div>
|
||||||
<EventBar />
|
<EventBar props={{ setMode, setTarget }} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,11 @@ export interface PointerProps extends Target, TargetList {
|
||||||
}
|
}
|
||||||
|
|
||||||
function GamefieldPointer({
|
function GamefieldPointer({
|
||||||
props: { preview, x, y, show, type, edges, imply },
|
props: { x, y, show, type, edges, imply },
|
||||||
|
preview,
|
||||||
}: {
|
}: {
|
||||||
props: PointerProps
|
props: PointerProps
|
||||||
|
preview?: boolean
|
||||||
}) {
|
}) {
|
||||||
const isRadar = type === "radar"
|
const isRadar = type === "radar"
|
||||||
const style = !(isRadar && !edges.filter((s) => s).length)
|
const style = !(isRadar && !edges.filter((s) => s).length)
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
import { Target } from "../../interfaces/frontend"
|
import { Hit, Target } from "../../interfaces/frontend"
|
||||||
import GamefieldPointer, { PointerProps } from "./GamefieldPointer"
|
import GamefieldPointer from "./GamefieldPointer"
|
||||||
|
import { composeTargetTiles } from "@lib/utils/helpers"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
function Targets({
|
function Targets({
|
||||||
props: { composeTargetTiles, target, targetPreview },
|
props: { target, targetPreview, mode, hits },
|
||||||
}: {
|
}: {
|
||||||
props: {
|
props: {
|
||||||
composeTargetTiles: (target: Target) => PointerProps[]
|
|
||||||
target: Target
|
target: Target
|
||||||
targetPreview: Target
|
targetPreview: Target
|
||||||
|
mode: number
|
||||||
|
hits: Hit[]
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{[
|
{[
|
||||||
...composeTargetTiles(target).map((props, i) => (
|
...composeTargetTiles(target, mode, hits).map((props, i) => (
|
||||||
<GamefieldPointer key={"t" + i} props={props} />
|
<GamefieldPointer key={"t" + i} props={props} />
|
||||||
)),
|
)),
|
||||||
...composeTargetTiles(targetPreview).map((props, i) => (
|
...composeTargetTiles(targetPreview, mode, hits).map((props, i) => (
|
||||||
<GamefieldPointer key={"p" + i} props={props} />
|
<GamefieldPointer key={"p" + i} props={props} preview />
|
||||||
)),
|
)),
|
||||||
]}
|
]}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -9,9 +9,26 @@ import { useSession } from "next-auth/react"
|
||||||
import { useRouter } from "next/router"
|
import { useRouter } from "next/router"
|
||||||
import { Fragment, useEffect, useState } from "react"
|
import { Fragment, useEffect, useState } from "react"
|
||||||
|
|
||||||
|
function WithDots({ children }: { children: string }) {
|
||||||
|
const [dots, setDots] = useState(3)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => setDots((e) => (e % 3) + 1), 1000)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [])
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{children + " "}
|
||||||
|
{Array.from(Array(dots), () => ".").join("")}
|
||||||
|
{Array.from(Array(3 - dots), (_, i) => (
|
||||||
|
<Fragment key={i}> </Fragment>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function LobbyFrame({ openSettings }: { openSettings: () => void }) {
|
function LobbyFrame({ openSettings }: { openSettings: () => void }) {
|
||||||
const { payload, full, leave, reset } = useGameProps()
|
const { payload, full, leave, reset } = useGameProps()
|
||||||
const [dots, setDots] = useState(3)
|
|
||||||
const { isConnected } = useSocket()
|
const { isConnected } = useSocket()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
|
@ -21,12 +38,6 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
|
||||||
socket.emit("update", full)
|
socket.emit("update", full)
|
||||||
}, [full, payload?.game?.id, isConnected])
|
}, [full, payload?.game?.id, isConnected])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (payload?.player2) return
|
|
||||||
const interval = setInterval(() => setDots((e) => (e % 3) + 1), 1000)
|
|
||||||
return () => clearInterval(interval)
|
|
||||||
}, [payload?.player2])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-32 flex flex-col self-stretch rounded-3xl bg-gray-400">
|
<div className="mx-32 flex flex-col self-stretch rounded-3xl bg-gray-400">
|
||||||
<div className="flex items-center justify-between border-b-2 border-slate-900">
|
<div className="flex items-center justify-between border-b-2 border-slate-900">
|
||||||
|
@ -58,11 +69,9 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<p className="font-farro w-96 text-center text-4xl font-medium">
|
<p className="font-farro w-96 text-center text-4xl font-medium">
|
||||||
Warte auf {isConnected ? "Spieler 2" : "Verbindung"}{" "}
|
<WithDots>
|
||||||
{Array.from(Array(dots), () => ".").join("")}
|
{"Warte auf " + (isConnected ? "Spieler 2" : "Verbindung")}
|
||||||
{Array.from(Array(3 - dots), (_, i) => (
|
</WithDots>
|
||||||
<Fragment key={i}> </Fragment>
|
|
||||||
))}
|
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,7 +14,7 @@ function Player({
|
||||||
}) {
|
}) {
|
||||||
const text =
|
const text =
|
||||||
player?.name ?? "Spieler " + (player?.index === "player2" ? "2" : "1")
|
player?.name ?? "Spieler " + (player?.index === "player2" ? "2" : "1")
|
||||||
const primary = userId === player?.id
|
const primary = userId && userId === player?.id
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-96 flex-col items-center gap-16 py-8">
|
<div className="flex w-96 flex-col items-center gap-16 py-8">
|
||||||
|
|
|
@ -1,235 +0,0 @@
|
||||||
import {
|
|
||||||
Hit,
|
|
||||||
Mode,
|
|
||||||
MouseCursor,
|
|
||||||
Target,
|
|
||||||
Position,
|
|
||||||
} from "../interfaces/frontend"
|
|
||||||
import BorderTiles from "@components/Gamefield/BorderTiles"
|
|
||||||
import EventBar from "@components/Gamefield/EventBar"
|
|
||||||
import type { PointerProps } from "@components/Gamefield/GamefieldPointer"
|
|
||||||
import HitElems from "@components/Gamefield/HitElems"
|
|
||||||
import Targets from "@components/Gamefield/Targets"
|
|
||||||
import {
|
|
||||||
hitReducer,
|
|
||||||
initlialLastLeftTile,
|
|
||||||
initlialTarget,
|
|
||||||
initlialTargetPreview,
|
|
||||||
initlialMouseCursor,
|
|
||||||
} from "@lib/utils/helpers"
|
|
||||||
import { useCallback, useEffect, useReducer, useState } from "react"
|
|
||||||
|
|
||||||
const modes: Mode[] = [
|
|
||||||
{
|
|
||||||
pointerGrid: Array.from(Array(3), () => Array.from(Array(3))),
|
|
||||||
type: "radar",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pointerGrid: Array.from(Array(3), () => Array.from(Array(1))),
|
|
||||||
type: "htorpedo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pointerGrid: Array.from(Array(1), () => Array.from(Array(3))),
|
|
||||||
type: "vtorpedo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pointerGrid: Array.from(Array(1), () => Array.from(Array(1))),
|
|
||||||
type: "missile",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
function useGameEvent(count: number) {
|
|
||||||
const [lastLeftTile, setLastLeftTile] =
|
|
||||||
useState<Position>(initlialLastLeftTile)
|
|
||||||
const [target, setTarget] = useState<Target>(initlialTarget)
|
|
||||||
const [eventReady, setEventReady] = useState(false)
|
|
||||||
const [appearOK, setAppearOK] = useState(false)
|
|
||||||
const [targetPreview, setTargetPreview] = useState<Target>(
|
|
||||||
initlialTargetPreview
|
|
||||||
)
|
|
||||||
const [mouseCursor, setMouseCursor] =
|
|
||||||
useState<MouseCursor>(initlialMouseCursor)
|
|
||||||
const [hits, DispatchHits] = useReducer(hitReducer, [] as Hit[])
|
|
||||||
const [mode, setMode] = useState(0)
|
|
||||||
|
|
||||||
const targetList = useCallback(
|
|
||||||
(target: Position) => {
|
|
||||||
const { pointerGrid, type } = modes[mode]
|
|
||||||
const xLength = pointerGrid.length
|
|
||||||
const yLength = pointerGrid[0].length
|
|
||||||
const { x: targetX, y: targetY } = target
|
|
||||||
return pointerGrid
|
|
||||||
.map((arr, i) => {
|
|
||||||
return arr.map((_, i2) => {
|
|
||||||
const relativeX = -Math.floor(xLength / 2) + i
|
|
||||||
const relativeY = -Math.floor(yLength / 2) + i2
|
|
||||||
const x = targetX + (relativeX ?? 0)
|
|
||||||
const y = targetY + (relativeY ?? 0)
|
|
||||||
return {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
type,
|
|
||||||
edges: [
|
|
||||||
i === 0 ? "left" : "",
|
|
||||||
i === xLength - 1 ? "right" : "",
|
|
||||||
i2 === 0 ? "top" : "",
|
|
||||||
i2 === yLength - 1 ? "bottom" : "",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.reduce((prev, curr) => [...prev, ...curr], [])
|
|
||||||
},
|
|
||||||
[mode]
|
|
||||||
)
|
|
||||||
|
|
||||||
const isHit = useCallback(
|
|
||||||
(x: number, y: number) => {
|
|
||||||
return hits.filter((h) => h.x === x && h.y === y)
|
|
||||||
},
|
|
||||||
[hits]
|
|
||||||
)
|
|
||||||
|
|
||||||
const settingTarget = useCallback(
|
|
||||||
(isGameTile: boolean, x: number, y: number) => {
|
|
||||||
if (!isGameTile || isHit(x, y).length) return
|
|
||||||
setMouseCursor((e) => ({ ...e, shouldShow: false }))
|
|
||||||
setTarget((t) => {
|
|
||||||
if (t.x === x && t.y === y && t.show) {
|
|
||||||
DispatchHits({
|
|
||||||
type: "fireMissile",
|
|
||||||
payload: { hit: (x + y) % 2 !== 0, x, y },
|
|
||||||
})
|
|
||||||
return { preview: false, show: false, x, y }
|
|
||||||
} else {
|
|
||||||
const target = { preview: false, show: true, x, y }
|
|
||||||
const hasAnyBorder = targetList(target).filter(({ x, y }) =>
|
|
||||||
isBorder(x, y, count)
|
|
||||||
).length
|
|
||||||
if (hasAnyBorder) return t
|
|
||||||
return target
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
[count, isHit, targetList]
|
|
||||||
)
|
|
||||||
|
|
||||||
const isSet = useCallback(
|
|
||||||
(x: number, y: number) => {
|
|
||||||
return (
|
|
||||||
!!targetList(target).filter((field) => x === field.x && y === field.y)
|
|
||||||
.length && target.show
|
|
||||||
)
|
|
||||||
},
|
|
||||||
[target, targetList]
|
|
||||||
)
|
|
||||||
|
|
||||||
const composeTargetTiles = useCallback(
|
|
||||||
(target: Target): PointerProps[] => {
|
|
||||||
const { preview, show } = target
|
|
||||||
const result = targetList(target).map(({ x, y, type, edges }) => {
|
|
||||||
return {
|
|
||||||
preview,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
show,
|
|
||||||
type,
|
|
||||||
edges,
|
|
||||||
imply: !!isHit(x, y).length || (!!isSet(x, y) && preview),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
},
|
|
||||||
[isHit, isSet, targetList]
|
|
||||||
)
|
|
||||||
|
|
||||||
// handle visibility and position change of targetPreview
|
|
||||||
useEffect(() => {
|
|
||||||
const { show, x, y } = targetPreview
|
|
||||||
// if mouse has moved too quickly and last event was entering and leaving the same field, it must have gone outside the grid
|
|
||||||
const hasLeft = x === lastLeftTile.x && y === lastLeftTile.y
|
|
||||||
const isSet = x === target.x && y === target.y && target.show
|
|
||||||
|
|
||||||
if (show && !appearOK) setTargetPreview((e) => ({ ...e, show: false }))
|
|
||||||
if (
|
|
||||||
!show &&
|
|
||||||
mouseCursor.shouldShow &&
|
|
||||||
eventReady &&
|
|
||||||
appearOK &&
|
|
||||||
!isHit(x, y).length &&
|
|
||||||
!isSet &&
|
|
||||||
!hasLeft
|
|
||||||
)
|
|
||||||
setTargetPreview((e) => ({ ...e, show: true }))
|
|
||||||
}, [
|
|
||||||
targetPreview,
|
|
||||||
mouseCursor.shouldShow,
|
|
||||||
isHit,
|
|
||||||
eventReady,
|
|
||||||
appearOK,
|
|
||||||
lastLeftTile,
|
|
||||||
target,
|
|
||||||
])
|
|
||||||
|
|
||||||
// enable targetPreview event again after 200 ms.
|
|
||||||
useEffect(() => {
|
|
||||||
setEventReady(false)
|
|
||||||
const previewTarget = { x: mouseCursor.x, y: mouseCursor.y }
|
|
||||||
const hasAnyBorder = targetList(previewTarget).filter(({ x, y }) =>
|
|
||||||
isBorder(x, y, count)
|
|
||||||
).length
|
|
||||||
if (targetPreview.show || !appearOK || hasAnyBorder) return
|
|
||||||
const autoTimeout = setTimeout(() => {
|
|
||||||
setTargetPreview((e) => ({ ...e, ...previewTarget }))
|
|
||||||
setEventReady(true)
|
|
||||||
setAppearOK(true)
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
// or abort if state has changed early
|
|
||||||
return () => {
|
|
||||||
clearTimeout(autoTimeout)
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
appearOK,
|
|
||||||
count,
|
|
||||||
mouseCursor.x,
|
|
||||||
mouseCursor.y,
|
|
||||||
targetList,
|
|
||||||
targetPreview.show,
|
|
||||||
])
|
|
||||||
|
|
||||||
// approve targetPreview new position after 200 mil. sec.
|
|
||||||
useEffect(() => {
|
|
||||||
// early return to start cooldown only when about to show up
|
|
||||||
const autoTimeout = setTimeout(
|
|
||||||
() => {
|
|
||||||
setAppearOK(!targetPreview.show)
|
|
||||||
},
|
|
||||||
targetPreview.show ? 500 : 300
|
|
||||||
)
|
|
||||||
|
|
||||||
// or abort if movement is repeated early
|
|
||||||
return () => {
|
|
||||||
clearTimeout(autoTimeout)
|
|
||||||
}
|
|
||||||
}, [targetPreview.show])
|
|
||||||
|
|
||||||
return {
|
|
||||||
BorderTiles: () => (
|
|
||||||
<BorderTiles
|
|
||||||
props={{ count, settingTarget, setMouseCursor, setLastLeftTile }}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
HitElems: () => <HitElems hits={hits} />,
|
|
||||||
Targets: () => (
|
|
||||||
<Targets props={{ composeTargetTiles, target, targetPreview }} />
|
|
||||||
),
|
|
||||||
EventBar: () => <EventBar props={{ setMode, setTarget }} />,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBorder(x: number, y: number, count: number) {
|
|
||||||
return x < 2 || x > count + 1 || y < 2 || y > count + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useGameEvent
|
|
|
@ -3,7 +3,6 @@ export interface Position {
|
||||||
y: number
|
y: number
|
||||||
}
|
}
|
||||||
export interface Target extends Position {
|
export interface Target extends Position {
|
||||||
preview: boolean
|
|
||||||
show: boolean
|
show: boolean
|
||||||
}
|
}
|
||||||
export interface MouseCursor extends Position {
|
export interface MouseCursor extends Position {
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
import type { Hit, HitDispatch } from "../../interfaces/frontend"
|
import type {
|
||||||
|
Hit,
|
||||||
|
HitDispatch,
|
||||||
|
Mode,
|
||||||
|
Position,
|
||||||
|
Target,
|
||||||
|
TargetList,
|
||||||
|
} from "../../interfaces/frontend"
|
||||||
|
import { count } from "@components/Gamefield/Gamefield"
|
||||||
|
import { PointerProps } from "@components/Gamefield/GamefieldPointer"
|
||||||
|
|
||||||
export function borderCN(count: number, x: number, y: number) {
|
export function borderCN(count: number, x: number, y: number) {
|
||||||
if (x === 0) return "left"
|
if (x === 0) return "left"
|
||||||
|
@ -28,10 +37,92 @@ export function hitReducer(formObject: Hit[], action: HitDispatch) {
|
||||||
return formObject
|
return formObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const initlialLastLeftTile = {
|
|
||||||
x: 0,
|
const modes: Mode[] = [
|
||||||
y: 0,
|
{
|
||||||
|
pointerGrid: Array.from(Array(3), () => Array.from(Array(3))),
|
||||||
|
type: "radar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pointerGrid: Array.from(Array(3), () => Array.from(Array(1))),
|
||||||
|
type: "htorpedo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pointerGrid: Array.from(Array(1), () => Array.from(Array(3))),
|
||||||
|
type: "vtorpedo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pointerGrid: Array.from(Array(1), () => Array.from(Array(1))),
|
||||||
|
type: "missile",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
function isBorder(x: number, y: number, count: number) {
|
||||||
|
return x < 2 || x > count + 1 || y < 2 || y > count + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isHit(x: number, y: number, hits: Hit[]) {
|
||||||
|
return hits.filter((h) => h.x === x && h.y === y)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSet(x: number, y: number, targetList: TargetList[], show: boolean) {
|
||||||
|
return (
|
||||||
|
!!targetList.filter((field) => x === field.x && y === field.y).length &&
|
||||||
|
show
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function targetList(
|
||||||
|
{ x: targetX, y: targetY }: Position,
|
||||||
|
mode: number
|
||||||
|
): TargetList[] {
|
||||||
|
const { pointerGrid, type } = modes[mode]
|
||||||
|
const xLength = pointerGrid.length
|
||||||
|
const yLength = pointerGrid[0].length
|
||||||
|
return pointerGrid
|
||||||
|
.map((arr, i) => {
|
||||||
|
return arr.map((_, i2) => {
|
||||||
|
const relativeX = -Math.floor(xLength / 2) + i
|
||||||
|
const relativeY = -Math.floor(yLength / 2) + i2
|
||||||
|
const x = targetX + (relativeX ?? 0)
|
||||||
|
const y = targetY + (relativeY ?? 0)
|
||||||
|
return {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
type,
|
||||||
|
edges: [
|
||||||
|
i === 0 ? "left" : "",
|
||||||
|
i === xLength - 1 ? "right" : "",
|
||||||
|
i2 === 0 ? "top" : "",
|
||||||
|
i2 === yLength - 1 ? "bottom" : "",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.reduce((prev, curr) => [...prev, ...curr], [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function overlapsWithAnyBorder(target: Position, mode: number) {
|
||||||
|
return targetList(target, mode).filter(({ x, y }) => isBorder(x, y, count))
|
||||||
|
.length
|
||||||
|
}
|
||||||
|
|
||||||
|
export function composeTargetTiles(
|
||||||
|
target: Target,
|
||||||
|
mode: number,
|
||||||
|
hits: Hit[]
|
||||||
|
): PointerProps[] {
|
||||||
|
const { show } = target
|
||||||
|
return targetList(target, mode).map((targetItem) => {
|
||||||
|
const { x, y } = targetItem
|
||||||
|
return {
|
||||||
|
...targetItem,
|
||||||
|
show,
|
||||||
|
imply: !!isHit(x, y, hits).length,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const initlialTarget = {
|
export const initlialTarget = {
|
||||||
preview: false,
|
preview: false,
|
||||||
show: false,
|
show: false,
|
||||||
|
|
|
@ -43,6 +43,11 @@ export default async function create(
|
||||||
create: {
|
create: {
|
||||||
userId: id,
|
userId: id,
|
||||||
index: "player1",
|
index: "player1",
|
||||||
|
chats: {
|
||||||
|
create: {
|
||||||
|
event: "created",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -119,7 +119,6 @@ const SocketHandler = async (
|
||||||
})
|
})
|
||||||
let body: GamePropsSchema
|
let body: GamePropsSchema
|
||||||
if (user_Game.index === "player1" && enemy) {
|
if (user_Game.index === "player1" && enemy) {
|
||||||
console.log(1)
|
|
||||||
body = composeBody(
|
body = composeBody(
|
||||||
(
|
(
|
||||||
await prisma.user_Game.update({
|
await prisma.user_Game.update({
|
||||||
|
@ -140,7 +139,6 @@ const SocketHandler = async (
|
||||||
).game
|
).game
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
console.log(2)
|
|
||||||
const game = await prisma.game.findUnique({
|
const game = await prisma.game.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: socket.data.gameId,
|
id: socket.data.gameId,
|
||||||
|
@ -151,7 +149,6 @@ const SocketHandler = async (
|
||||||
body = composeBody(game)
|
body = composeBody(game)
|
||||||
}
|
}
|
||||||
const { payload, hash } = body
|
const { payload, hash } = body
|
||||||
console.log(payload?.player1, payload?.player2)
|
|
||||||
if (!payload || !hash) return cb(false)
|
if (!payload || !hash) return cb(false)
|
||||||
io.to(socket.data.gameId).emit(
|
io.to(socket.data.gameId).emit(
|
||||||
"playerEvent",
|
"playerEvent",
|
||||||
|
|
|
@ -16,6 +16,12 @@ export default function Lobby() {
|
||||||
<meta name="description" content="Generated by create next app" />
|
<meta name="description" content="Generated by create next app" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/fonts/cpfont_ote/CP Font.otf"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
/>
|
||||||
</Head>
|
</Head>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|
|
@ -15,8 +15,11 @@ import { toast } from "react-toastify"
|
||||||
import { Icons } from "react-toastify"
|
import { Icons } from "react-toastify"
|
||||||
|
|
||||||
export function isAuthenticated(res: Response) {
|
export function isAuthenticated(res: Response) {
|
||||||
if (status[`${res.status}_CLASS`] === status.classes.SUCCESSFUL)
|
switch (status[`${res.status}_CLASS`]) {
|
||||||
return res.json()
|
case status.classes.SUCCESSFUL:
|
||||||
|
case status.classes.REDIRECTION:
|
||||||
|
return res.json()
|
||||||
|
}
|
||||||
|
|
||||||
const resStatus = status[`${res.status}_CLASS`]
|
const resStatus = status[`${res.status}_CLASS`]
|
||||||
if (typeof resStatus !== "string") return
|
if (typeof resStatus !== "string") return
|
||||||
|
@ -60,10 +63,13 @@ export default function Start() {
|
||||||
|
|
||||||
const gameFetch = useCallback(
|
const gameFetch = useCallback(
|
||||||
async (pin?: string) => {
|
async (pin?: string) => {
|
||||||
const gamePromise = fetch("/api/game/" + (!pin ? "create" : "join"), {
|
const gameRequestPromise = fetch(
|
||||||
method: "POST",
|
"/api/game/" + (!pin ? "create" : "join"),
|
||||||
body: JSON.stringify({ pin }),
|
{
|
||||||
})
|
method: "POST",
|
||||||
|
body: JSON.stringify({ pin }),
|
||||||
|
}
|
||||||
|
)
|
||||||
.then(isAuthenticated)
|
.then(isAuthenticated)
|
||||||
.then((game) => GamePropsSchema.parse(game))
|
.then((game) => GamePropsSchema.parse(game))
|
||||||
|
|
||||||
|
@ -76,9 +82,9 @@ export default function Start() {
|
||||||
hideProgressBar: true,
|
hideProgressBar: true,
|
||||||
closeButton: false,
|
closeButton: false,
|
||||||
})
|
})
|
||||||
const res = await gamePromise.catch(() =>
|
const res = await gameRequestPromise.catch(() =>
|
||||||
toast.update(toastId, {
|
toast.update(toastId, {
|
||||||
render: "Es ist ein Fehler aufgetreten 🤯",
|
render: "Es ist ein Fehler aufgetreten bei der Anfrage 🤯",
|
||||||
type: "error",
|
type: "error",
|
||||||
icon: Icons.error,
|
icon: Icons.error,
|
||||||
theme: "colored",
|
theme: "colored",
|
||||||
|
@ -108,7 +114,7 @@ export default function Start() {
|
||||||
)
|
)
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
toast.update(toastId, {
|
toast.update(toastId, {
|
||||||
render: "Es ist ein Fehler aufgetreten 🤯",
|
render: "Es ist ein Fehler aufgetreten beim Seiten wechsel 🤯",
|
||||||
type: "error",
|
type: "error",
|
||||||
icon: Icons.error,
|
icon: Icons.error,
|
||||||
theme: "colored",
|
theme: "colored",
|
||||||
|
|
|
@ -197,7 +197,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.preview {
|
&.preview {
|
||||||
--color: lawngreen;
|
--color: forestgreen;
|
||||||
background-color: #0001;
|
background-color: #0001;
|
||||||
// border: 5px dashed var(--color);
|
// border: 5px dashed var(--color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: "CP_Font";
|
|
||||||
src: url("/fonts/cpfont_ote/CP Font.otf") format("opentype");
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin CP_Font {
|
|
||||||
font-family: "CP_Font", sans-serif;
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue