JavaScript 게임의 컨트롤 메카니즘

노트북, 데스크탑, 스마트폰, 태블릿, TV, 그리고 냉장고… 이 기기들의 공통점이 하나 있습니다. 이 기기들은 모두 브라우저를 실행시킬 수 있습니다. 우리는 이 기기들 위에서 HTML5 게임을 플레이할 수 있습니다. 웹 화면 위에 게임을 랜더링하는 것은 어려운 일입니다. 하지만 그전에 반드시 필요한 일이 있습니다. 적절한 컨트롤 메카니즘을 제공하는 일입니다. 플랫폼이 다양한만큼 선택할 수 있는 방법도 무척 다양합니다. 터치를 이용하는 방법부터 마우스와 키보드를 이용하는 방법, 게임패드를 이용하는 방법, 심지어 TV 리모콘이나 … 바나나를 이용하는 방법까지. 이런 인터페이스를 다루는 새로운 기사 시리즈인 컨트롤 메카니즘을 지금 MDN 에서 보실 수 있습니다.

captainrogers2-cover

실제 사례를 보여 드리겠습니다. Phaser 프레임워크로 이런 컨트롤 메카니즘들을 구현한 Captain Rogers: Battle at Andromeda demo 게임입니다. 이 게임을 보면 플랫폼에 따라 게임을 플레이하는 방식이 어떻게 달라지는지 느낄 수 있습니다. 또 다양한 플랫폼 별로 다양한 빌드 과정을 가질 필요가 없다는 사실도 알 수 있습니다. 웹이 원래부터 가지고 있는 멀티-플랫폼 지원 속성 덕분에 당신은 코딩에 큰 노력을 들이지 않고서도 각 기기들에 맞는 게임 컨트롤 메카니즘을 구현할 수 있습니다.

controls-purejsgame

GitHub 에 순수 JavaScript 로 만든 아주 작은 컨트롤 데모 프로젝트가 오픈소스로 존재합니다. 이 데모 프로젝트를 통해 컨트롤 메카니즘의 구현 방식을 볼 수 있습니다. 당신이 만드는 게임에 이 데모 프로젝트를 적용해 보세요. 지금 당장 코드를 파헤쳐 보세요. 그게 어렵다면 아래 요약된 설명을 읽어 보세요.

모바일 터치

먼저 모바일 터치를 지원하는 것에 대해 이야기해 봅시다. HTML5 게임의 경우 모바일 퍼스트 정책이 점점 더 인기를 얻고 있습니다.

document.addEventListener("touchstart", touchHandler);
document.addEventListener("touchmove", touchHandler);
function touchHandler(e) {
    if(e.touches) {
        playerX = e.touches[0].pageX - canvas.offsetLeft - playerWidth / 2;
        playerY = e.touches[0].pageY - canvas.offsetTop - playerHeight / 2;
    }
}

몇 줄 안되는 이 JavaScript 코드가 모바일 게임의 터치 컨트롤을 위해 필요한 전부입니다. 처음 2줄은 관심 있는 터치 이벤트에 대한 이벤트 리스너를 설정하는 코드입니다. 이 이벤트 리스너가 스크린을 터치하거나 터치한 손가락을 움직이는 이벤트를 처리합니다. 해당 함수는 터치 이벤트가 발생했는 지 체크하고, 우주선이 게임 캔버스 위의 적절한 위치에 그려질 수 있도록 플레이어의 좌표를 설정합니다.

이것은 단지 기본일 뿐입니다. 우리는 여러가지 가능성을 고려해서 코드를 확장할 수 있으며, 또 확장해야만 합니다. 예를 들어, 멀티-터치 또는 제스쳐를 지원해야 합니다. 이런 확장은 당신이 만들려고하는 게임의 종류에 따라 그리고 컨트롤하려는 대상에 따라 결정됩니다. 스크린 위에 버튼을 제공해서 미리 정해진 어떤 액션을 수행하게 할 수도 있습니다. 예를 들면 이동을 위한 방향 버튼이나 무기 발사 버튼 말이죠. 보다 자세한 내용을 알고 싶다면 모바일 터치 컨트롤 기사를 읽어 보세요.

데스크탑 마우스와 키보드

“이동을 위한 방향 버튼”에 대해 말해봅시다. 우리는 모바일 기기의 스크린 위에 방향 버튼을 그릴 수 있습니다. 하지만 데스크탑을 위해서도 방향 버튼을 처리해야 합니다. 커서 키 또는 WASD 키가 게임 속 캐릭터를 움직이기 위해 자주 쓰이는 방법입니다. 아래 코드는 커서 키 처리에 관한 구현 사례입니다.

document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
    if(e.keyCode == 39) {
        rightPressed = true;
    }
    else if(e.keyCode == 37) {
        leftPressed = true;
    }
    if(e.keyCode == 40) {
        downPressed = true;
    }
    else if(e.keyCode == 38) {
        upPressed = true;
    }
}

이 코드는 어떤 키가 눌렸는지 지속적으로 감시하고 눌려진 키의 정보를 기록합니다. 기록된 키 정보는 드로잉 루프에서 처리됩니다.

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if(rightPressed) {
        playerX += 5;
    }
    else if(leftPressed) {
        playerX -= 5;
    }
    if(downPressed) {
        playerY += 5;
    }
    else if(upPressed) {
        playerY -= 5;
    }
    ctx.drawImage(img, playerX, playerY);
    requestAnimationFrame(draw);
}

플레이어의 위치를 나타내는 x 변수와 y 변수를 계산해서 새로운 위치에 우주선을 그립니다.

controls-howtoplay

데스크탑의 마우스 이벤트와 모바일의 터치 이벤트는 코딩 관점에서 볼 때 매우 비슷합니다. 우리가 해야 할 일은 터치 이벤트 또는 클릭 이벤트가 어디에서 발생했는지 확인해서 플레이어의 위치를 갱신하는 것입니다.

document.addEventListener("mousemove", mouseMoveHandler);
function mouseMoveHandler(e) {
    playerX = e.pageX - canvas.offsetLeft - playerWidth / 2;
    playerY = e.pageY - canvas.offsetTop - playerHeight / 2;
}

mousemove 이벤트가 감지되면, 마우스 포인터의 위치가 바뀜에 따라 우주선의 위치가 조정됩니다. 당신이 만든 게임을 데스크탑에서 키보드와 마우스로 플레이하게 하기 위해 필요한 것은 이게 전부입니다. 보다 자세한 내용을 알고 싶다면 마우스와 키보드를 이용한 데스크탑 컨트롤 기사를 읽어 보세요.

게임패드

제가 가장 좋아하는 컨트롤 장치입니다. 저는 프리젠테이션 할 때 제가 만든 HTML5 슬라이드를 조종하기 위해 Gamepad API 를 사용합니다. 저는 이 방법에 대해 몇 번 발표한 적이 있습니다. 몇 건의 기사를 쓰기도 했습니다. 몇 개의 게임도 만들었고, 관련된 모든 정보를 Gamepad API Content Kit 에 정리했습니다. 데스크탑에서 게임콘솔 같은 느낌을 가질 수 있다는 것은 멋진 일입니다. 더구나 웹 기술입니다! Captain Rogers 도 게임패드로 플레이하면 훨씬 좋은 느낌을 얻을 수 있습니다.

controls-gamepadinfo

Gamepad API 를 지원하는 일은 터치나 키보드를 지원하는 것보다 다소 복잡합니다. 하지만 여전히 할 만한 일입니다.

window.addEventListener("gamepadconnected", gamepadHandler);
function gamepadHandler(e) {
    controller = e.gamepad;
}
function gamepadUpdateHandler() {
    buttonsPressed = [];
    if(controller.buttons) {
        for(var b=0; b<controller.buttons.length; b++) {
            if(controller.buttons[b].pressed) {
                buttonsPressed.push(b);
            }
        }
    }
}
function gamepadButtonPressedHandler(button) {
    var press = false;
    for(var i=0; i<buttonsPressed.length; i++) {
        if(buttonsPressed[i] == button) {
            press = true;
        }
    }
    return press;
}

게임패드가 연결되면 관련 이벤트가 발생합니다. 이때 우리는 나중에 사용할 변수에 필요한 레퍼런스를 저장합니다. 게임패드의 상태가 변할 때마다 눌린 버튼들의 정보가 담긴 배열이 새로 생성됩니다. 우리는 이 배열을 이용해서 현재 상태를 최신으로 유지할 수 있습니다. 이 배열을 순회하는 함수가 어떤 버튼이 눌렸는지 확인합니다. 이렇게 확인된 정보는 드로잉 루프에서 활용됩합니다. 드로잉 루프 처리 방식은 키보드 때와 비슷합니다.

function draw() {
    // ...
    gamepadUpdateHandler();
    if(gamepadButtonPressedHandler(0)) {
        playerY -= 5;
    }
    else if(gamepadButtonPressedHandler(1)) {
        playerY += 5;
    }
    if(gamepadButtonPressedHandler(2)) {
        playerX -= 5;
    }
    else if(gamepadButtonPressedHandler(3)) {
        playerX += 5;
    }
    if(gamepadButtonPressedHandler(11)) {
        alert('BOOM!');
    }
    // ...
}

이와 같은 방법으로 우리는 DPad 버튼으로 우주선을 조종하고, A 버튼으로 폭탄을 발사할 수 있습니다. 방향키도 감지할 수 있습니다. 게임패드 입력을 처리하는 자신만의 작은 라이브러리를 만들 수도 있습니다. 보다 자세한 내용을 알고 싶다면 데스크탑 게임패드 컨트롤 기사를 읽어 보세요.

특이한 컨트롤러들

만약 원한다면, 컨트롤 방식에 대한 지원 범위를 조금 더 넓힐 수 있습니다. 우리는 거실에 있는 커다란 TV 스크린 위에서 리모콘으로 게임을 플레이할 수도 있고, 노트북 앞에서 손을 흔들 수도 있으며, PC 에 연결된 음식들을 두들길 수도 있습니다.

controls-tvremote

예를 들어, 파나소닉 TV 리모콘은 놀라울 정도로 훌륭한 게임 컨트롤러입니다. TV 리모콘의 경우 키보드 이벤트 코드를 재사용할 수 있고, 리모콘의 방향키 코드가 키보드의 커서키 코드값과 똑같기 때문에 – 37, 38, 39, 40 – 아주 쉽게 처리할 수 있습니다. 만약 리모콘에만 있는 특수한 버튼들을 사용해야 한다면, 여기 아주 상세한 내용이 담긴 기사가 있습니다. 읽어 보세요.

controls-leapmotion

리모콘에 있는 버튼을 누르는 대신, 우리는 Leap Motion 기능을 이용해서 우리 손의 위치 등 우주선 조종을 위해 필요한 파라메터들을 얻을 수 있습니다. 아무것도 터치할 필요가 없습니다. 미리 정의한 루프를 이용해서 우리는 손에 관한 상세 정보를 얻을 수 있습니다.

Leap.loop({
    hand: function(hand) {
        horizontalDegree = Math.round(hand.roll() * toDegrees);
        verticalDegree = Math.round(hand.pitch() * toDegrees);
        grabStrength = hand.grabStrength;
    }
});

그리고, 이렇게 얻은 정보를 이용해서 플레이어의 위치를 갱신할 수 있습니다.

function draw() {
    // ...
    if(horizontalDegree > degreeThreshold) {
        playerX -= 5;
    }
    else if(horizontalDegree < -degreeThreshold) {
        playerX += 5;
    }
    if(verticalDegree > degreeThreshold) {
        playerY += 5;
    }
    else if(verticalDegree < -degreeThreshold) {
        playerY -= 5;
    }
    if(grabStrength == 1) {
        alert('BOOM!');
    }
    // ...
}

도플러 효과, Proximity API, MaKey MaKey 같은 다른 재밌는 컨트롤 메카니즘들의 이용 사례를 이상한 컨트롤러들 기사에서 볼 수 있습니다.

요약

최근에, HTML5 게임 플레이를 지원하는 크고 작은 장치들의 숫자가 늘고 있습니다. 손목시계? 음성? 가능성은 무한합니다. 기억하세요. 컨트롤 메카니즘은 더 많이 지원할수록 더 좋습니다. 왜냐하면 우리가 만든 게임이 더 많은 기기들 위에서, 또 더 많은 플랫폼들 위에서 실행될 수 있기 때문입니다. 브라우저에 의해 가능해진 기회를 누려 보세요.

이 글은 Andrzej Mazur 이 쓴 Control mechanisms in JavaScript games 의 한국어 번역본입니다.

작성자: ingeeKim

"누구에게나 평등하고 자유로운 웹"에 공감하는 직장인.

ingeeKim가 작성한 문서들…


댓글이 없습니다.

댓글 쓰기