JavaScript와 Canvas로 룰렛 게임 구현하기 (코드 예제 포함)

JavaScript와 Canvas로 룰렛 게임 구현하기 – 완성된 모습

✨ 1. 초기 HTML 구조 작성하기

먼저, 기본적인 HTML 파일을 만들고, 룰렛을 그릴 canvas 요소와 룰렛을 돌리는 버튼을 배치합니다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Canvas 룰렛</title>
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <button id="spin">spin</button>
    <script>
    </script>
  </body>
</html>

<canvas>는 룰렛을 그리는 공간입니다.

<button>은 룰렛을 회전시키는 버튼입니다.

<script>는 자바스크립트 코드를 이곳에 작성합니다.

🚀 2. Canvas를 이용해 룰렛 그리기

이제 script 부분에서 JavaScript를 이용해 룰렛 UI를 그리는 코드를 작성합니다.

2.1. Canvas 설정 및 초기화

먼저, script 부분에서 Canvas 요소를 가져오고, 2D 컨텍스트를 설정합니다.

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

// 캔버스 크기 설정
canvas.width = 500;
canvas.height = 500;

getContext("2d"): 캔버스에서 그림을 그릴 수 있도록 설정합니다.

canvas.width, canvas.height: 캔버스 크기를 500×500으로 설정합니다.

2.2. 룰렛 원판그리기

원을 그리는 함수를 작성합니다.

function drawCircle() {
    ctx.beginPath();
    ctx.arc(250, 250, 240, 0, Math.PI * 2);
    ctx.closePath();
    
    ctx.fillStyle = "#63FF84";
    ctx.fill();
    ctx.stroke();
}

drawCircle()

1. 새로운 경로를 시작 (beginPath())

2. 원의 중심(250, 250)과 반지름(240)으로 원을 그림 (arc())

3. 경로를 닫아 원을 완성 (closePath())

4. 연두색("#63FF84")으로 원을 채움 (fillStyle → fill())

5. 테두리를 그림 (stroke())

실행하면 초록색 원이 나타납니다. 🎨

Javascript Canvas를 사용해서 룰렛 만들기 - javascript canvas roulette circle

2.3. 포인터 그리기

삼각형을 그리는 함수를 작성합니다.(포인터는 원판의 12시 부분에, 선택된 아이템을 가리키는 역할을 하는 삼각형을 의미합니다.)

function drawPointer() {
    ctx.beginPath();
    ctx.moveTo(250, 20);
    ctx.lineTo(243, 6);
    ctx.lineTo(257, 6);
    ctx.closePath();

    ctx.fillStyle = "#fff";
    ctx.fill();
    ctx.stroke();
}

drawPointer()

1. 새로운 경로를 시작 (beginPath())

2. 포인터(삼각형)의 세 꼭짓점을 지정

  • moveTo(250, 20) → 포인터의 꼭짓점을 설정
  • lineTo(243, 6), lineTo(257, 6) → 삼각형을 완성하는 두 점 추가

3. 경로를 닫아 삼각형을 완성 (closePath())

4. 흰색("#fff")으로 삼각형을 채움 (fillStyle → fill())

5. 테두리를 그림 (stroke())

실행하면 원 위쪽에 삼각형 모양의 포인터가 추가됩니다.

Javascript Canvas를 사용해서 룰렛 만들기 - javascript canvas roulette background

2.4. 룰렛 섹션 나누기

룰렛을 여러 조각으로 나누고, 각 조각에 색상과 텍스트를 추가합니다.

2.4.1. 데이터 배열 만들기

룰렛에 들어갈 항목과 색상을 배열로 정의합니다.

const testData = [
    { id: 0, text: "김치찌개", background: "#ab6c66" },
    { id: 1, text: "부대찌개", background: "#86bc85" },
    { id: 2, text: "된장찌개", background: "#a5adce" },
];

let segments = [...testData];

testData 배열 → 룰렛에 들어갈 메뉴와 색상을 저장

segments 배열 → 룰렛의 조각을 동적으로 조작할 때 사용

2.4.2. 룰렛 조각 그리기

segments 조각을 룰렛에 그립니다.

function drawSegments(angle) {
    const addAngle = (Math.PI * 2) / segments.length;
    ctx.clearRect(0, 0, 500, 500); // 이전 프레임 지우기

    segments.forEach((segment, index) => {
        ctx.beginPath();
        ctx.moveTo(250, 250);
        ctx.arc(250, 250, 240 - 1, angle, angle + addAngle);
        ctx.closePath();

        ctx.fillStyle = segment.background;
        ctx.fill();
        ctx.lineWidth = 1; // 선 두께 설정
        ctx.stroke(); // 경로 외곽선 그리기
        ctx.save(); // 현재 상태 저장

        ctx.translate(250, 250);
        ctx.rotate(angle + addAngle / 2);

        ctx.textAlign = "center";
        ctx.font = "bold 28px sans-serif";
        ctx.fillStyle = "black";
        ctx.fillText(segment.text, 240 / 2, 0);

        ctx.restore();
        angle += addAngle; // 다음 각도 시작 각도 업데이트
    });

    drawPointer();
}

drawSegments(0);

1. 각 조각의 크기(addAngle)를 계산하여 룰렛을 균등하게 나눔

2. 이전 프레임을 지움 (clearRect()) → 이전 프레임이 남아있으면 외곽선이 두꺼워짐

3. 각 조각을 순회하면서 원을 그림 (forEach())

  • arc()를 이용해 원의 한 조각을 그림
  • fill()로 조각을 색칠하고, stroke()로 테두리를 그림

4. 텍스트 배치 준비

  • save()로 캔버스 상태 저장
  • translate(250, 250)로 원점 이동
  • rotate()를 사용해 조각 중앙에 맞춤

5. 텍스트 추가 후 상태 복원

  • fillText()로 조각 중앙에 텍스트 표시
  • restore()로 원래 캔버스 상태로 복원

6. 각도를 업데이트하여 다음 조각을 그림마지막으로 포인터(화살표)를 그림 (drawPointer())

Javascript Canvas를 사용해서 룰렛 만들기 - javascript canvas roulette

2.5. 애니메이션 및 회전 로직

룰렛을 부드럽게 회전하도록 설정합니다.

2.5.1. 상태 변수 설정

let spinning = false; // 회전 상태
let selectedSegment = null // 랜덤 값을 저장
let rotationCount = 20; // 기본 회전수
let totalRotation = 0 // 계산된 전체 회전수에 대한 라디안 값 
let startTimestamp = null // animate 함수가 실행된 시간
let duration = 5000 // 회전 시간

2.5.2. 감속 함수 (이징)

animate 함수의 progress 부분을 수정하면 됩니다. 저는 easings.net 에서 제공해주는 코드를 사용했습니다.

function easeInOutQuad(x) {
  return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
}

2.5.3. 회전 애니메이션

룰렛을 회전시키는 애니메이션 동작을 하는 함수를 작성합니다.

function animate(timestamp) {
    if (!spinning) {
        spinning = true;
        startTimestamp = timestamp;
    }

    let elapsed = timestamp - startTimestamp; // 경과 시간 계산
    let progress = easeInOutQuad(Math.min(elapsed / duration, 1)); // 이징함수 적용
    let angle = totalRotation * progress;  // 현재 회전 각도 계산

    drawSegments(angle);

    if (progress < 1) {
        requestAnimationFrame(animate);
    } else {
        spinning = false;
    }
}

1. timestamp → requestAnimationFrame()이 제공하는 현재 시간

2. 애니메이션 처음 실행 시 (spinning === false)

  • startTimestamp에 timestamp 저장
  • spinning = true;로 설정하여 중복 실행 방지

3. 경과 시간 계산 (elapsed = timestamp - startTimestamp;)

4. progress (진행 정도) 계산

  • elapsed / duration으로 진행률 계산
  • progress가 1이 되면 애니메이션 종료

2.5.4. 회전 시작 함수

룰렛의 회전을 시작하는 함수를 작성합니다.

function spin() {
    if (spinning) return; // 이미 실행중이면, 실행되지 않게함

    selectedSegment = Math.floor(Math.random() * segments.length); // 랜덤한 섹션 선택
    const angle = (Math.PI * 2) / segments.length; // 한 조각의 크기를 계산
    const randomAngle = Math.random() * -angle;  // 선택된 섹션이 차지하는 범위에서 랜덤 값을 구합니다.
    const correctionAngle = Math.PI * 1.5 - angle * selectedSegment; // 섹션의 시작각이 270도에 위치하게 합니다.

    totalRotation = Math.PI * 2 * rotationCount + correctionAngle + randomAngle; // 전체 회전수
    requestAnimationFrame(animate); // 애니메이션 시작
}

3. 이벤트 추가

버튼을 클릭하면 spin()을 호출하여 룰렛이 회전하도록 설정합니다.

document.getElementById("spin").addEventListener("click", spin);

3 thoughts on “JavaScript와 Canvas로 룰렛 게임 구현하기 (코드 예제 포함)”

  1. 잘 보고 가요! 저도 Canvas를 이용해서 재미있는 것들 좀 만들어보고 싶네요.

    응답

Leave a Comment