Roll It 만들기

Justin Gitlin
Justin Gitlin

Roll It은 휴대전화와 컴퓨터의 브라우저만을 사용하여 고전적인 보드워크 게임을 재해석한 Chrome 실험입니다. 휴대전화의 브라우저를 사용하면 손목을 빠르게 돌리기만 하면 공을 조준하고 굴릴 수 있으며, 컴퓨터의 브라우저는 WebGL과 캔버스를 사용하여 Roll It Alley의 실시간 그래픽을 렌더링합니다. 두 장치는 WebSocket을 통해 통신합니다. 앱 없음 다운로드 없이 즐기세요. 토큰이 없습니다. 최신 브라우저만 있으면 됩니다.

Legwork는 Google Creative Lab의 지침에 따라 사용자 환경, 인터페이스, 게임 환경을 개발한 다음 개발 파트너인 Mode Set와 협력하여 Roll It을 구축했습니다. 프로젝트를 진행하는 동안 여러 가지 독특한 과제가 있었습니다. 이 도움말에서는 Google에서 사용한 기법, 발견한 비법, Roll It을 통해 성과를 거두면서 얻은 교훈을 소개합니다.

3D 워크플로

초창기의 어려움 중 하나는 당사 소프트웨어의 3D 모델을 웹 지원 파일 형식으로 가져오는 최선의 방법을 찾는 것이었습니다. Cinema 4D 내에서 애셋을 만든 후 모델을 단순화하여 로우 폴리곤 메시로 변환했습니다. 각 메시에는 색상 및 텍스처링을 위한 객체의 부분을 구별하기 위한 특정 다각형 선택 태그가 제공됩니다. 그런 다음, Collada 1.5 (.dae) 파일로 내보낸 후 오픈소스 3D 프로그램인 Blender로 가져와 3.js와 호환되는 파일을 만들 수 있었습니다. 모델을 올바르게 가져왔는지 확인한 후 메시를 JSON 파일로 내보내고 코드를 사용해 조명을 적용했습니다. Google에서 취한 조치를 보다 자세히 살펴보면 다음과 같습니다.

C4D 내에서 객체를 모델링합니다. 메시 노멀이 바깥쪽을 향해야 합니다.
C4D 내에서 객체를 모델링합니다. 메시 노멀이 바깥쪽을 향해야 합니다.
다각형 선택 도구를 사용하여 텍스처링하려는 특정 영역의 선택 태그를 만듭니다. 각 선택 태그에 소재를 적용합니다.
다각형 선택 도구를 사용하여 텍스처링하려는 특정 영역의 선택 태그를 만듭니다. 각 선택 태그에 소재를 적용합니다.
메시를 COLLADA 1.5 .dae 파일로 내보냅니다.
메시를 COLLADA 1.5 .dae 파일로 내보냅니다.
'2D 도형 내보내기'가 선택되어 있는지 확인합니다. 삼각형 내보내기는 일반적으로 코드 측면에서 3D 환경에서 더 광범위하게 지원되지만 다각형 수가 두 배가 된다는 단점이 있습니다. 다각형 수가 클수록 모델에 더 많은 부담을 주게 됩니다. 따라서 성능이 느려지면 체크박스를 선택한 상태로 둡니다.
'2D 도형 내보내기'가 선택되어 있는지 확인합니다. 삼각형 내보내기는 일반적으로 코드 측면에서 3D 환경에서 더 광범위하게 지원되지만 다각형 수가 두 배가 된다는 단점이 있습니다. 다각형 수가 클수록 모델에 더 많은 부담을 주게 됩니다. 따라서 성능이 저하되면 체크박스를 선택한 상태로 둡니다.
Collada 파일을 Blender로 가져옵니다.
Collada 파일을 Blender로 가져옵니다.
믹서로 가져온 후에는 재료와 선택 태그도 함께 이전된 것을 확인할 수 있습니다.
믹서기로 가져온 후에는 소재와 선택 태그도 함께 이전된 것을 확인할 수 있습니다.
개체를 선택하고 개체의 재질을 원하는 대로 조정합니다.
개체를 선택하고 객체의 재료를 원하는 대로 조정합니다.
파일을 3.js 파일로 내보냅니다.
webGL 호환성을 위해 파일을 3.js 파일로 내보냅니다.

코드 작성

Roll - 오픈소스 라이브러리로 개발되었으며 최신 브라우저에서 기본적으로 실행됩니다. WebGL 및 WebSockets와 같은 기술을 통해 웹은 콘솔 수준의 게임 및 멀티미디어 경험에 밀접히 맞서고 있습니다. 개발자가 이러한 환경을 빌드할 수 있는 편리함과 편의성은 HTML 개발에 보다 현대적인 도구를 사용할 수 있게 됨에 따라 크게 발전하고 있습니다.

개발 환경

Roll It의 원본 코드는 대부분 CoffeeScript로 작성된 깔끔하고 간결한 언어이며 형식이 올바르고 린트된 자바스크립트로 트랜스컴파일됩니다. CoffeeScript는 뛰어난 상속 모델과 더 깔끔한 범위 처리로 OOP 개발에 빛을 발합니다. CSS는 SASS 프레임워크로 작성되었으며, 이 프레임워크는 개발자에게 프로젝트의 스타일시트를 개선하고 관리하는 데 유용한 여러 가지 도구를 제공합니다. 이러한 시스템을 빌드 프로세스에 추가하려면 설정하는 데 약간의 시간이 걸리지만 Roll It과 같은 대규모 프로젝트의 경우 확실히 그만한 가치가 있습니다. 개발 중에 애셋을 자동 컴파일하도록 Ruby on 레일 서버를 설정합니다. 따라서 이러한 모든 컴파일 단계가 투명하게 공개되었습니다.

Google은 간소화되고 편안한 코딩 환경을 조성하는 것 외에도 사이트 로드 속도를 높이기 위해 요청을 최소화하도록 애셋을 수동으로 최적화했습니다. 모든 이미지를 몇 가지 압축 프로그램(ImageOptimImageAlpha)을 통해 실행했습니다. 각 프로그램은 고유한 방식(무손실 및 손실)으로 이미지를 최적화합니다. 적절한 설정 조합을 사용하면 이미지의 파일 크기를 크게 줄일 수 있습니다. 이렇게 하면 외부 이미지를 로드할 때 대역폭이 절약될 뿐만 아니라 이미지가 최적화되면 HTML, CSS 및 JavaScript에 인라인으로 삽입할 수 있도록 이미지가 훨씬 작은 base64로 인코딩된 문자열로 변환됩니다. base64 인코딩과 관련하여 이 기법을 사용하여 Open Sans WOFF 및 SVG 글꼴 파일을 CSS에 직접 삽입했으며, 그 결과 총 요청 수가 훨씬 줄었습니다.

물리학 지원 3D 장면

THREE.js는 웹용 유비쿼터스 3D JavaScript 라이브러리입니다. 또한 낮은 수준의 3D 수학 및 하드웨어 기반 WebGL 최적화를 제공합니다. 이 WebGL 최적화를 사용하면 단순 필사자가 사용자 지정 셰이더를 작성하거나 수동 행렬 변환을 수행할 필요 없이 조명이 밝고 아름다운 대화형 3D 장면을 쉽게 만들 수 있습니다. Physijs는 JavaScript로 변환된 인기 있는 C++ 물리학 라이브러리를 위한 THREE.js 전용 래퍼입니다. 우리는 이 라이브러리를 활용하여 공을 굴리고, 점프하고, 대상을 향해 튀어오르는 동작을 3D로 시뮬레이션했습니다.

처음부터 Google은 공을 굴리는 물리적인 경험을 현실감 있게 만드는 것뿐만 아니라 게임 속 물체가 사실적인 느낌을 주도록 하는 데에 착수했습니다. 이를 위해서는 Physijs 장면의 전체 중력, 플레이어가 던지는 과정에서 공이 굴리는 속도, 레인 점프의 경사, 공과 레인 소재의 마찰 및 탄력성 (탄성) 속성을 조정해야 했습니다. 더 큰 중력과 더 빠른 속도 덕분에 더욱 사실적인 게임 경험을 선사할 수 있었습니다.

부드럽게 하기

대부분의 최신 브라우저 및 비디오 카드 조합은 WebGL 환경에서 기본 하드웨어 기반 앤티앨리어싱을 활용해야 하지만 일부는 제대로 작동하지 않습니다. 앤티앨리어싱이 기본적으로 작동하지 않는 경우, THREE.js 장면에서 단단하고 대비되는 가장자리가 들쭉날쭉하고 보기 좋지 않을 수 있습니다 (적어도 안정적이었던 눈에는 안 보이네요).

다행히 해결책이 있습니다. 코드 스니펫을 통해 플랫폼이 기본적으로 앤티앨리어싱을 지원하는지 감지할 수 있습니다. 그렇다면 계속 진행해도 됩니다. 그렇지 않은 경우 3.js와 함께 제공되는 후처리 셰이더 시리즈가 도움이 될 수 있습니다. 바로 FXAA 앤티앨리어싱 필터입니다. 이 셰이더로 모든 프레임마다 렌더링된 장면을 다시 그리면 일반적으로 선과 가장자리가 훨씬 더 부드러워집니다. 아래 데모를 참고하세요.

// Check for native platform antialias support via the THREE renderer
// from: http://codeflow.org/entries/2013/feb/22/how-to-write-portable-webgl/#antialiasing
var nativeAntialiasSupport = (renderer.context.getParameter(renderer.context.SAMPLES) == 0) ? false : true;

가속도계 기반 게임 컨트롤

굴리기 마법의 대부분은 플레이어가 휴대전화로 볼을 굴리는 동작에서 비롯됩니다. 휴대기기는 한동안 브라우저 내의 가속도계에 액세스할 수 있었지만, 업계로서 우리는 이제 막 웹에서 모션 기반 동작 인식을 탐구하기 시작했습니다. 휴대전화의 가속도계가 제공하는 데이터로 인해 약간의 제약이 있지만 약간의 창의성을 발휘하면 새롭고 멋진 경험을 할 수 있습니다.

롤 감지 기본 '롤' 동작은 창의 deviceorientation 이벤트에서 발생한 최근 가속도계 업데이트 10개를 추적하는 것으로 시작됩니다. 현재 기울기 값에서 이전 기울기 값을 빼서 이벤트 간의 각도 델타를 저장합니다. 그런 다음 마지막 10개의 각 델타를 지속적으로 합산하여 휴대전화가 공간을 이동할 때 연속적인 회전을 감지할 수 있습니다. 휴대전화가 스위핑 각도 변경 기준점을 초과하면 롤이 트리거됩니다. 그런 다음 스윕에서 가장 큰 단일 기울기 델타를 찾아 공의 속도를 추정할 수 있습니다. Roll It에서 이 속도는 각 가속도계 업데이트에 첨부된 타임스탬프를 사용하여 정규화됩니다. 이렇게 하면 가속도계 업데이트가 다양한 기기의 브라우저로 스트리밍되는 다양한 속도를 완화할 수 있습니다.

WebSockets 통신

플레이어가 휴대전화로 공을 굴리면 공을 던지라는 메시지가 휴대전화에서 노트북으로 전송됩니다. 이 '롤' 메시지는 두 컴퓨터 간의 WebSocket 연결을 통해 JSON 데이터 객체를 통해 전송됩니다. JSON 데이터는 작으며 주로 메시지 유형, 투사 속도, 조준 방향으로 구성됩니다.

{
  "type": "device:ball-thrown",
  "speed": 0.5,
  "aim": 0.1
}

노트북과 휴대전화 간의 모든 통신은 이와 같은 작은 JSON 메시지를 통해 이루어집니다. 게임이 데스크톱에서 상태를 업데이트하거나 사용자가 전화기의 버튼을 기울이거나 탭할 때마다 컴퓨터 간에 WebSocket 메시지가 전송됩니다. 이 통신을 간단하고 관리하기 쉽게 유지하기 위해, WebSockets 메시지는 양쪽 브라우저에서 단일 이탈 지점을 사용하여 브로드캐스트됩니다. 반대로 수신 브라우저에는 단일 진입점이 있으며, 하나의 WebSocket 객체가 양쪽 끝에서 모든 수신 및 발신 메시지를 처리합니다. WebSocket 메시지가 수신되면 jQuery의 trigger() 메서드를 사용하여 JSON 데이터가 JavaScript 앱 내에서 다시 브로드캐스트됩니다. 이 시점에서 수신 데이터는 다른 맞춤 DOM 이벤트와 같은 방식으로 작동하며, 애플리케이션의 다른 객체에서 가져와서 처리할 수 있습니다.

var websocket = new WebSocket(serverIPAddress);

// rebroadcast incoming WebSocket messages with a global event via jQuery
websocket.onmessage = function(e) {
  if (e.data) {
    var obj = JSON.parse(e.data);
    $(document).trigger(data.type, obj);
  }
};

// broadcast outgoing WebSocket messages by passing in a native .js object
var broadcast = function(obj) {
  websocket.send(JSON.stringify(obj));
};

Roll It's WebSocket 서버는 두 기기가 게임 코드와 동기화되면 즉시 생성됩니다. Roll It의 백엔드는 Go를 사용하여 Google Compute EngineApp Engine 플랫폼에서 빌드되었습니다.

메뉴 화면 기울이기

게임플레이 중에 사용되는 이벤트 기반 WebSocket 메시지 외에도 Roll It의 메뉴는 휴대전화를 기울이고 버튼을 탭하여 선택 항목을 확인하는 방식으로 제어됩니다. 그러려면 휴대전화에서 노트북으로 전송되는 기울기 데이터의 일관된 스트림이 필요합니다. 대역폭을 줄이고 불필요한 업데이트를 전송하지 않기 위해 이러한 메시지는 기기의 기울기가 몇 도 이상 변경된 경우에만 전송됩니다. 휴대전화가 탁자 위에 평평하게 놓여 있다면 기울이기 데이터 스트림을 보내도 무의미합니다. 전송 속도도 제한됩니다. 기기가 활발하게 기울어지더라도 Roll It에서 초당 15개 이하의 WebSockets 메시지가 전송되지 않습니다.

컴퓨터에서 기울기 값을 선택하면 부드러운 느낌을 유지하기 위해 시간 경과에 따라 requestAnimationFrame를 사용하여 보간됩니다. 그 결과 회전 메뉴와 공이 굴려 사용자의 선택 여부를 나타냅니다. 휴대전화에서 기울기 데이터를 전송할 때 이러한 DOM 요소는 requestAnimationFrame 루프 내에서 CSS 변환을 다시 계산하여 실시간으로 업데이트됩니다. 메뉴의 컨테이너는 단순히 회전하지만 공은 바닥을 따라 굴리는 것처럼 보입니다. 이 효과를 얻기 위해 공의 x좌표와 공의 회전을 연관 짓는 기본적인 삼각법을 구현합니다. 간단한 방정식은 다음과 같습니다. 회전 = x / (지름 * π)

마무리

굴리기 - 시대의 표시입니다. 개발을 주도한 오픈소스 프로젝트, 책상과 주머니에 있는 기기의 처리 능력, 플랫폼으로서의 웹 상태 등 오픈 웹에 연결되는 것은 정말 흥미롭고도 혁신적인 시기입니다. 불과 몇 년 전만 해도 이 기술의 대부분은 독점적인 시스템에만 존재하여 자유롭게 사용하고 배포할 수 없었습니다. 오늘날 우리는 매일 새로운 퍼즐 조각을 만들고 공유하면서 적은 노력으로도 복잡한 경험을 실현할 수 있습니다. 망설이지 마시고 멋진 앱을 만들어 전 세계와 공유하세요.

Roll It 로고