Drawing function
This commit is contained in:
parent
6bff62c0c2
commit
a088bff7be
3 changed files with 116 additions and 6 deletions
|
@ -1,12 +1,13 @@
|
||||||
// import Bluetooth from './Bluetooth'
|
import { Draw, Hit, MouseCursor, Target } from "../../interfaces/frontend"
|
||||||
// import FogImages from './FogImages'
|
// import Bluetooth from "./Bluetooth"
|
||||||
import { Hit, MouseCursor, Target } from "../../interfaces/frontend"
|
// import FogImages from "./FogImages"
|
||||||
import Labeling from "./Labeling"
|
import Labeling from "./Labeling"
|
||||||
import Ships from "./Ships"
|
import Ships from "./Ships"
|
||||||
import BorderTiles from "@components/Gamefield/BorderTiles"
|
import BorderTiles from "@components/Gamefield/BorderTiles"
|
||||||
import EventBar from "@components/Gamefield/EventBar"
|
import EventBar from "@components/Gamefield/EventBar"
|
||||||
import HitElems from "@components/Gamefield/HitElems"
|
import HitElems from "@components/Gamefield/HitElems"
|
||||||
import Targets from "@components/Gamefield/Targets"
|
import Targets from "@components/Gamefield/Targets"
|
||||||
|
import { useDraw } from "@hooks/useDraw"
|
||||||
import {
|
import {
|
||||||
hitReducer,
|
hitReducer,
|
||||||
initlialTarget,
|
initlialTarget,
|
||||||
|
@ -52,17 +53,15 @@ function Gamefield() {
|
||||||
} else if (!overlapsWithAnyBorder(targetPreview, mode))
|
} else if (!overlapsWithAnyBorder(targetPreview, mode))
|
||||||
setTarget({ show: true, x, y })
|
setTarget({ show: true, x, y })
|
||||||
},
|
},
|
||||||
[hits, mode, targetPreview]
|
[hits, mode, target, targetPreview]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(1)
|
|
||||||
const { x, y, show } = target
|
const { x, y, show } = target
|
||||||
const { shouldShow, ...position } = mouseCursor
|
const { shouldShow, ...position } = mouseCursor
|
||||||
if (!shouldShow || overlapsWithAnyBorder(position, mode))
|
if (!shouldShow || overlapsWithAnyBorder(position, mode))
|
||||||
setTargetPreview((e) => ({ ...e, show: false }))
|
setTargetPreview((e) => ({ ...e, show: false }))
|
||||||
else {
|
else {
|
||||||
console.log(2, position)
|
|
||||||
setTargetPreview({
|
setTargetPreview({
|
||||||
...position,
|
...position,
|
||||||
show: !show || x !== position.x || y !== position.y,
|
show: !show || x !== position.x || y !== position.y,
|
||||||
|
@ -70,6 +69,29 @@ function Gamefield() {
|
||||||
}
|
}
|
||||||
}, [mode, mouseCursor, target])
|
}, [mode, mouseCursor, target])
|
||||||
|
|
||||||
|
const [color, setColor] = useState<string>("#f00")
|
||||||
|
const [disable, setDisable] = useState(false)
|
||||||
|
const { canvasRef, onMouseDown, clear } = useDraw(drawLine)
|
||||||
|
|
||||||
|
function drawLine({ prevPoint, currentPoint, ctx }: Draw) {
|
||||||
|
const { x: currX, y: currY } = currentPoint
|
||||||
|
const lineColor = color
|
||||||
|
const lineWidth = 5
|
||||||
|
|
||||||
|
let startPoint = prevPoint ?? currentPoint
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.lineWidth = lineWidth
|
||||||
|
ctx.strokeStyle = lineColor
|
||||||
|
ctx.moveTo(startPoint.x, startPoint.y)
|
||||||
|
ctx.lineTo(currX, currY)
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
|
ctx.fillStyle = lineColor
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(startPoint.x, startPoint.y, 2, 0, 2 * Math.PI)
|
||||||
|
ctx.fill()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="gamefield">
|
<div id="gamefield">
|
||||||
{/* <Bluetooth /> */}
|
{/* <Bluetooth /> */}
|
||||||
|
@ -95,7 +117,20 @@ function Gamefield() {
|
||||||
|
|
||||||
<Targets props={{ target, targetPreview, mode, hits }} />
|
<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> */}
|
||||||
|
<canvas
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
pointerEvents: !disable ? "auto" : "none",
|
||||||
|
} as CSSProperties
|
||||||
|
}
|
||||||
|
ref={canvasRef}
|
||||||
|
onMouseDown={onMouseDown}
|
||||||
|
width="648"
|
||||||
|
height="648"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<button onClick={() => setDisable((e) => !e)}>toggle disable</button>
|
||||||
|
<button onClick={clear}>Clear</button>
|
||||||
<EventBar props={{ setMode, setTarget }} />
|
<EventBar props={{ setMode, setTarget }} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
64
leaky-ships/hooks/useDraw.ts
Normal file
64
leaky-ships/hooks/useDraw.ts
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import { Draw, Point } from "../interfaces/frontend"
|
||||||
|
import { useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
|
export const useDraw = (
|
||||||
|
onDraw: ({ ctx, currentPoint, prevPoint }: Draw) => void
|
||||||
|
) => {
|
||||||
|
const [mouseDown, setMouseDown] = useState(false)
|
||||||
|
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||||
|
const prevPoint = useRef<null | Point>(null)
|
||||||
|
|
||||||
|
const onMouseDown = () => setMouseDown(true)
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
const canvas = canvasRef.current
|
||||||
|
if (!canvas) return
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d")
|
||||||
|
if (!ctx) return
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = (e: MouseEvent) => {
|
||||||
|
if (!mouseDown) return
|
||||||
|
const currentPoint = computePointInCanvas(e)
|
||||||
|
|
||||||
|
const ctx = canvasRef.current?.getContext("2d")
|
||||||
|
if (!ctx || !currentPoint) return
|
||||||
|
|
||||||
|
onDraw({ ctx, currentPoint, prevPoint: prevPoint.current })
|
||||||
|
prevPoint.current = currentPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
const computePointInCanvas = (e: MouseEvent) => {
|
||||||
|
const canvas = canvasRef.current
|
||||||
|
if (!canvas) return
|
||||||
|
|
||||||
|
const rect = canvas.getBoundingClientRect()
|
||||||
|
const x = e.clientX - rect.left
|
||||||
|
const y = e.clientY - rect.top
|
||||||
|
|
||||||
|
return { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
const mouseUpHandler = () => {
|
||||||
|
setMouseDown(false)
|
||||||
|
prevPoint.current = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
canvasRef.current?.addEventListener("mousemove", handler)
|
||||||
|
window.addEventListener("mouseup", mouseUpHandler)
|
||||||
|
|
||||||
|
// Remove event listeners
|
||||||
|
return () => {
|
||||||
|
canvasRef.current?.removeEventListener("mousemove", handler)
|
||||||
|
window.removeEventListener("mouseup", mouseUpHandler)
|
||||||
|
}
|
||||||
|
}, [onDraw])
|
||||||
|
|
||||||
|
return { canvasRef, onMouseDown, clear }
|
||||||
|
}
|
|
@ -47,3 +47,14 @@ interface removeMissile {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HitDispatch = fireMissile | removeMissile
|
export type HitDispatch = fireMissile | removeMissile
|
||||||
|
|
||||||
|
export interface Point {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Draw {
|
||||||
|
ctx: CanvasRenderingContext2D
|
||||||
|
currentPoint: Point
|
||||||
|
prevPoint: Point | null
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue