1편이 ‘왜 만들었는가’에 대한 이야기였다면,
2편은 ‘어떻게 만들었는가’ 에 대한 이야기다.
개인적으로 웹 애플리케이션 제작시 나는 Django, PostgreSQL, Redis, Docker 같은 백엔드 기반 시스템을 다루는 것을 훨씬 편하게 느끼는 사람이다.
그런데 이번 프로젝트는 거의 전부 순수 바닐라 JS + HTML5 Canvas 기반으로 진행됐다.
평소라면 절대 깊게 다루지 않았을 법한 프론트엔드 기술들이 이 게임에서는 핵심이 되었다.
그리고 놀랍게도…
엄청 재미있었다.
이것이 나를 더욱 몰입하게 만든 기술적 요인이었다.
평소에는 프론트엔드 쪽 업무를 "좋아하지 않는다"라는 표현보다 "싫어한다"라는 표현이 적절할 정도인데, 豆柴の大群 에 대한 사랑의 힘이 "싫어하는 일"도 좋아하게 만든 것이 아닐까 싶다.

1. HTML5 Canvas – “그림판 + 애니메이션” 같은 세계
MAME RUN!!의 핵심은 HTML5 Canvas다.
이는 웹페이지 위에 만들어진 ‘그림판’ 같은 영역인데, 여기에 직접 픽셀을 그리는 방식으로 게임을 만든다.
보통 웹 개발은
-
버튼 만들고(HTML)
-
색 입히고(CSS)
-
약간의 행동을 준다(JS)
이런 흐름이지만 Canvas는 완전히 다르다.
Canvas는 30~60fps로 계속 다시 그리는 구조다.
매 프레임마다:
-
배경을 지우고
-
다시 그리고
-
캐릭터를 그리고
-
장애물을 그리고
-
충돌을 계산하고
-
점수를 올리고
-
다음 프레임을 예약한다
이걸 매 초 수십 번 반복한다.
요즘 웹 브라우저는 게임 엔진 못지않게 정말 강력 하다고 느껴진다.
2. 점프와 중력: “단 3줄의 코드가 만들어내는 마법”
게임의 기본인 ‘점프’는 사실 단순 물리로 구현되었다.
dino.vy += gravity * dt; // 중력 적용
dino.y += dino.vy * dt; // 위치 변경
if (dino.y >= ground) {
dino.y = ground;
dino.vy = 0;
}
이 단순한 로직만으로도
레오나가 부드럽게 뛰고 착지하고 떨어지는 동작이 자연스럽게 만들어진다.
게임 엔진이 없는 상황에서,
“아… 이런 기본 물리만으로도 충분히 쫀쫀한 움직임이 나오는구나”
라는 작은 감동이 있었다.

3. 스프라이트 애니메이션 – 레오나가 달리는 순간 생명이 붙었다
레오나의 러닝 모션은 다음 이미지처럼 6 프레임짜리 스프라이트 시트다.
(※ 블로그에 스프라이트 이미지 삽입 추천)
JS에서는 스프라이트를 잘라서 프레임마다 그리면 된다:
const frameWidth = sprite.width / 6;
ctx.drawImage(
sprite,
frameIndex * frameWidth, 0, frameWidth, sprite.height,
dino.x, dino.y, dino.width, dino.height
);
프레임 인덱스만 계속 바꾸면
레오나가 귀엽게 달린다.
이 순간 게임에 ‘생명’이 들어간 느낌이 들었다.
게임 개발에서 애니메이션은 정말 중요하다.
4. 장애물 랜덤 생성 – "단조로움을 없애는 핵심"
장애물은 여러 종류가 있다.
-
주황색 콘
-
빨간 콘
-
노란 콘
-
오토바이 (2가지 색)
-
자동차 (2가지 종류)
-
표지판 (세가지)
그냥 1~2개만 반복되면 금방 질리는데,
여러 타입을 랜덤 간격으로 섞어주면 게임 흐름이 확 살아난다.
const key = OBSTACLE_KEYS[Math.random() * length];
const interval = 0.8 + Math.random() * 1.2;
아주 단순한 랜덤이지만
플레이 감각은 완전히 달라진다.
5. 충돌 판정 – 가장 어려우면서도 가장 재미있던 부분
충돌 판정은 흔히 “AABB 박스 충돌”이라고 부르는 방식이다.
if (dino.x < ob.x + ob.width &&
dino.x + dino.width > ob.x &&
dino.y < ob.y + ob.height &&
dino.y + dino.height > ob.y) {
// 충돌!
}
여기서 중요한 건
-
너무 빡빡하게 판정하면 게임이 짜증나고
-
너무 널널하면 게임 난이도가 떨어진다
그래서 레오나와 장애물 둘 다 히트박스를 실제보다 10~15% 축소해서 “기분 좋은 난이도”를 만들었다.
이 미세 조정이 꽤 재밌었다.
게임 개발자들이 왜 난이도 밸런스에 혼을 담는지 조금 알 것 같았다.
6. 거리 기반 스테이지 시스템 – 50초면 클리어
Stage 1은 약 50초에 클리어되도록 설계했다.
그래서 레오나는 초당 16m를 이동하는 것으로 가정했다.
목표 거리: 800m
속도: 16 m/s → 약 50초
이걸 숫자로만 정하는 게 아니라, 실제로 30~40번 플레이하면서
“이 정도면 한 판 즐기고 다시 하고 싶은 길이인가?”
를 계속 시험했다.
작지만 플레이 감각을 좌우하는 중요한 요소였다.
7. 서버 연동 – 점수 랭킹과 기록 저장
백엔드 기반 개발자인 만큼, 서버 파트는 자연스럽게 Django + DRF로 구성했다.
-
POST로 점수 제출
-
Serializer에서 유효성 검사
-
비로그인 유저는 guest_id로 기록
-
유저별 최고점은 UserScore 테이블에서 관리
-
TOP 5는 HTML 조각으로 반환해 JS가 교체
그래서 게임오버 시 바로 랭킹 TOP5가 실시간 갱신된다.
재밌는 건, Canvas 게임 안에서도
백엔드의 안정성과 구조화된 데이터 흐름이 엄청 큰 힘이 된다는 사실이었다.
백엔드에서 체계적으로 캐릭터의 이미지과 대사 데이터를 정리해두고 이를 조합해서 브라우저로 보내주는 방식이다.
8. 모바일 대응 – 예상보다 훨씬 어려웠다
웹 게임을 만드는 데 있어서 가장 예상 밖의 난관은 모바일 환경이었다.
-
해상도 대응
-
터치 동작
-
캔버스 비율
-
렌더링 성능
-
배경 스크롤 속도 보정
데스크탑에서는 매우 부드럽게 돌아가지만
모바일에서는 자잘한 프레임 드랍 · 터치 반응성 · canvas 크기 계산 같은 문제들이 있었다.
결국 해결했지만,
이 과정에서 “프론트엔드 개발자들 존경합니다…” 라는 말이 절로 나왔다.
9. 2편 – 기술편을 마치며
백엔드 쪽을 좋아해서 주로 API를 위주로 개발하는 내가 디자인이 메인인 게임을 JS로 웹으로 만드는 일은 처음이었다. 평소에도 프론트는 해야하니까 어쩔 수 없이 하는 정도였고, 특히 HTML5 Canvas를 이렇게 깊게 써본 적은 거의 없었다.
그런데 이번 프로젝트를 통해,
-
웹은 생각보다 강력하고
-
지저분하다고 한 때 싫어했던 자바스크립트는 나름 재미있는 언어이며
-
게임 개발은 ‘작은 기술들의 조합’이라는 것
을 배울 수 있었다.
팬심 하나로 시작한 프로젝트였지만,
개발자로서도 꽤 많은 배움과 성장을 얻은 작업이었다.
다음 편 예고 (3편: 스토리 편)
다음 글에서는
“왜 시부야에서 시작하는가?”, “왜 도쿄돔인가?”, “각 멤버별 캐릭터 설정은 어떻게 정했는가?”
같은 세계관/스토리 제작 비하인드를 정리해볼 생각이다.
댓글이 없습니다.