트릭컬 웹 팬게임

원리버·2025년 12월 6일
post-thumbnail

플레이 링크 : https://neleujimaseyo.web.app/

1. 프로젝트 소개

2. 주요 기능

3. 기타 로직

4. 배운 점

5. 마무리


프로젝트 소개

때는 바야흐로 12월 3일, 스핔의 시대가 도래하고 있다.
여러 영상을 보며 깔깔 웃던 트릭컬 유저로서, 수학여행 중 문득 이런 생각이 들었다.

한번 비슷한 거 만들어 보고 싶은데?

그렇게 3일간의 개발이 시작됐다.

🎮 게임 소개

게임명: 네르지마세요
개발 기간: 3일
기술 스택:

  • Frontend: React (JS) + Canvas API
  • Backend: Firebase Realtime Database

게임 방식

  • 이동: WASD 또는 방향키, 타 캐릭터 클릭시 일그러짐
  • 목표: 30초마다 생성되는 호박 구역에서 5초간 버티면 1점 획득
  • 특징: 최대 100명 동시 플레이, 실시간 리더보드

플레이 영상:

https://youtu.be/udM6HxwW4rs?si=SgUpNyP3-SaZ_Ir2

주요 기능

🌐 실시간 멀티플레이어

Firebase Realtime Database로 최대 100명 동시 플레이.

  • 플레이어 위치 실시간 동기화
  • 접속/종료 자동 감지 (onDisconnect)

🎨 Canvas 렌더링

requestAnimationFrame으로 60fps 안정화.

  • 플레이어 중심 카메라
  • 5000x2872 맵

🖱️ 클릭 왜곡 효과

다른 플레이어 클릭 시 픽셀 왜곡 애니메이션.

  • Map 기반 캐싱으로 성능 최적화

🔊 사운드 시스템

  • BGM, 클릭 소리, 구역 진입/종료 효과음
  • 브라우저 autoplay 정책 대응

🏆 실시간 리더보드

Top 5 플레이어 실시간 표시.

기타 로직

왜 React (JS)?

TypeScript 대신 JavaScript를 선택한 이유:

  • 빠른 프로토타이핑 (3일 개발)
  • 타입 정의 오버헤드 없음
  • 단순한 게임 로직

React를 선택한 이유:

  • Canvas + 상태 관리 용이
  • Firebase 연동 라이브러리 풍부
  • 익숙한 개발 환경

사실 뭐 걍 팬게임이라서 묵직하게는 안들어갈려고 했다.

왜 Firebase?

자체 서버 vs Firebase:

항목자체 서버Firebase
개발 시간2-3일 추가즉시
비용$5~10/월무료~$5/월
확장성직접 관리자동
실시간Socket.io 구현내장

결정: 3일 프로젝트에 Firebase가 최적.

이게 인기가 많아지면 Firebase 말고 지금 서버를 파던지 유료플랜을 바꾸던지 이런식으로 만들면 될것같다

렌더링 최적화 (440fps → 60fps)

문제 발견:

useEffect(() => {
    // Canvas 렌더링
}, [position, otherPlayers, zone, squishPlayers]); // 😱 과도한 의존성

모든 상태 변경마다 렌더링 → 440fps 폭주.

해결:

// 1. ref로 state 접근
const positionRef = useRef(position);

// 2. requestAnimationFrame
useEffect(() => {
    const render = () => {
        ctx.drawImage(img, positionRef.current.x, ...);
        requestAnimationFrame(render);
    };
    render();
}, []); // ✅ 빈 의존성 → 60fps 안정

결과: 86% 성능 향상 (440fps → 60fps)

클릭 왜곡 성능 최적화

문제:

픽셀 단위 왜곡 계산 (200x200 = 40,000번) → 렉 발생.

해결: Map 캐싱

const squishCache = new Map();

// 같은 위치 클릭 시 캐시 재사용
if (squishCache.has(cacheKey)) {
    return cachedCanvas;
}

// 최대 20개 유지
if (squishCache.size > 20) {
    const firstKey = squishCache.keys().next().value;
    squishCache.delete(firstKey);
}

결과: 반복 클릭 시 즉시 렌더링.

Firebase 실시간 동기화 이슈

문제:

왜곡 효과 공유 시 타이밍 문제 - 저장 후 0.5초 만에 삭제 → 다른 클라이언트가 못 받음.

해결:

// 삭제 시간 증가
setTimeout(() => {
    remove(squishRef);
}, 1000); // 500ms → 1000ms

Git 비밀키 노출 해결

문제:

serviceAccountKey.json 커밋 → GitHub Push Protection 차단.

해결:

# 1. 커밋 히스토리에서 제거
git reset --soft HEAD~1
git rm --cached serviceAccountKey.json

# 2. .gitignore 추가
echo "serviceAccountKey.json" >> .gitignore

# 3. 재커밋
git commit -m "..."
git push --force

교훈: 민감 정보는 .env + .gitignore 필수!

배운 점

Canvas API 실전 활용

이론으로만 알던 Canvas를 실제 게임에 적용하면서:

  • requestAnimationFrame의 중요성 체감
  • 카메라 좌표계 변환 이해
  • 픽셀 단위 이미지 조작 (왜곡 효과)

가장 어려웠던 부분:

좌표 계산. 월드 좌표 → 스크린 좌표 → 캐릭터 중심점 계산이 계속 헷갈렸다.

const screenX = player.x - cameraX;
const screenY = player.y - cameraY;

이 한 줄을 이해하는 데 생각보다 오래 걸렸다.

Firebase Realtime Database

생각보다 쉬웠던 것:

  • 기본 CRUD 연산
  • onValue로 실시간 구독

생각보다 어려웠던 것:

  • onDisconnect 타이밍
  • 동시성 이슈 (여러 명이 동시에 쓸 때)
  • Rules 설계 (보안 vs 편의성)

처음엔 Rules를 전부 열어놨다가, 나중에 제대로 설정했다.

{
  "players": {
    "$uid": {
      ".write": "auth.uid == $uid"  // 자기 데이터만 수정
    }
  }
}

React 성능 최적화

useEffect 의존성의 중요성:

아무 생각 없이 넣었던 의존성 배열이 440fps를 만들었다.

// ❌ 이렇게 하면 안 됨
useEffect(() => {
    // 렌더링
}, [position, zone, players]); // 모든 변화마다 실행

// ✅ 이렇게 해야 함
useEffect(() => {
    const render = () => {
        // positionRef.current로 접근
        requestAnimationFrame(render);
    };
    render();
}, []); // 한 번만 실행

useRef의 힘:

state는 변경되면 리렌더링하지만, ref는 그렇지 않다는 걸 제대로 이해했다.

멀티플레이어 게임 설계

동시성은 어렵다:

  • 혼자 개발할 때는 몰랐던 타이밍 이슈
  • 네트워크 지연 고려
  • 여러 명이 동시에 같은 데이터 수정

특히 왜곡 효과 공유:

  1. A가 B 클릭 → Firebase 저장
  2. 0.5초 후 삭제
  3. C는 못 받음 (너무 빠름)

이런 문제를 겪으면서 "동기화"가 얼마나 어려운지 알았다.

배포의 중요성

localhost에서만 돌리다가 실제 배포하니:

  • 브라우저 autoplay 정책 (소리 안 남!)
  • Firebase 비밀키 관리
  • favicon/title 같은 디테일

"일단 돌아가게" 만드는 것과 "실제 사용 가능하게" 만드는 건 다르다는 걸 배웠다.

가장 큰 수확

3일 만에 100명이 플레이할 수 있는 게임을 만들었다는 자신감.

처음엔 "이거 내가 할 수 있나?" 싶었는데, 하나씩 해결하다 보니 완성됐다.

특히 성능 최적화 (440fps → 60fps)를 직접 해결한 게 뿌듯했다.

클로드의 도움을 받지 않았다면 효율적으로 코드를 생산해 내지 못했을것이다.
고마워요 클로드!pro샀는데 이정도는 해야지 암

마무리

3일간의 개발 회고:

수학여행 중 떠올린 아이디어가 실제 게임이 됐다.

처음엔 단순히 "재미있겠다" 싶어서 시작했지만, 막상 만들다 보니:

  • 렌더링 최적화
  • 실시간 동기화
  • 성능 이슈

생각보다 많은 문제를 마주했다.

하지만 하나씩 해결하면서 성장했고, 결과물이 나왔다는 게 뿌듯하다.
좀 바이브를 돌리긴 했지만

앞으로의 계획:

  • 다양한 이벤트
  • 커스터마이징

링크:

피드백 환영합니다!

버그 제보나 개선 아이디어가 있다면 GitHub Issues나 댓글로 남겨주세요.


"일단 만들어보자"가 가장 중요한 것 같다.

profile
트릭컬을 알려주마

4개의 댓글

comment-user-thumbnail
2025년 12월 9일

수학여행이면 고등학생인가요?? 대단하네요 잘 보고 갑니다!

2개의 답글
comment-user-thumbnail
2025년 12월 20일

우와 너무 신기하네요 ㅎㅎ

답글 달기