서버와 Phaser3에서 간단한 멀티 플레이어 게임 만들기 - 1 부

이 멀티 파트 튜토리얼에서는 Phaser 및 Socket.io와 함께 간단한 멀티 플레이어 게임을 제작할 것입니다. 멀티 플레이어 게임의 경우 클라이언트 - 서버 게임 아키텍처를 따르고 서버에서 실행되도록 Phaser를 설정하고 이를 신뢰할 수있는 서버로 사용합니다. 클라이언트 - 서버 게임 아키텍처에 익숙하지 않은 경우 클라이언트가 플레이어에게 게임을 표시하고 플레이어의 입력을 처리하며 서버에 데이터를 전송해야합니다. 우리의 인증서버는 주요 Phaser 논리를 실행하는 책임이 있으며 각 클라이언트에 데이터를 전송할 책임이 있습니다.

이 튜토리얼의 목표는 멀티 플레이어 게임을 만드는 기본 사항을 가르치는 것입니다. 다음 방법을 배우게됩니다.

- 신뢰할 수있는 서버로 작동 할 Node.js 및 Express 서버를 설정합니다. 이 서버는 또한 클라이언트 측 파일 렌더링을 담당합니다.
- 서버에서 헤드리스 모드로 Phaser를 설정하고 실행하십시오.
- 우리의 클라이언트로 행동 할 기본 Phaser 3 게임을 설정하십시오.

- Socket.IO를 사용하면 서버와 클라이언트가 서로 통신 할 수 있습니다.

자습서 요구 사항

이 자습서에서는 Node.js와 npm을 사용하여 이 프로젝트에 필요한 필수 패키지를 설치합니다. 이 자습서를 수행하려면 Node.js 및 NPM을 로컬로 설치해야하며 그렇지 않으면 이미 설치되어있는 환경에 액세스해야 합니다. 또한 명령 프롬프트 (Windows) / 터미널 (Mac)을 사용하여 필수 패키지를 설치하고 노드 서버를 시작 / 중지합니다.

이러한 도구에 대한 사전 경험이 있으면 도움이되지만 이 자습서에서는 필요하지 않습니다. 이 튜토리얼의 초점이 Phaser로 게임을 만들고 있으므로 이 도구를 설치하는 방법은 다루지 않을 것입니다. 또한 이 자습서와 함께 Chrome 웹 브라우저에 액세스해야합니다. 마지막으로 필요한 것은 코드 편집을 위한 IDE 또는 텍스트 편집기입니다.

Node.js를 설치하려면 여기 링크를 클릭하고 LTS 버전을 선택하십시오. 이 자습서에서는 현재 버전을 다운로드하여 사용할 수 있지만 대부분의 사용자는 LTS 버전을 사용하는 것이 좋습니다. Node.js를 설치하면 NPM도 컴퓨터에 설치됩니다. 이러한 도구가 설치되면 다음 부분으로 넘어갈 수 있습니다.

서버 설정

우리가 할 첫 번째 일은 게임 파일을 제공 할 기본 Node.js 서버를 만드는 것입니다. 시작하려면 컴퓨터에 새 폴더를 만드십시오. 원하는 이름으로 부를 수 있습니다. 그런 다음 터미널에서 이 폴더로 이동하여 다음 명령을 실행합니다. npm init -f. 이렇게 하면 프로젝트 폴더에 package.json 파일이 만들어집니다. 이 파일을 사용하여 프로젝트가 의존하는 모든 패키지를 추적합니다.

프로젝트에 추가 할 첫 번째 패키지는 정적 인 클라이언트 측 파일을 렌더링하는 데 사용할 Node.js 웹 응용 프로그램 프레임 워크입니다. 터미널에서 다음 명령을 실행하십시오. npm install --save express 그러면 프로젝트의 node_modules 폴더에 해당 패키지와 필수 종속성이 설치됩니다. 이 명령은 express 모듈을 추가하여 package.json 파일을 업데이트합니다.

이제 프로젝트 폴더에 server라는 새 폴더를 만들고 이 폴더에 index.js라는 새 파일을 만듭니다. index.js를 열고 다음 코드를 추가하십시오.
const express = require('express');
const app = express();
const server = require('http').Server(app);

app.use(express.static(__dirname + '/public'));

app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});

server.listen(8081, function () {
console.log(`Listening on ${server.address().port}`);
});
위의 코드에서 우리는 다음을 수행했습니다.

- Express 모듈을 참조했습니다. 이 모듈은 정적 파일을 렌더링하는 데 도움이 되는 웹 프레임 워크입니다.
- 표현의 새로운 인스턴스를 만들고 app이라고 했습니다.
- 익스프레스가 HTTP 요청을 처리 할 수 있도록 HTTP 서버에 앱을 제공했습니다.
- Express에서 기본 제공되는 express.static 미들웨어 기능을 사용하여 정적 파일을 렌더링하도록 서버를 업데이트했습니다.
- 루트 페이지로 index.html 파일을 제공하도록 서버에 알립니다.

- 서버가 포트 8081에서 청취를 시작 했어야 합니다.

클라이언트 설정

기본 서버 코드가 끝나면 클라이언트 측 코드 설정 작업을 시작합니다. 서버 폴더에서 public이라는 새 폴더를 만듭니다. 이 폴더에 넣은 파일은 우리가 설정 한 서버에서 렌더링됩니다. 따라서 모든 정적 클라이언트 측 파일을 이 폴더에 저장하려고 합니다. 이제 공용 폴더에서 index.html이라는 새 파일을 만듭니다. index.html을 열고 다음 코드를 추가하십시오.
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
</head>

<body>
<script src="https://cdn.jsdelivr.net/npm/phaser@3.18.0/dist/phaser.min.js"></script>
<script src="js/game.js"></script>
</body>

</html>
그런 다음 공용 폴더에서 js라는 새 폴더를 만들고, 이 폴더에 game.js.라는 새 파일을 만듭니다. 이 파일에 다음 코드를 추가하십시오.
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: {
preload: preload,
create: create,
update: update
}
};

var game = new Phaser.Game(config);

function preload(){}
function create(){}
function update(){}
위의 코드에서 기본 HTML 파일을 만들고 Phaser 라이브러리를 참조했습니다. 마지막으로 새로운 Phaser Game 인스턴스를 만들었습니다.

기본 클라이언트 측 코드가 설정되면 서버를 테스트하고 모든 것이 올바르게 작동하는지 확인합니다. 터미널 / 명령 프롬프트로 돌아가서 node / index.js 명령을 실행하면 다음 줄이 표시됩니다. 8081에서 Listening이 표시됩니다. 이제 웹 브라우저를 열고 http : // localhost : 8081 /을 선택하면 웹 페이지에 검은 색 상자가 표시되고 개발자 도구에서 콘솔을 열면 게임이 실행중인 Phaser 버전의 로그 라인이 표시됩니다.


디버깅

다음 단계에서는 Headless 모드에서 Phaser를 실행하기 위해 서버를 설정합니다. 서버에서 가상 DOM을 실행해야 합니다. 그러나 먼저 서버에서 실행중인 Phaser 코드를 디버깅하는 것이 좋습니다. 코드를 디버깅하기 위해 노드의 --inspect 플래그와 Chrome의 개발자 도구를 사용하여 서버에서 실행중인 dom의 콘솔 출력을 볼 수 있습니다. 이 작업을 수행하려면 node --inspect  index.js 명령을 사용하여 서버를 중지했다가 다시 시작해야합니다. 그런 다음 Chrome을 열고 chrome : // inspect / # devices URL을 방문합니다. 다음과 유사한 화면이 나타납니다.

노드의 전용 DevTools 열기 링크를 클릭하면 dom의 출력을 표시하는 콘솔이있는 새 브라우저 창이 열립니다. 위의 링크를 클릭하면 서버를 중지했다가 다시 시작하더라도 콘솔은 노드 세션에 계속 연결되며 업데이트 된 출력이 표시됩니다.

권한있는 서버 설정

이제 클라이언트 측에서 Phaser를 실행 했으므로 Phaser를 서버에서 실행하는 작업을 진행할 것입니다. 서버에서 Phaser를 실행할 것이므로 제대로 작동하려면 몇 가지 추가 라이브러리를 프로젝트에 추가해야합니다. 우리가 필요로하는 첫 번째 패키지는 브라우저에서 DOM JavaScript API의 대부분을 재생성하는 데 사용되는 jsdom이며, HTML 파일을로드하고 상호 작용할 수 있습니다.

두 번째 패키지는 노드 캔버스입니다.이 캔버스는 Node.js에 캔버스 API를 구현 한 것입니다. 이 패키지가 필요한 이유는 헤드리스 모드로 실행 중일 때도 Phaser가 캔버스 API를 실행해야하기 때문입니다. 이 패키지를 설치하려면 터미널에서 다음 명령을 실행하십시오. 
npm install --save canvas 
npm install --save jsdom

이제 필요한 패키지가 설치되었으므로 서버에 Phaser를 실행하기위한 코드를 추가 할 수 있습니다. 서버 폴더에서 authoritative_server라는 새 폴더를 만듭니다. 이 폴더에서 index.html이라는 새 파일을 만들고 다음 코드를 추가합니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/phaser@3.18.0/dist/phaser.min.js"></script>
<script src="js/game.js"></script>
</body>
</html>
그런 다음 js라는 새 폴더를 만들고 여기에 game.js라는 새 파일을 만들고 여기에 다음 코드를 추가합니다.
const config = {
type: Phaser.HEADLESS,
parent: 'phaser-example',
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
debug: false,
gravity: { y: 0 }
}
},
scene: {
preload: preload,
create: create,
update: update
}
};

function preload() { }
function create() { }
function update() { }

const game = new Phaser.Game(config);
이 코드는 이전에 추가 한 클라이언트 측 코드와 비슷해야합니다. 이 둘의 주된 차이점은 Phaser 구성에서 Phaser.HEADLESS로 유형을 설정한다는 것입니다.

페이저 서버 코드를 제자리에 두면 다음으로 해야 할 일은 서버에 이러한 파일을 로드하고 실행하는 것입니다. server 폴더에서 index.js를 열고 다음 코드를 파일의 맨 위에 추가하십시오.
const path = require('path');
const jsdom = require('jsdom');
그런 다음 서버 변수 아래에 다음 코드를 추가하십시오.
const { JSDOM } = jsdom;
마지막으로 파일 맨 아래에 다음 코드를 추가합니다.
function setupAuthoritativePhaser() {
JSDOM.fromFile(path.join(__dirname, 'authoritative_server/index.html'), {
// To run the scripts in the html file
runScripts: "dangerously",
// Also load supported external resources
resources: "usable",
// So requestAnimatinFrame events fire
pretendToBeVisual: true
});
}
setupAuthoritativePhaser();
위의 코드에서 우리는 다음을 수행했습니다.

- 먼저 jsdom 패키지를 포함 시켰습니다. jsdom 패키지를 사용하면 서버에서 DOM API를 사용할 수 있습니다.
- 그런 다음 setupAuthoritativePhaser라는 새 함수를 만들어 함수를 호출했습니다.
- 이 함수에서 JSDOM의 fromFile 메소드를 사용하여 앞서 만든 index.html을로드했습니다. 
- fromFile 메서드를 호출 할 때 우리는 로드하려는 파일과 이 파일을 실행할 때 필요한 옵션이 들어있는 객체를 전달합니다. 이러한 옵션에는 다음이 포함됩니다.
  JSDOM이 스크립트를 실행할 수 있도록 허용
  JSDOM이 외부 리소스를로드 할 수 있도록 허용

  일반적인 비주얼 브라우저처럼 동작하도록 JSDOM에 지시

이제 코드를 저장하고 서버를 다시 시작하면 Phaser가 서버에서 실행 중이며 헤드리스 모드로 실행되고 있음을 확인해야합니다.


그러나 구현되지 않은 window.focus 메서드에 대한 오류 메시지가 표시되어야 합니다. 이 오류가 표시되는 이유는 현재 이 메서드가 jsdom에 구현되어 있지 않으며 이 메서드가 호출 될 때마다 이 오류가 표시된다는 것입니다. 이 오류를 해결하려면 서버에서 실행중인 Phaser가로드 한 마이너 변경 구성 객체 만 만들어야합니다. authoritative_server / js / game.js에서 config 객체에 다음 속성을 추가합니다.
autoFocus: false
이렇게하면 게임이 처음 부팅 할 때 Phaser가 window.focus ()를 호출하지 않게됩니다. 기본적으로 이 값은 true로 설정됩니다. 다음 섹션으로 넘어 가기 전에 서버 코드를 약간 변경해야 합니다. 현재 우리 서버는 청취를 시작하고 서버상의 Phaser가 작동하기 전에 클라이언트가 서버에 연결할 수 있습니다. 대신 클라이언트가 연결하기 전에 Phaser가 서버에서 실행되고 있는지 확인하고자 합니다.

이렇게하려면 가상 DOM이 준비되고 Express 서버가 시작될 때까지 기다려야합니다. server / index.js를 열고 파일에서 다음 코드 행을 제거합니다.
server.listen(8081, function () {
console.log(`Listening on ${server.address().port}`);
});
그런 다음 setupAuthoritativePhaser 함수를 다음 코드로 바꿉니다.
function setupAuthoritativePhaser() {
JSDOM.fromFile(path.join(__dirname, 'authoritative_server/index.html'), {
// To run the scripts in the html file
runScripts: "dangerously",
// Also load supported external resources
resources: "usable",
// So requestAnimatinFrame events fire
pretendToBeVisual: true
}).then((dom) => {
dom.window.gameLoaded = () => {
server.listen(8081, function () {
console.log(`Listening on ${server.address().port}`);
});
};
}).catch((error) => {
console.log(error.message);
});
}
마지막으로 authoritative_server / js / game.js 파일을 열고 파일 맨 아래에 다음 코드를 추가합니다.
window.gameLoadded();
방금 추가 한 코드를 살펴 보겠습니다.

fromFile 메서드는 약속을 반환하므로 .then ()을 사용하여 약속이 해결 될 때까지 기다린 다음 콜백 함수를 호출하게 할 수 있습니다. 이 콜백 함수에서는 서버를 시작하기위한 논리를 추가했습니다.

game.js에서 우리는 위의 콜백 함수에서 정의한 window.gameLoaded ()를 호출했습니다. Phaser 라이브러리를 로드 한 다음 게임 객체를 생성하기 때문에 우리는 서버를 시작하기 전에 이러한 작업이 완료되었는지 확인해야합니다. 따라서 이 새로운 함수가 추가되었습니다.

이제 변경 사항을 저장하고 서버를 다시 시작하면 고속 서버를 시작하기 전에 Phaser 게임이 생성 된 것을 볼 수 있습니다.

결론

서버에서 헤드리스 모드로 실행되는 Phaser를 사용하면 Part 1이 끝납니다. 2 부에서는 멀티 플레이어 게임을 계속 진행합니다.

프로젝트에 Socket.IO 라이브러리 추가하기.
게임에 플레이어를 추가하기위한 서버 로직 추가.
게임에서 플레이어를 제거하기위한 서버 로직 추가.
게임에 플레이어를 추가하기위한 클라이언트 측 로직 추가.

이 튜토리얼 시리즈의 시작을 즐겁게하고 도움이되기를 바랍니다. 
우리가 다음에 다루어야 할 것에 관한 질문이나 제안이 있으면, 아래의 의견에 우리에게 알려주십시오.

댓글 없음:

댓글 쓰기