Как сделать камеру слежения за игроком и перемещаться по карте, не теряя игрока из поля зрения?
Здраствуйте, у меня проблема с непониманием того как в canvas сделать камеру слежения за игроком, и как перемещаться по карте не теряя игрока с поля зрения.
Вот код моего кастомного хука для получения позиции:
export const usePosition = (speed: number) => {
const [keysPressed, setKeysPressed] = useState<{ [key: string]: boolean }>({})
const [x, setX] = useState<number>(0)
const [y, setY] = useState<number>(0)
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
setKeysPressed((prevState) => ({
...prevState,
[e.key]: true,
}))
}
const handleKeyUp = (e: KeyboardEvent) => {
setKeysPressed((prevState) => ({
...prevState,
[e.key]: false,
}))
}
window.addEventListener("keydown", handleKeyDown)
window.addEventListener("keyup", handleKeyUp)
return () => {
window.removeEventListener("keydown", handleKeyDown)
window.removeEventListener("keyup", handleKeyUp)
}
}, [])
useEffect(() => {
const moveCharacter = () => {
let newX = x
let newY = y
if (keysPressed["ArrowUp"] || keysPressed["w"]) newY -= speed
if (keysPressed["ArrowDown"] || keysPressed["s"]) newY += speed
if (keysPressed["ArrowLeft"] || keysPressed["a"]) newX -= speed
if (keysPressed["ArrowRight"] || keysPressed["d"]) newX += speed
setX(newX)
setY(newY)
}
const animationFrame = requestAnimationFrame(moveCharacter)
return () => cancelAnimationFrame(animationFrame)
}, [keysPressed, x, y])
return { x, y }
}
А вот код компонента игры:
"use client"
import { useEffect, useRef } from "react"
import { usePosition } from "@/hooks/usePosition"
import { socket } from "@/components/Socket"
import { userId } from "@/components/userId"
import { map } from "@/components/map"
socket.emit("new_player", { userId })
const Game = () => {
const { x, y } = usePosition(3)
const canvasRef = useRef<HTMLCanvasElement>(null)
socket.emit("move", { x, y })
useEffect(() => {
const ctx = canvasRef.current?.getContext("2d")
if (ctx) {
socket.on("state", (players: Player[]) => {
ctx.clearRect(
0,
0,
canvasRef.current?.width || 0,
canvasRef.current?.height || 0
)
map(ctx, 32)
for (let id in players) {
const currentPlayer: Player = players[id]
const color = () => {
if (userId == currentPlayer.userId) {
return "red"
} else {
return "#30363d"
}
}
ctx.fillStyle = color()
ctx.beginPath()
ctx.arc(
currentPlayer.positionX,
currentPlayer.positionY,
25,
0,
Math.PI * 2
)
ctx.fill()
}
})
}
return () => {
socket.off("state")
}
}, [socket])
return (
<main>
<canvas ref={canvasRef} width={700} height={700}></canvas>
<div>
<div>
<div>x: {x}</div>
<div>y: {y}</div>
</div>
</div>
</main>
)
}
export default Game
Код компонента по создания карты:
const tilemap: number[][] = [
[1, 2, 0, 1, 2, 0, 1, 2, 0],
[2, 2, 0, 2, 2, 0, 1, 2, 0],
[1, 2, 0, 1, 2, 0, 1, 2, 0],
[0, 0, 1, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 0, 0, 1, 0, 0, 1],
[0, 0, 2, 0, 0, 2, 0, 0, 2],
[1, 0, 2, 0, 0, 0, 0, 0, 1],
[0, 0, 1, 0, 0, 2, 0, 0, 2],
]
for (let i = 0; i < tilemap.length; i++) {
for (let j = 0; j < tilemap[i].length; j++) {
const tile = tilemap[i][j]
const tileX = j * tileSize
const tileY = i * tileSize
if (tile === 1) {
ctx.fillStyle = "green"
} else if (tile === 2) {
ctx.fillStyle = "blue"
} else {
ctx.fillStyle = "white"
}
ctx.fillRect(tileX, tileY, tileSize, tileSize)
}
}
}