20240205_234709.png

러너 게임(달리기 게임)은 플레이어가 자동으로 전진하면서 장애물을 회피하고, 점수를 획득하는 게임 유형이다. 간단한 러너 게임은 캔버스 없이 JavaScript, HTML, CSS 만으로도 구현할 수 있다. 러너 게임 구현은 크게 ①이동(전진), ②점프, ③장애물 배치, ④장애물 충돌 감지로 나눌 수 있다. 슈퍼 마리오는 플레이어가 캐릭터를 직접 조종하는 플랫포머 장르에 속하지만 친숙한 마리오 캐릭터와 구조물을 이용해서 러너 게임으로 만들어보자.

싱글톤 DOM 관리



class DomManager {
  static instance = null;

  constructor() {
    if (DomManager.instance) return DomManager.instance;

    this.gameArea = document.querySelector('.game');
    this.dialog = document.querySelector('.dialog-failed');
    // ...

    DomManager.instance = this;
  }

  static getInstance() {
    if (!DomManager.instance) DomManager.instance = new DomManager();
    return DomManager.instance;
  }
}

export default DomManager.getInstance();

게임 영역, 스코어, 시작 버튼 등 게임에서 자주 사용하는 요소들은 DomManager 라는 클래스에서 관리한다. 이렇게 DOM 관련 작업을 한 곳에 중앙화하면 반복적인 쿼리와 조작을 피할 수 있다.

클래스의 인스턴스를 오직 하나만 생성하여 어플리케이션 전체에 공유하는 방식을 싱글톤 패턴이라고 부른다. 돔 매니저를 싱글톤으로 내보내면 프로젝트 어디서든 동일한 인스턴스에 접근하기 때문에 일관성을 높일 수 있다.

getInstance() 정적 메서드를 처음 호출하면 생성한 인스턴스가 없기 때문에 constructor를 실행해서 새로운 인스턴스를 만들고, DomManager.instance 정적 프로퍼티에 할당한다. 그 후 getInstance() 를 다시 호출하면 DomManager.instance 프로퍼티에 할당했던 기존 인스턴스를 반환한다.

<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> 생성자(constructor) 함수는 기본적으로 새로 생성된 인스턴스(this)를 반환하지만 위처럼 명시적으로 반환 값을 지정할 수도 있다.

</aside>

마리오 전진



게임내 구조물들이 게임 화면을 기준으로 움직일 수 있도록, 게임 화면 요소의 position 값은 relative로 설정하고, 마리오나 장애물 등은 absolute로 설정한다.

.game {
  width: 100%;
  min-height: 440px;
  overflow: hidden;
  position: relative;
  background-image: url('./assets/background.png');
  background-size: 600px 500px;
  background-position: center;
}

background-position-x 는 배경 이미지의 수평 위치를 조절할 때 사용하는 스타일 속성이다. 이 속성을 이용해 배경 이미지의 수평 위치를 주기적으로 왼쪽으로 이동 시키면 앞으로 전진하는 듯한 효과를 구현할 수 있다. 이 속성의 기본값은 왼쪽 가장 자리를 나타내는 0%다.