DrawLineCanvas.tsx: 선 잇기 게임의 UI와 로직을 전반 관리하는 컴포넌트canvasDrawer.ts: 선 잇기 게임의 점을 찍고 선을 그리는 캔버스 로직 담당하는 클래스particle.ts: 선 잇기 게임 종료 후 축하 애니메이션에 사용될 파티클 정의하는 클래스Ex1.tsx: DrawLineCanvas를 호출하며, 특정 비행기 이미지를 사용해 선 잇기 게임 진행하는 컴포넌트// canvasDrawer.ts
import { loadImage } from "../utils/image.ts";
class CanvasDrawer {
private canvas: HTMLCanvasElement;
private ctx: CanvasRenderingContext2D | null;
private proceedImage: HTMLImageElement | null = null;
private finishImage: HTMLImageElement | null = null;
constructor(
canvas: HTMLCanvasElement,
proceedImagePath: string,
finishImagePath: string,
) {
this.canvas = canvas;
this.ctx = this.canvas.getContext('2d');
this.initializeCanvas(proceedImagePath, finishImagePath);
}
// 캔버스 초기화 (이미지 불러와서 그리기)
private async initializeCanvas(proceedImagePath: string, finishImagePath: string) {
const [proceedImage, finishImage] = await Promise.all([
loadImage(proceedImagePath), loadImage(finishImagePath)
])
this.proceedImage = proceedImage;
this.finishImage = finishImage;
this.ctx?.drawImage(this.proceedImage, 0, 0);
}
}
export default CanvasDrawer;
Promise.all로 이미지를 비동기 로드하고 첫 번째 이미지를 캔버스에 그림// DrawerLineCanvas.tsx
import {FC, useEffect, useRef} from "react";
import CanvasDrawer from "../classes/canvasDrawer.ts";
import "./drawLineCanvas.css";
interface Props {
drawingImage: string;
completedImage: string;
}
const DrawLineCanvas: FC<Props> = ({drawingImage, completedImage}) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const drawerRef = useRef<CanvasDrawer | null>(null);
useEffect(() => {
if (canvasRef.current) drawerRef.current = new CanvasDrawer(
canvasRef.current,
drawingImage,
completedImage,
);
}, []);
return (
<div className={"canvas_container"}>
<canvas ref={canvasRef} width={600} height={400}/>
</div>
);
};
export default DrawLineCanvas;
canvasDrawer 객체 생성, 내부적으로는 생성자로 인해 drawingImage, completedImage가 로드되고 drawingImage가 캔버스에 그려짐// Ex1.tsx
import DrawLineCanvas from "./DrawLineCanvas.tsx";
// 비행기 선 그리는 예제
const Ex1 = () => {
return (
<DrawLineCanvas
drawingImage={"./src/assets/dottodot_airplane.png"}
completedImage={"./src/assets/dottodot_airplane_finish.png"}
/>
);
};
export default Ex1;
DrawLineCanvas 컴포넌트를 호출하여 drawingImage, completedImage 이미지 경로를 props로 전달
실행하면 위와 같이 선 잇기 게임을 하기 위한 이미지가 뜨게 된다.
// canvasDrawer.ts
class CanvasDrawer {
...
// 시작한 점의 좌표
private startX: number = 0;
private startY: number = 0;
// 몇 번째 점을 클릭했는지 추적하는 순서 카운터
private order: number = 1;
...
// 점 클릭
public handleClick(event: React.MouseEvent<HTMLCanvasElement>) {
const { offsetX: mouseX, offsetY: mouseY } = event.nativeEvent;
if (this.order === 1) {
this.startLine(mouseX, mouseY);
} else {
this.drawLine(mouseX, mouseY);
}
this.order++;
}
// 맨 처음 점의 좌표 찍기
private startLine(mouseX: number, mouseY: number) {
this.startX = mouseX - 5;
this.startY = mouseY;
this.ctx?.beginPath();
this.ctx?.moveTo(this.startX, this.startY);
}
// 찍은 좌표까지 선 그리기
private drawLine(mouseX: number, mouseY: number) {
this.ctx?.lineTo(mouseX - 5, mouseY);
this.ctx?.stroke();
}
}
export default CanvasDrawer;