게임 로직 설계: 베네치아 스타일 자바스크립트 타자 게임 만들기

자바스크립트 타자 게임 화면

안녕하세요! 14번째 프로젝트는 조금 특별한 추억 여행을 떠나보려 합니다. 혹시 예전 ‘한컴타자연습’에서 즐겼던 ‘베네치아’ 게임을 기억하시나요? 하늘에서 내려오는 단어들이 바다에 빠지기 전에 빛의 속도로 타이핑하던 그 긴장감! 오늘은 그 고전 게임의 핵심 메커니즘을 ‘자바스크립트 타자 게임’으로 재현해 보았습니다.

단순히 글자를 입력하는 것을 넘어, 객체들이 독립적으로 움직이고 특정 조건에서 화면 전체에 영향을 주는 ‘아이템 로직’, ‘패배 조건(Game Over)’과 사용자를 방해하는 ‘디버프(Debuff)’ 효과까지 구현하며 웹 프로그래밍의 역동성을 한껏 끌어올린 과정을 공유합니다.


1. 프로젝트 기획: 게임의 3요소 정의하기

본격적인 코딩에 앞서 게임의 핵심 요소를 세 가지로 정의했습니다.

  1. 동적 생성: 일정한 시간마다 랜덤한 위치에서 단어가 나타날 것.
  2. 중력 시스템: 생성된 단어는 초당 일정 픽셀만큼 아래로 이동할 것.
  3. 상호작용: 사용자가 입력한 값과 단어의 텍스트가 일치하면 즉시 화면에서 제거할 것.

이 세 가지를 구현하기 위해 자바스크립트의 setInterval과 배열(Array) 관리 기법을 활용했습니다. 특히 화면에 그려지는 DOM 요소와 메모리 상의 데이터를 일치시키는 작업이 이번 자바스크립트 타자 게임 프로젝트의 기술적 기반이 되었습니다.

2. 핵심 로직 구현: 움직이는 단어와 입력 시스템

가장 먼저 해결해야 할 과제는 단어를 움직이는 것이었습니다. fallingWords라는 배열에 생성된 단어의 정보(좌표, 텍스트, DOM 객체)를 담고, 30ms마다 실행되는 update 함수를 통해 Y좌표를 계속 증가시켰습니다.

입력 시스템은 사용자가 Enter 키를 눌렀을 때만 작동하도록 설계했습니다. findIndex 메서드를 사용하여 현재 화면에 존재하는 단어 중 입력값과 일치하는 요소를 찾아내고, 성공 시 점수를 부여한 뒤 DOM에서 즉시 제거하는 흐름을 구축했습니다.

게임의 입력 처리 방식은 이전에 작성한 [자바스크립트 타이핑 측정기] 포스팅의 문자열 비교 로직을 기반으로 설계되었습니다.

3. 재미 요소의 확장: ‘폭탄’과 ‘안개’ 단어 시스템

단순한 타자 연습은 금방 지루해질 수 있습니다. 그래서 저는 자바스크립트 타자 게임의 게임성을 높이기 위해 두 가지 특수 아이템을 도입했습니다.

  • 폭탄 단어 (빨간색): 위기 상황을 단번에 반전시키는 아이템입니다. 입력 시 화면의 모든 단어를 지워주며 높은 보너스 점수를 줍니다.
  • 안개 단어 (파란색): 사용자를 방해하는 역설적인 재미를 줍니다. 입력 시 3초간 모든 단어가 가려지도록 하였습니다. 처음에는 화면 전체를 흐리게 했으나, 입력창까지 흐려져 조작감이 나빠지는 문제를 해결하기 위해 ‘단어 요소들만’ 골라서 효과를 주도록 리팩토링했습니다.

4. 자바스크립트 타자 게임 실행 영상

자바스크립트 타자 게임 실행 화면

5. 디버깅 후 수정 사항

개발 중반부, ‘프론트엔드’나 ‘자바스크립트’처럼 긴 단어가 화면 오른쪽 끝에서 생성될 때 글자가 두 줄로 꺾이는 현상이 발생했습니다. 게임 디자인적으로 매우 보기 좋지 않았죠.

저는 CSS에 white-space: nowrap을 추가해 줄바꿈을 원천 차단했습니다. 또한, 단어가 생성될 때 해당 엘리먼트의 실제 너비(wordEl.offsetWidth)를 계산하여, 화면 너비를 초과해 생성되지 않도록 좌표 생성 범위를 조정했습니다. 덕분에 어떤 단어든 화면 안에서 안정적으로 내려오게 되었습니다.

자바스크립트 타자 게임을 만들면서 가장 까다로웠던 문제는 사용자가 게임 도중 다른 탭으로 이동했을 때 발생했습니다. 브라우저가 백그라운드 탭의 연산을 지연시키면서, 다시 돌아왔을 때 그동안 생성된 단어들이 한꺼번에 뭉쳐서 쏟아지는 버그가 있었습니다.

이를 해결하기 위해 Page Visibility API를 사용하여 사용자가 현재 탭을 보고 있는지 실시간으로 체크했습니다.

이 간단한 로직 하나로 게임의 안정성이 몰라보게 좋아졌습니다. 사용자가 자리를 비웠을 때는 게임도 잠시 숨을 고르게 함으로써 비정상적인 데이터 누적을 막은 것이죠.

6. 패배의 미학: 게임 오버와 재시작

베네치아 게임의 묘미는 바다에 단어가 빠지는 순간의 아찔함입니다. 단어의 좌표가 gameArea의 높이에 도달하면 즉시 endGame 함수를 호출하여 화면을 어둡게 가리고 최종 점수를 노출했습니다. 다시 시작 버튼은 location.reload()를 사용하여 복잡한 상태 초기화 없이도 쾌적하게 게임을 재개할 수 있도록 유도했습니다.


이번 14번째 프로젝트는 하나의 완성된 웹앱을 만드는 기분으로 임했습니다. 글자가 깨지지 않게 하고, 탭 이동 시의 버그를 잡는 등의 사소한 디테일이 모여 사용자가 신뢰할 수 있는 앱이 완성된다는 것을 다시 한번 깨달았습니다.

위에서 아래로 단어가 내려오는 애니메이션 속도와 점수 계산 로직을 동기화하는 것이 가장 큰 도전이었습니다. setInterval의 타이밍 문제로 인해 게임이 종료되지 않는 에러를 해결하면서, 자바스크립트의 실행 컨텍스트와 타이머 함수에 대해 깊이 있는 통찰을 얻었습니다. 단순한 구현을 넘어 시스템의 안정성을 고민해 볼 수 있었던 즐거운 시간이었습니다.

여기에 더불어 난이도 시스템을 추가하여, 점점 속도가 빨라지는 기능을 넣거나, 콤보 시스템을 더해 연속으로 단어를 틀리지 않고 맞혔을 경우 점수에 가중치를 부여하기, 실제 서버와 연동 시켜서 사용자들끼리 경쟁할 수 있도록 랭킹 시스템 등을 추가하면 진짜 완벽한 자바스크립트 타자 게임이 될 것 같습니다.

다음 15번째 프로젝트부터는 또 다른 흥미로운 주제와 새로운 작성 패턴으로 찾아뵙겠습니다.

댓글 남기기