WEBGL :: 'PHASER.JS' 카테고리의 글 목록

달력

52024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

다른 플레이어 표시

마지막 튜토리얼에서 우리는 게임에서 플레이어를 표시하는 논리를 추가하여 포장을 풀었습니다. 이제 우리는 게임에서 다른 플레이어를 표시하는 작업을 할 것입니다. 이 튜토리얼의 두 번째 파트에서는 newPlayer와 disconnect 이벤트를 내보내는 Socket.IO를 설정합니다. 이 두 가지 이벤트와 currentPlayers 이벤트에 대한 현재 논리를 사용하여 다른 플레이어를 추가하거나 제거합니다. 이렇게하려면 server / public / js / game.js를 열고 create 함수를 다음과 일치하도록 업데이트하십시오.

function create() {
var self = this;
this.socket = io();
this.players = this.add.group();

this.socket.on('currentPlayers', function (players) {
Object.keys(players).forEach(function (id) {
if (players[id].playerId === self.socket.id) {
displayPlayers(self, players[id], 'ship');
} else {
displayPlayers(self, players[id], 'otherPlayer');
}
});
});

this.socket.on('newPlayer', function (playerInfo) {
displayPlayers(self, playerInfo, 'otherPlayer');
});

this.socket.on('disconnect', function (playerId) {
self.players.getChildren().forEach(function (player) {
if (playerId === player.playerId) {
player.destroy();
}
});
});
}

방금 추가 한 코드를 살펴 보겠습니다.


currentPlayers 이벤트가 발생할 때 호출되는 함수를 업데이트하여 해당 플레이어가 현재 플레이어가 아닌 경우 플레이어 객체를 반복 할 때 displayPlayers 함수를 호출합니다.

우리는 socket.on ()을 사용하여 newPlayer를 수신하고 이벤트 연결을 끊습니다.

newPlayer 이벤트가 발생하면 displayPlayers 함수를 호출하여 새 플레이어를 게임에 추가합니다.

연결 해제 이벤트가 발생하면 해당 플레이어의 ID를 가져와 해당 플레이어의 배를 게임에서 제거합니다. 우리는 플레이어 그룹에서 getChildren () 메서드를 호출하여이를 수행합니다. getChildren () 메서드는 해당 그룹에있는 모든 게임 객체의 배열을 반환하며 여기에서 forEach () 메서드를 사용하여 해당 배열을 반복합니다.

마지막으로 destroy () 메서드를 사용하여 해당 게임 객체를 게임에서 제거합니다.


다른 플레이어를 우리 게임에 추가하는 새로운 논리를 테스트하기 전에이 플레이어를 위해 자산을로드해야합니다. 그 자산을 여기서 찾을 수 있습니다.


이 이미지는 public / assets 폴더에 저장해야합니다. 이미지가 있으면 이미지를 게임에로드 할 수 있습니다. 프리로드 함수에 다음 행을 추가하십시오.

this.load.image('otherPlayer', 'assets/enemyBlack5.png');

이제 브라우저에서 게임을 새로 고침하면 플레이어의 배가 계속 표시됩니다. 다른 탭이나 브라우저를 열고 게임으로 이동하면 게임 창에 여러 개의 스프라이트가 나타나야 하며, 해당 게임 중 하나를 닫으면 다른 게임에서 스프라이트가 사라지는 것을 볼 수 있습니다.


플레이어 입력 처리

게임에서 모든 플레이어를 표시하기 위한 논리를 사용하여 플레이어 입력을 처리하고 플레이어가 움직 이도록 할 것입니다. Phaser의 내장 키보드 관리자를 사용하여 플레이어 입력을 처리하고 플레이어를 클라이언트 측에서 직접 이동하는 대신 Socket.IO를 사용하여 플레이어 입력을 서버에 보냅니다. 이렇게 하려면 public / js / game.js의 create 함수 맨 아래에 다음 코드를 추가하십시오.

this.cursors = this.input.keyboard.createCursorKeys();
this.leftKeyPressed = false;
this.rightKeyPressed = false;
this.upKeyPressed = false;

이렇게하면 커서 객체를 네 개의 기본 Key 객체 (위쪽, 아래쪽, 왼쪽 및 오른쪽)로 채우고 키보드의 해당 화살표에 바인딩합니다. 그런 다음, 업데이트 기능에서 이러한 키가 눌러져 있는지 확인하면됩니다. 우리는 또한 어떤 키가 현재 눌려지고 있는지 추적하는 세 가지 새로운 변수를 만들었습니다.이 변수는 업데이트 기능에 사용될 것입니다.


Socket.IO를 사용하여 플레이어의 입력을 서버에 전송할 것이므로 이 키 중 하나를 누르고 있으면 언제든지 서버에 메시지를 보낼 수 있습니다. 그러나 이렇게 하면 필요하지 않은 많은 수의 호출이 서버에 발생합니다. 그 이유는 플레이어가 처음 키를 눌렀을 때와 키를 놓을 때를 인식하기 만하면 되기 때문입니다. 이것을 추적하기 위해 위에서 만든 세 변수를 사용하여 키가 눌려져있는 상태를 저장하고 상태가 변경되면 서버에 메시지를 보냅니다.


이제 public / js / game.js의 업데이트 함수에 다음 코드를 추가합니다.

const left = this.leftKeyPressed;
const right = this.rightKeyPressed;
const up = this.upKeyPressed;

if (this.cursors.left.isDown) {
this.leftKeyPressed = true;
} else if (this.cursors.right.isDown) {
this.rightKeyPressed = true;
} else {
this.leftKeyPressed = false;
this.rightKeyPressed = false;
}

if (this.cursors.up.isDown) {
this.upKeyPressed = true;
} else {
this.upKeyPressed = false;
}

if (left !== this.leftKeyPressed || right !== this.rightKeyPressed || up !== this.upKeyPressed) {
this.socket.emit('playerInput', { left: this.leftKeyPressed, right: this.rightKeyPressed, up: this.upKeyPressed });
}

방금 추가 한 코드를 살펴 보겠습니다.


먼저 왼쪽, 오른쪽 및 위로 세 가지 변수를 새로 만들었습니다. 이 변수는 이전에 누른 키의 상태를 저장하는 데 사용됩니다.

그런 다음 위로, 왼쪽 또는 오른쪽 키를 눌렀는지 확인합니다. 그런 경우 keyPressed 변수를 새 상태로 업데이트하고 키가 눌러지지 않은 경우 해당 변수를 false로 설정합니다.

마지막으로, 플레이어가 업 키를 누르지 않고 현재 키가 눌려 있지 않은 경우와 같이 키 중 하나의 상태가 변경되었는지 확인합니다. 상태가 변경되면 각 키의 상태를 전달하는 playerInput 메시지를 내 보냅니다.


다음으로 새로운 playerInput 메시지를 처리하기 위해 서버의 로직을 업데이트해야합니다. 이렇게하려면 authoritative_server / js / game.js를 열고 socket.on ( 'disconnect', function () {} 밑에 다음 코드를 추가합니다.

socket.on('playerInput', function (inputData) {
handlePlayerInput(self, socket.id, inputData);
});


그런 다음 update 함수 아래에 다음 코드를 추가합니다.

function handlePlayerInput(self, playerId, input) {
self.players.getChildren().forEach((player) => {
if (playerId === player.playerId) {
players[player.playerId].input = input;
}
});
}

위의 코드에서 우리는 다음을 수행했습니다.


먼저 playerInput 메시지를 듣고 이 메시지가 수신되면 handlePlayerInput이라는 새로운 함수를 호출하고 현재 장면에 대한 참조, 메시지를 전달한 플레이어의 소켓 ID 및 플레이어의 입력 키를 전달합니다

handlePlayerInput 함수에서 우리는 players 그룹의 getChildren 메소드를 호출하여 모든 게임 객체의 배열을 가져 왔습니다. 그런 다음 배열을 반복하여 해당 게임 객체의 playerId가 메시지를 전달한 플레이어의 소켓 ID와 일치하는지 확인합니다.

해당 playerId가 일치하면 플레이어 객체의 해당 플레이어 데이터를 업데이트하고 해당 플레이어의 입력을 저장합니다. 플레이어의 입력을 업데이트 기능에서 사용할 수 있도록 저장하고 있습니다.


다음으로 플레이어의 입력을 플레이어 객체의 새 속성에 저장하므로 초기에 이 객체에 기본값을 추가합니다. io.on ( 'connection') 콜백 함수에서 플레이어 [socket.id] 객체에 다음 코드를 추가합니다.

input: {
left: false,
right: false,
up: false
}

이 객체는 다음과 같이 보일 것입니다 :

players[socket.id] = {
rotation: 0,
x: Math.floor(Math.random() * 700) + 50,
y: Math.floor(Math.random() * 500) + 50,
playerId: socket.id,
team: (Math.floor(Math.random() * 2) == 0) ? 'red' : 'blue',
input: {
left: false,
right: false,
up: false
}
};

이제 우리는 각 플레이어의 게임 객체를 이동시키는 업데이트 기능에 로직을 추가 할 수 있습니다.


업데이트 함수에 다음 코드를 추가합니다.

this.players.getChildren().forEach((player) => {
const input = players[player.playerId].input;
if (input.left) {
player.setAngularVelocity(-300);
} else if (input.right) {
player.setAngularVelocity(300);
} else {
player.setAngularVelocity(0);
}

if (input.up) {
this.physics.velocityFromRotation(player.rotation + 1.5, 200, player.body.acceleration);
} else {
player.setAcceleration(0);
}

players[player.playerId].x = player.x;
players[player.playerId].y = player.y;
players[player.playerId].rotation = player.rotation;
});
this.physics.world.wrap(this.players, 5);
io.emit('playerUpdates', players);

방금 추가 한 코드를 살펴 보겠습니다.


먼저 플레이어 그룹의 getChildren 메서드를 호출하여 플레이어의 게임 개체 배열을 가져온 다음 forEach 메서드를 사용하여이 배열을 반복합니다.

이 루프에서는 먼저 input이라는 새 변수를 만들고 거기에 플레이어의 입력 데이터를 저장합니다. 그런 다음 왼쪽, 오른쪽 또는 위로 키를 눌렀는지 확인합니다.

왼쪽 또는 오른쪽 키를 누르면 setAngularVelocity ()를 호출하여 플레이어의 각 속도를 업데이트합니다. 각 속도는 선박이 좌우로 회전하도록합니다.

왼쪽 또는 오른쪽 키를 누르지 않으면 각 속도가 다시 0으로 재설정됩니다.

위로 키를 누르면 배의 속도가 업데이트되고 그렇지 않으면 0으로 설정됩니다.

마지막으로 우리는 플레이어 객체에 플레이어 게임 객체의 x, y 및 회전 속성을 저장합니다. 우리는 클라이언트 측에 다시 전달할 수 있도록 이러한 속성을 저장하고 있으며 해당 데이터를 사용하여 플레이어의 위치를 ​​업데이트합니다.

그런 다음 physics.world.wrap ()을 호출하고 플레이어 그룹과 오프셋 5를 전달합니다. 플레이어의 배가 화면에서 벗어나면 플레이어의 배가 다른쪽에 강제로 표시됩니다. 화면.

마지막으로 우리는 모든 플레이어에게 playerUpdates 메시지를 내고 플레이어에게이 메시지를 전달합니다.


이제 서버에서 플레이어의 입력을 처리하기 위한 코드를 만들었으므로 마지막으로 해야 할 일은 클라이언트 측을 업데이트하여 새 playerUpdates 메시지를 처리하는 것입니다. 클라이언트 쪽에서 이 메시지를 받으면 우리는 그 데이터를 사용하여 각 플레이어의 게임 개체의 위치와 회전을 업데이트합니다.


이렇게하려면 public / js / game.js를 열고 this.cursors = this.input.keyboard.createCursorKeys (); 위에 다음 코드를 추가하십시오.

this.socket.on('playerUpdates', function (players) {
Object.keys(players).forEach(function (id) {
self.players.getChildren().forEach(function (player) {
if (players[id].playerId === player.playerId) {
player.setRotation(players[id].rotation);
player.setPosition(players[id].x, players[id].y);
}
});
});
});

위의 코드에서 우리는 다음을 수행했습니다.


먼저 playerUpdates 메시지와 함께 전달 된 플레이어 객체를 반복 한 다음 플레이어 그룹에있는 모든 게임 객체를 반복합니다.

그런 다음 플레이어 게임 개체 인 playerId가 플레이어 개체의 playerId와 일치하는지 확인합니다.

playerId가 일치하면 setRotation 및 setPosition 메소드를 호출하여 해당 게임 객체의 회전 및 위치를 업데이트합니다.


저장하고 서버를 다시 시작한 다음 게임을 새로 고침하면 우주선을 화면에서 움직일 수있게되었습니다.


별 수집하기

현재 플레이어의 입력을 다루는 게임으로 플레이어에게 목표를 제공해야합니다. 이 튜토리얼에서는 플레이어가 수집 할 수 있도록 게임에 수집 할 수있는 별표를 추가하고 팀이 10 점을 얻게됩니다. 이렇게하려면 몇 가지 새로운 게임 개체와 몇 가지 새로운 Socket.IO 이벤트를 만들어야합니다. 첫째, 스타 게임 객체에 집중할 것입니다.


이 소장품의 자산은 여기에서 다운로드 할 수 있습니다. public / assets 및 authoritative_server / assets 폴더에 star_gold.png 복사본을 놓습니다.


이제 authoritative_server / js / game.js의 preload 함수에 다음 코드를 추가합니다.

this.load.image('star', 'assets/star_gold.png');


그런 다음 create 함수에 다음 코드를 추가하십시오.

this.scores = {
blue: 0,
red: 0
};

this.star = this.physics.add.image(randomPosition(700), randomPosition(500), 'star');
this.physics.add.collider(this.players);

this.physics.add.overlap(this.players, this.star, function (star, player) {
if (players[player.playerId].team === 'red') {
self.scores.red += 10;
} else {
self.scores.blue += 10;
}
self.star.setPosition(randomPosition(700), randomPosition(500));
io.emit('updateScore', self.scores);
io.emit('starLocation', { x: self.star.x, y: self.star.y });
});

위의 코드에서 우리는 다음을 수행했습니다.


프리로드 기능으로 새로운 스타 이미지에로드됩니다.

빨간색과 파란색 팀 모두 점수를 저장하는 데 사용할 객체 인 scores라는 새 변수를 만듭니다.

star collectible에 대한 새로운 게임 객체를 생성하고, randomPosition이라는 새 함수를 호출하여 x 및 y 위치에 대한 임의의 위치를 ​​만들었습니다.

플레이어 Phaser 그룹에 콜리더를 추가했습니다. Phaser 그룹을 physics.add.collider () 메소드에 전달하면 Phaser가 모든 하위 게임 객체 간의 충돌을 자동으로 확인합니다.

플레이어 Phaser 그룹과 별 게임 개체 사이에 중복을 추가했으며, 게임 개체 중 하나가 다른 개체와 겹칠 때 호출되는 콜백 함수를 제공했습니다. Phaser 그룹과 하나의 게임 개체를 전달하면 Phaser는 모든 자식 게임 개체와 단일 게임 개체 사이의 충돌을 자동으로 확인합니다.

콜백 함수에서 플레이어 게임 개체가 속한 팀을 확인하고 해당 팀의 점수를 업데이트했습니다. 그런 다음 새로운 임의의 위치를 ​​제공하여 스타 게임 개체의 위치를 ​​업데이트합니다.

마지막으로 updateScore와 starLocation이라는 두 개의 새로운 Socket.IO 메시지를 생성했습니다. updateScore 메시지를 내 보내면 점수 변수도 클라이언트 측에 보냅니다. starLocation 메시지를 내 보내면 별 게임 개체의 x 및 y 위치도 보냅니다.


다음으로, io.on ( 'connection') 콜백 함수에서 socket.broadcast.emit ( 'newPlayer', players [socket.id]) 아래에 다음 코드를 추가하십시오.

// send the star object to the new player
socket.emit('starLocation', { x: self.star.x, y: self.star.y });
// send the current scores
socket.emit('updateScore', self.scores);


마지막으로 update 함수 아래에 다음 코드를 추가합니다.

function randomPosition(max) {
return Math.floor(Math.random() * max) + 50;
}

위 코드에서 우리는 :


별 게임 개체의 위치와 현재 점수를 우리 게임에 참여하는 새로운 플레이어에게 보냅니다.

위의 코드에서 호출 된 randomPosition 함수가 추가되었습니다.


서버의 코드가 변경되면 클라이언트 측으로 전환합니다. 우리가 할 첫 번째 일은 스타 애셋을 클라이언트 측 코드에 로드하는 것입니다. public / js / game.js에서 preload 함수 맨 아래에 다음 행을 추가하십시오.

this.load.image('star', 'assets/star_gold.png');


다음으로, 현재 점수가 무엇인지 알리는 방법이 필요합니다. Phaser의 텍스트 게임 개체를 사용하여이를 수행 할 수 있습니다. create 함수에서 this.players = this.add.group (); 아래에 다음 코드를 추가하십시오.

this.blueScoreText = this.add.text(16, 16, '', { fontSize: '32px', fill: '#0000FF' });
this.redScoreText = this.add.text(584, 16, '', { fontSize: '32px', fill: '#FF0000' });

위의 코드에서 this.add.text ()를 호출하여 두 개의 새로운 텍스트 게임 객체를 만들었습니다. 이 두 객체를 만들 때 객체 배치 위치, 객체의 기본 텍스트, 텍스트 객체에 사용할 글꼴 크기 및 채우기를 전달했습니다.


마지막으로 우리가 만든 두 개의 새로운 Socket.IO 이벤트에 대한 논리를 추가하면됩니다. create 함수에서 this.cursors = this.input.keyboard.createCursorKeys (); 위에 다음 코드를 추가하십시오.

this.socket.on('updateScore', function (scores) {
self.blueScoreText.setText('Blue: ' + scores.blue);
self.redScoreText.setText('Red: ' + scores.red);
});

this.socket.on('starLocation', function (starLocation) {
if (!self.star) {
self.star = self.add.image(starLocation.x, starLocation.y, 'star');
} else {
self.star.setPosition(starLocation.x, starLocation.y);
}
});

방금 추가 한 코드를 살펴 보겠습니다.


updateScore 이벤트가 수신되면 setText () 메서드를 호출하여 게임 개체의 텍스트를 업데이트하고 팀의 점수를 각 개체에 전달합니다.

starLocation 이벤트가 수신되면 먼저 스타 게임 개체가 존재하지 않는지 확인하고 그렇지 않은 경우 제공된 위치에 스타 게임 개체를 만듭니다. 별 게임 개체가 존재하면 setPosition 메서드를 호출하여 별 게임 개체를 업데이트합니다.


코드 변경 사항을 저장하고 서버를 다시 시작하고 브라우저를 새로 고침하면 새로운 스타 수집품과 팀 점수를 확인해야합니다.

우주선을 스타 수집품으로 옮기면 스타가 새로운 위치로 이동해야하며 팀 점수 업데이트가 표시되어야합니다. 또한 브라우저에서 새 탭을 열면 우주선을 다른 플레이어의 우주선으로 옮기고 충돌을 볼 수 있어야합니다.


결론

스타 수집품을 게임에 추가하면이 가이드가 끝납니다. 요약하면 Phaser의 신뢰할 수있는 서버로 간단한 멀티 플레이어 게임을 만드는 방법을 보여주었습니다. 주로 Socket.IO와 Node.js를 사용했습니다.


이 튜토리얼을 모두 즐겁게 사용하여 도움이 되었기를 바랍니다. 궁금한 점이 있거나 다음에 다루어야 할 사항에 대한 제안이 있으면 아래 의견에 알려주십시오.

Posted by HammerOh
|

이 튜토리얼의 제 1 부에서는 Node.js 서버를 만들고 기본적인 Phaser 게임을 설정하고 헤드리스 모드로 Phaser를 실행하도록 서버를 설정합니다.

이 튜토리얼에서는 게임에 Socket.IO 라이브러리를 추가하고 게임에 플레이어를 추가 및 제거하는 서버 로직을 추가하며 플레이어를 게임에 추가하기위한 클라이언트 측 로직을 추가하는 데 집중할 것입니다.


Socket.IO 추가하기

Phaser가 이제 서버에서 실행되면서 이제 Socket.IO를 게임에 추가 할 것입니다.

Socket.IO는 웹 클라이언트와 서버 간의 실시간 양방향 통신을 가능하게하는 JavaScript 라이브러리입니다.

Socket.IO를 사용하려면 클라이언트와 서버 코드를 업데이트하여 둘 사이의 통신을 가능하게해야합니다.


터미널에서 다음 명령을 실행하십시오.

npm install --save socket.io

서버가 계속 실행중인 경우 새 터미널 창을 열고 프로젝트 폴더에서 코드를 실행하거나 서버를 중지 한 다음 (Ctrl + C) 명령을 실행할 수 있습니다. 이렇게하면 Socket.IO 노드 패키지가 설치되어 package.json 파일에 저장됩니다.


이제 index.js에 var server = require ( 'http').Server (app); 아래에 다음 코드를 추가합니다.

const io = require('socket.io').listen(server);

그런 다음 dom.window.gameLoaded 코드 아래에 다음 행을 추가하십시오.

dom.window.io = io;

그러면 jsdom에 socket.io 인스턴스가 삽입되어 서버에서 실행중인 Phaser 코드에서 이 인스턴스에 액세스 할 수 있습니다. 이제 authoritative_server / js / game.js에서 create 함수에 다음 코드를 추가합니다.

io.on('connection', function(socket) {

console.log('a user connected');

socket.on('disconnect', function() {

console.log('user disconnected');

});

});

위 코드에서 우리는 :

socket.io 모듈을 참조하고 서버 객체를 수신하게했습니다.

연결 및 연결 끊김을 청취하는 논리가 추가되었습니다.


다음으로 Socket.IO 라이브러리를 포함하도록 클라이언트 측 코드를 업데이트합니다. public / index.html을 열고 <body> 요소의 맨 위에 다음 줄을 추가하십시오.

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

그런 다음 public / js / game.js를 열고 create 함수에 다음 코드를 추가합니다.

this.socket = io();

이제 코드 변경 사항을 저장하고 서버를 다시 시작한 다음 브라우저에서 게임을 새로 고침하면 연결된 사용자에 대한 메시지가 표시됩니다. 브라우저에서 게임을 새로 고침하면 사용자 연결 해제에 대한 새 메시지와 사용자 연결에 대한 다른 메시지가 표시됩니다.

플레이어 추가 - 서버

소켓 연결 설정을 통해 플레이어를 게임에 추가 할 수 있습니다. 가장 먼저해야 할 일은 플레이어의 우주선에 사용될 자산을 적재하는 것입니다. 이 튜토리얼에서는 Kenny 's Space Shooter Redux 자산 팩의 일부 이미지를 사용합니다. 게임의 자산은 여기에서 다운로드 할 수 있습니다.


authoritative_server 폴더에서 assets이라는 새 폴더를 만들고 여기에 이미지를 저장합니다. 게임에서 이미지를로드하려면 authoritative_server / js / game.js의 사전로드 함수에 다음 행을 추가해야합니다.

this.load.image('ship', 'assets/spaceShips_001.png');


우주선 이미지가 로드되면 플레이어 추가를 위한 나머지 로직이 추가됩니다. 모든 플레이어의 게임을 동기화 상태로 유지하려면 사용자가 게임에 연결하거나 연결을 끊을 때 모든 플레이어에게 알릴 수있는 방법이 필요합니다. 또한 새 플레이어가 연결되면 새 플레이어가 게임의 다른 모든 플레이어를 알 수있는 방법이 필요합니다.


이렇게 하기 위해 소켓 연결을 사용하여 각 클라이언트에 메시지를 보낼 수 있습니다. 플레이어 데이터의 경우 연결하고 끊는 각 플레이어를 추적해야 합니다.


authoritative_server / js / game.js 파일의 맨 위에 다음 코드를 추가하십시오.

const players = {};


이 오브젝트를 사용하여 현재 게임중인 모든 플레이어를 추적합니다. 그런 다음 create 함수의 맨 위에 다음 코드를 추가합니다.

const self = this;

this.players = this.physics.add.group();


그런 다음 socket.io 연결 이벤트의 콜백 함수에서 console.log ( 'a user connected') 아래에 다음 코드를 추가합니다.

// create a new player and add it to our players object

players[socket.id] = {

rotation: 0,

x: Math.floor(Math.random() * 700) + 50,

y: Math.floor(Math.random() * 500) + 50,

playerId: socket.id,

team: (Math.floor(Math.random() * 2) == 0) ? 'red' : 'blue'

};

// add player to server

addPlayer(self, players[socket.id]);

// send the players object to the new player

socket.emit('currentPlayers', players);

// update all other players of the new player

socket.broadcast.emit('newPlayer', players[socket.id]);

방금 추가 한 코드를 살펴 보겠습니다.


- 우리는 self라고 불리는 새로운 변수를 만들었고이 변수를 사용하여 이 Phaser Scene에 대한 참조를 저장합니다.

- 우리는 우리 게임에서 모든 플레이어를 관리하는 데 사용될 새로운 Phaser 물리 그룹을 만들었습니다. Phaser의 그룹에 익숙하지 않은 경우, 유사한 게임 개체를 관리하고 하나의 단위로 제어 할 수있는 방법입니다. 한 가지 예는 각 게임 개체의 충돌을 개별적으로 확인하지 않고 그룹과 다른 게임 개체 간의 충돌을 검사 할 수 있다는 것입니다.

- 플레이어가 웹 소켓에 연결하면 플레이어에 대한 데이터로 플레이어 개체를 업데이트하고 이 데이터를 개체로 저장하고 소켓의 ID를 개체의 키로 사용합니다.

- 우리는 플레이어의 회전, x 및 y 위치를 저장하고 있으며 클라이언트 측에서 스프라이트를 작성하고 이 데이터를 사용하여 각 플레이어 게임을 업데이트하는 데 사용합니다.

- 우리는 또한 playerId를 저장하여 게임에서 참조 할 수 있으며 나중에 사용할 팀 속성을 추가했습니다.

- 우리는 socket.emit과 socket.broadcast.emit을 사용하여 클라이언트 측 소켓에 이벤트를 발생시켰다. socket.emit은 이 특정 소켓 (방금 연결 한 새 플레이어)으로 이벤트를 방출합니다. socket.broadcast.emit은 이벤트를 다른 모든 소켓 (기존 플레이어)에게 보냅니다.

- currentPlayers 이벤트에서 플레이어 개체를 새 플레이어로 전달합니다. 이 데이터는 새 플레이어의 게임에서 모든 플레이어 스프라이트를 채우는 데 사용됩니다.

- newPlayer 이벤트에서 우리는 새로운 플레이어의 데이터를 다른 모든 플레이어에게 전달하므로 새로운 스프라이트를 게임에 추가 할 수 있습니다.

- 마지막으로 addPlayer라는 새로운 함수를 호출했습니다.이 함수는 서버에서 플레이어를 만드는 데 사용됩니다.


이제 우리는 addPlayer 함수를 생성 할 것입니다. 이 함수는 새로운 플레이어 게임 개체를 만드는 데 사용되며 방금 만든 플레이어 그룹에 해당 게임 개체를 추가합니다. 업데이트 함수 아래에 다음 코드를 추가하십시오.

function addPlayer(self, playerInfo) {

const player = self.physics.add.image(playerInfo.x, playerInfo.y, 'ship').setOrigin(0.5, 0.5).setDisplaySize(53, 40);

player.setDrag(100);

player.setAngularDrag(100);

player.setMaxVelocity(200);

player.playerId = playerInfo.playerId;

self.players.add(player);

}

위 코드에서 우리는 :

- 이전에 생성 한 x와 y 좌표를 사용하여 새 플레이어의 배를 만들었습니다.

- 플레이어의 배를 만들기 위해 self.add.image를 사용하는 대신 self.physics.add.image를 사용하여 게임 객체가 아케이드 물리를 사용할 수있게했습니다.

- setOrigin ()을 사용하여 게임 객체의 원점을 왼쪽 상단 대신 객체의 중간에 설정했습니다. 우리가 게임 객체를 회전시킬 때 원점을 중심으로 회전하기 때문에 이 작업을 수행 한 이유입니다.

- setDisplaySize ()를 사용하여 게임 객체의 크기와 크기를 변경했습니다. 원래 우주선 이미지는 106 × 80 픽셀이었습니다. setDisplaySize ()를 호출 한 후 이미지가 이제 게임에서 53x40 픽셀입니다.

- 마지막으로 setDrag, setAngularDrag 및 setMaxVelocity를 사용하여 게임 객체가 아케이드 물리에 반응하는 방식을 수정했습니다. setDrag 및 setAngularDrag는 객체가 움직일 때 저항하는 양을 제어하는 ​​데 사용됩니다. setMaxVelocity는 게임 개체가 도달 할 수있는 최대 속도를 제어하는 ​​데 사용됩니다.


플레이어 제거 - 서버

서버에 플레이어를 추가하는 로직을 사용하여 서버에서 플레이어를 제거하는 로직을 추가합니다. 플레이어가 연결을 끊으면 플레이어 개체에서 해당 플레이어의 데이터를 제거해야하며,이 사용자에 대한 다른 모든 플레이어에게 메시지를 내 보내야합니다. 그러면 플레이어의 스프라이트가 클라이언트 게임에서 제거 될 수 있습니다.


socket.io 연결 해제 이벤트의 콜백 함수에서 console.log ( 'user disconnected') 아래에 다음 코드를 추가하십시오.

// remove player from server

removePlayer(self, socket.id);

// remove this player from our players object

delete players[socket.id];

// emit a message to all players to remove this player

io.emit('disconnect', socket.id);


그런 다음 addPlayer 함수 아래에 다음 코드를 추가합니다.

function removePlayer(self, playerId) {

self.players.getChildren().forEach((player) => {

if (playerId === player.playerId) {

player.destroy();

}

});

}

위 코드에서 우리는 :


- removePlayer라는 새 함수를 만들었습니다. 이 함수는 연결이 끊어진 플레이어의 socket.id를 가져오고 Phaser 그룹에서 플레이어의 게임 개체를 찾아 파괴합니다.

- 우리는 플레이어 그룹에서 getChildren () 메서드를 호출하여이를 수행합니다. getChildren () 메서드는 해당 그룹에있는 모든 게임 객체의 배열을 반환합니다. 일치하는 ID를 가진 게임 객체를 찾을 때까지 forEach () 메서드를 사용하여 배열을 반복합니다.

- 서버에서 게임 개체가 파괴되면 delete 개체를 사용하여 해당 개체를 제거하여 플레이어 개체에서 해당 개체를 삭제합니다.

- 마지막으로 io.emit을 사용하여 모든 소켓에 메시지를 보냈습니다. 이 경우 연결을 끊은 사용자의 socket.id를 전달하여 클라이언트 측 코드에서 해당 플레이어의 스프라이트를 제거 할 수 있습니다.


authoritative_server / js / game.js 파일은 다음과 같아야합니다.

const players = {};


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

},

autoFocus: false

};


function preload() {

this.load.image('ship', 'assets/spaceShips_001.png');

}


function create() {

const self = this;

this.players = this.physics.add.group();


io.on('connection', function (socket) {

console.log('a user connected');

// create a new player and add it to our players object

players[socket.id] = {

rotation: 0,

x: Math.floor(Math.random() * 700) + 50,

y: Math.floor(Math.random() * 500) + 50,

playerId: socket.id,

team: (Math.floor(Math.random() * 2) == 0) ? 'red' : 'blue'

};

// add player to server

addPlayer(self, players[socket.id]);

// send the players object to the new player

socket.emit('currentPlayers', players);

// update all other players of the new player

socket.broadcast.emit('newPlayer', players[socket.id]);


socket.on('disconnect', function () {

console.log('user disconnected');

// remove player from server

removePlayer(self, socket.id);

// remove this player from our players object

delete players[socket.id];

// emit a message to all players to remove this player

io.emit('disconnect', socket.id);

});

});

}


function update() { }


function addPlayer(self, playerInfo) {

const player = self.physics.add.image(playerInfo.x, playerInfo.y, 'ship').setOrigin(0.5, 0.5).setDisplaySize(53, 40);

player.setDrag(100);

player.setAngularDrag(100);

player.setMaxVelocity(200);

player.playerId = playerInfo.playerId;

self.players.add(player);

}


function removePlayer(self, playerId) {

self.players.getChildren().forEach((player) => {

if (playerId === player.playerId) {

player.destroy();

}

});

}


const game = new Phaser.Game(config);

window.gameLoaded();


이제 코드 변경 사항을 저장하고 서버를 다시 시작한 다음 브라우저에서 게임을 새로 고침하면 콘솔에 오류 메시지가 표시됩니다.


오류 메시지의 모양에서 jsdom은 URL.createObjectURL 메소드를 지원하지 않는 것 같습니다. 이 정적 메서드는 지정된 소스 객체의 내용을 참조하는 데 사용할 수있는 객체 URL이 포함 된 DOMString을 만드는 데 사용됩니다. 이 오류를 해결하려면 비슷한 값을 반환하는 메서드를 구현해야합니다.


이를 위해 datauri 패키지를 사용하여 데이터 URI를 반환합니다. 이 패키지를 사용하려면 프로젝트에 추가해야합니다. 터미널에서 서버를 중지하고 다음 명령을 실행하십시오.

npm install -save datauri


그런 다음 서버 코드에 라이브러리를 포함시켜야합니다. server / index.js를 열고 const {JSDOM} = jsdom;

const Datauri = require('datauri');

const datauri = new Datauri()


setupAuthoritativePhaser 함수에서 다음 코드를 dom.window.gameLoaded = () => {line :

dom.window.URL.createObjectURL = (blob) => {

if (blob) {

return datauri.format(blob.type, blob[Object.getOwnPropertySymbols(blob)[0]]._buffer).content;

}

};

dom.window.URL.revokeObjectURL = (objectURL) => { };

방금 추가 한 코드를 살펴 보겠습니다.


- 첫째, 우리는 datauri 패키지를 포함 시켰고 새로운 인스턴스를 만들었습니다.

그런 다음 jsdom에 구현되어 있지 않은 createObjectURL 및 revokeObjectURL 함수를 만들었습니다.

- revokeObjecURL 함수의 경우 함수에 아무 것도하지 않습니다.

- createObjectURL 함수의 경우 datauri.format 메서드를 사용하여 blob을 필요한 형식으로 포맷합니다.

이제 코드 변경 사항을 저장하고 서버를 시작하면 모든 것이 잘 시작됩니다.


플레이어 추가 - 클라이언트

플레이어를 추가하는 서버 코드를 사용하여 클라이언트 측 코드를 작성합니다. 가장 먼저해야 할 일은 플레이어에게 사용될 자산을 로드하는 것입니다. 공용 폴더에서 assets이라는 새 폴더를 만들고 이 폴더에서 다른 assets 폴더의 spaceShips_001.png 이미지를 복사합니다.


게임에서 이미지를 로드하려면 public / js / game.js의 preload 함수에 다음 줄을 추가해야합니다.

this.load.image('ship', 'assets/spaceShips_001.png');

우주선 이미지가 로드되면 이제 게임에서 플레이어를 만들 수 있습니다. 이전에 새 플레이어가 게임에 연결할 때마다 currentPlayers 이벤트를 발생하도록 Socket.IO를 설정했으며 이 이벤트가 발생하면 현재 플레이어의 데이터가 포함 된 플레이어 개체도 전달했습니다.


public / js / game.js의 create 함수를 다음과 일치하도록 업데이트하십시오.

function create() {
var self = this;
this.socket = io();
this.players = this.add.group();

this.socket.on('currentPlayers', function (players) {
Object.keys(players).forEach(function (id) {
if (players[id].playerId === self.socket.id) {
displayPlayers(self, players[id], 'ship');
}
});
});
}

방금 추가 한 코드를 살펴 보겠습니다.


먼저 클라이언트 측의 모든 게임 개체를 관리하는 데 사용되는 새로운 Phaser 그룹을 만들었습니다.

우리는 currentPlayers 이벤트를 수신하기 위해 socket.on을 사용했으며, 이 이벤트가 트리거되면 우리가 제공 한 함수가 서버에서 전달한 players 객체로 호출됩니다.

이 함수가 호출되면 각 플레이어를 반복하고 해당 플레이어의 ID가 현재 플레이어의 소켓 ID와 일치하는지 확인합니다.

플레이어를 통해 반복하기 위해 우리는 Object.keys ()를 사용하여 전달 된 Object의 모든 키 배열을 만듭니다. 반환되는 배열의 경우 forEach () 메서드를 사용하여 배열의 각 항목을 반복합니다 .

마지막으로 displayPlayers () 함수를 호출하여 현재 플레이어의 정보와 현재 장면에 대한 참조를 전달했습니다.


이제 public / js / game.js에 displayPlayer 함수를 추가해 보겠습니다. 파일의 맨 아래에 다음 코드를 추가하십시오.

function displayPlayers(self, playerInfo, sprite) {
const player = self.add.sprite(playerInfo.x, playerInfo.y, sprite).setOrigin(0.5, 0.5).setDisplaySize(53, 40);
if (playerInfo.team === 'blue') player.setTint(0x0000ff);
else player.setTint(0xff0000);
player.playerId = playerInfo.playerId;
self.players.add(player);
}

위 코드에서 우리는 :


우리 서버 코드에서 생성 한 x와 y 좌표를 사용하여 플레이어의 배를 만들었습니다.

setOrigin ()을 사용하여 게임 객체의 원점을 왼쪽 상단 대신 객체의 중간에 설정했습니다.

setDisplaySize ()를 사용하여 게임 객체의 크기와 크기를 변경했습니다.

우리는 setTint ()를 사용하여 배 게임 객체의 색상을 변경했으며 서버에 플레이어 정보를 생성 할 때 생성 된 팀에 따라 색상을 선택합니다.

나중에 id로 게임 객체를 찾을 수 있도록 playerId를 저장했습니다.

마지막으로 플레이어의 게임 개체를 우리가 만든 Phaser 그룹에 추가했습니다.


브라우저를 새로 고침하면 플레이어의 배가 화면에 표시됩니다.


또한 게임을 새로 고침하면 우주선이 다른 위치에 나타나고 우주선이 빨간색이나 파란색으로 무작위로 표시되어야 합니다.


결론

플레이어를 표시하기위한 클라이언트 측 코드를 사용하면이 자습서 시리즈의 제 2 편이 끝납니다. 3 부에서는 멀티 플레이어 게임을 계속 진행합니다.


다른 플레이어를 게임에 추가하기위한 클라이언트 측 로직 추가.

플레이어 입력에 대한 논리 추가.

수집품에 대한 논리 추가.

나는 당신이 우리 두 번째 할부를 즐겁게하고 그것이 도움이되기를 바랐다. 우리가 다음에 다루어야 할 것에 대해 질문이나 제안이 있으면, 아래의 의견에 저희에게 알려주십시오.

Posted by HammerOh
|

이 멀티 파트 튜토리얼에서는 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 라이브러리 추가하기.

게임에 플레이어를 추가하기위한 서버 로직 추가.

게임에서 플레이어를 제거하기위한 서버 로직 추가.

게임에 플레이어를 추가하기위한 클라이언트 측 로직 추가.


이 튜토리얼 시리즈의 시작을 즐겁게하고 도움이되기를 바랍니다. 

우리가 다음에 다루어야 할 것에 관한 질문이나 제안이 있으면, 아래의 의견에 우리에게 알려주십시오.

Posted by HammerOh
|

저는 종종 프로젝트 중 그룹으로 생성된 객체를 드래그할 필요가 있다는 문제에 직면했습니다.

지난 며칠간 프로젝트로 인해 이것은 나를 괴롭혔습니다.

나는 현재 그리드에 엄지 손톱을 많이 표시해야하는 앱을 만들고 있습니다.

그리드는 수직으로 스크롤해야하며 축소판을 클릭해야합니다.


이제 Phaser의 그룹에서 드래그를 구현하려고 시도해 본 적이 있다면 쉬운 일이 아닌지 알 수 있습니다.

Phaser의 창시자 인 Richard Davey는 html5gamedevs 포럼에서이 게시물의 그룹을 끌 수있는 기본 방법이없는 이유를 설명합니다.


"그것은 실제로 생각보다 조금 더 복잡합니다. 그룹에는 모든 영역이 없으며 모든 방향에서 무한합니다. 따라서 클릭 한 경우 감지 할 수 없습니다. 그러나 드래그하여 다른 모든 자식, 그 자식 또는 그룹 x / y 배치 자체를 업데이트해야한다면 쉽게 자식을 클릭 할 수 있습니까? (차례 차례로 다른 아이들을, 당신이 예기 할 방법에서 어쩌면 단지) 새롭게 할 것입니다. 그리고 중첩 된 그룹은 어떻습니까?"


필자는이 기능이 마음에 든다. 표면에 나타나는 것처럼 구현하기가 쉽지 않다.


Brainstorming the solution

그래서 내가 뭘해야하니? 내가 생각해 낸 첫 번째 해결책은 그룹의 높이와 너비가 같고 드래그 할 수 있도록 스프라이트를 만드는 것입니다. 작동하지만 새로운 자체 문제는 스프라이트를 클릭하여 개별 축소판에 도달 할 수 없다는 것입니다. 이것은 프로젝트의 핵심 부분입니다. 이제는 더 나은 솔루션이 필요하다는 것을 알게되었습니다. 이것은 내가 지금까지 알고있는 것이다 :


내 요구 사항 :

- 그룹 드래그

- 자녀를 클릭 할 수있는 상태로두기


내가 지금까지 알고있는 것 :

- 클릭 할 수있는 스프라이트는 마우스 이벤트를 다른 스프라이트로 차단합니다.

- 그룹이 마우스 이벤트를 감지 할 수 없습니다.

- Phaser의 드래그를 사용하여 그룹을 끌 수 없습니다.

- game.input은 아무것도 차단되지 않습니다.


그 마지막 요점은 내가 끌기가 무엇인지 생각하고있다 :

- 마우스 다운 이벤트

- 마우스가 눈금의 범위 내에 있는지 확인하기

- 마우스의 움직임을 확인하고 필요에 따라 눈금을 업데이트하십시오.


여기서 마우스라는 용어를 사용하고 있지만 터치 이벤트 일 수도 있습니다.


여기에 내가 지금 애플 리케이션에서 사용하고있는 해결책이있다. 이 예제에서는 Javascript 클래스를 사용합니다.


드래그를 위해 DragBox라는 클래스를 사용하고 있으며이 클래스도 그룹을 확장합니다. 나는 아이들을 여기에 추가하고 있지 않지만 내장 된 업데이트 기능을 사용할 수 있도록 그룹을 확장 중입니다. 드래그 해야하는 객체는 DragBox의 인스턴스로 유일한 매개 변수로 전달됩니다.

class DragBox extends Phaser.Group {

    constructor(dragObj) {

        super(game);

        this.dragObj = dragObj;

        game.input.onDown.add(this.onDown, this);

    }

    onDown() {

        //set canDrag to false

        this.canDrag = false;

        //check if the mouse is in bounds

        //since my dragObject is the full width of the game

        //I only need to check the y position

        //The top of the drag object is the y position

        //and the bottom is the top plus the height

        //

        if (game.input.y &gt; this.dragObj.y &amp;&amp; game.input.y &lt; (this.dragObj.y + this.dragObj.height)) {

            //set the canDrag to true;

            this.canDrag = true;

            //get the start position of the dragObject

            //so we may compare it to the current position

            //when dragging

            this.startY = this.dragObj.y;

            //the offset is how far down on the grid the

            //mouse is when the user started dragging

            //without this line the grid will jump when

            //the drag starts

            this.offSet = this.dragObj.y - game.input.y;

        }

    }

    update() {

        if (game.input.mousePointer.isDown) {

            if (this.canDrag == true) {

                //calculate the difference between the startY

                //and the current mouse y position

                //and add in the offSet

                var diff = game.input.y - this.startY + this.offSet;

                //update the start position

                //by adding the difference to the start position

                this.dragObj.y = this.startY + diff;

            }

        }

    }

}

대부분의 코드는 주석입니다. 노트가 없는 코드는 약 23 행뿐입니다.

class DragBox extends Phaser.Group {

    constructor(dragObj) {

        super(game);

        this.dragObj = dragObj;

        game.input.onDown.add(this.onDown, this);

    }

    onDown() {

        this.canDrag = false;

        if (game.input.y &gt; this.dragObj.y &amp;&amp; game.input.y &lt; (this.dragObj.y + this.dragObj.height)) {

            this.canDrag = true;

            this.startY = this.dragObj.y;

            this.offSet = this.dragObj.y - game.input.y;

        }

    }

    update() {

        if (game.input.mousePointer.isDown) {

            if (this.canDrag == true) {

                var diff = game.input.y - this.startY + this.offSet;

                this.dragObj.y = this.startY + diff;

            }

        }

    }

}


그룹을 직접 드래그하려면 코드 클래스를 직접 복사하여 프로젝트에 포함해야합니다.


그런 다음, 이 코드를 사용하여 개체를 만든 직후에 구현합니다.

var dragBox = new DragBox(objectYouWantToDrag);


이렇게하면 객체를 세로로 드래그 할 수 있지만 코드는 수평이 좋도록 조정할 수 있습니다.

다음은 내가 하는 일의 예입니다.

먼저 Phaser 그룹을 확장하는 그리드 클래스를 만들었습니다.

이 그리드 클래스는 같은 크기의 자식 요소 용입니다.

열 수에 'cols' 매개 변수가 필요합니다.

class Grid extends Phaser.Group {

    constructor(cols) {

        super(game);

        this.cols = cols;

    }

    arrange() {

        var xx = 0;

        var yy = 0;

        this.children.forEach(function(item) {

            //place the item on a column with a 10 percent buffer

            item.x = item.width * xx * 1.1;

            //place the item on a row with a 10 percent buffer

            item.y = item.height * yy * 1.1;

            xx++;

            if (xx ==this.cols) {

                xx = 0;

                yy++;

            }

        }.bind(this));

    }

    center() {

        this.x = game.width / 2-this.width/2;

        this.y = game.height / 2-this.height/2;

    }

}


미리보기 이미지의 경우 Box라는 클래스를 사용하고 있습니다. 이것은 단순히 마우스 리스너가 연결된 이미지가 포함 된 그룹을 확장하는 클래스입니다.

class Box extends Phaser.Group

{

constructor()

{

super(game);

var thumb=this.create(0,0,"box");

thumb.anchor.set(0.5,0.5);

thumb.inputEnabled=true;

thumb.events.onInputDown.add(this.clicked);

}

clicked()

{

console.log("click");

}

}


그리고 이건 내 stateMain.js 코드입니다.

var StateMain = {

    preload: function() {

        game.load.image("box", "images/box.png");

    },

    create: function() {

        //make a grid

        //

        this.grid = new Grid(5);

        //make 30 boxes and add to the grid

        //

        for (var i = 0; i &lt; 30; i++) {

            var box = new Box();

            this.grid.add(box);

        }

        //arrange the child objects into a grid

        //

        this.grid.arrange();

        //center on stage

        //

        this.grid.center();

        //make a dragBox and pass the grid to it

        //

        var dragBox = new DragBox(this.grid);

    }

}

그리고 드래그 그룹 코드가 실제로 작동합니다. 개발자 콘솔을 열면 사각형이 여전히 클릭 가능한지 확인할 수 있습니다. 드래그 중에 실수로 사각형이 클릭되지 않도록하려면 마우스를 아래로 내리고 마우스를 위로 올리는 시간을 확인하는 함수를 구현할 것입니다. 그것은 빠른 다음 그렇지 않으면 클릭이 될 것입니다, 나는 사용자가 드래그하고 있다고 가정합니다.




Posted by HammerOh
|

Phaser Audio Delay

PHASER.JS 2018. 10. 12. 09:01

이것은 나에게 여러 번 일어났습니다. 다시 Phaser 오디오 딜레이에 직면 해 있습니다! 나는 준비가되어있다. 예술 자산이 들어가고 점수 판이 작동하며 내일 게임을 시작해야합니다! 빨리 배경 음악을 넣고 반복하십시오. 게임은 시작되지만 음악은 어디에 있습니까 ???


3 초 기다려 ...


거기는! 그것은 성가신 지연이지만 우리는 그것을 무시하기 위해 시작해야합니다. 그 밖의 무엇을 할 수 있습니까?


이제 마감 기한을 넘기지 않고 다시 물러나서 무슨 일이 일어나는지 살펴 보겠습니다. 나는 왜 음악을 미리 불러 들여서 지연시킬까요?


나는 당신에게 문제를 보여주기 위해 표본을 모았다. 다음은 일반적으로 음악을로드하는 코드입니다. 이미지가 정상 속도로로드되는 것을 볼 수 있도록 이미지를 배치합니다. 또한 타이머가 포함되어 있으므로 지연되기 전에 몇 초가 지나야하는지 확인할 수 있습니다.

sdsd

var StateMain = {

    preload: function() {

        game.load.audio("music", "audio/music.mp3");

        game.load.image("title", "images/Cool-Game-Title.png");

    },

    create: function() {

        this.secs = 0;

        //create the music

        var music = game.add.audio("music");

        //play the music

        music.play();

        //

        //

        //

        //put the title on screen

        var title = game.add.image(game.width / 2, game.height / 2, "title");

        title.anchor.set(0.5, 0.5);

        //make the timer text

        this.timeText = game.add.text(game.width / 2, 100, "0",{fill:'#ffffff'});

        this.timeText.anchor.set(0.5, 0.5);

        //start counting seconds

        game.time.events.loop(Phaser.Timer.SECOND, this.tick, this);

    },

    tick: function() {

     this.secs++;

        this.timeText.text = this.secs;

    },

    update: function() {}

}

그럼 여기서 뭐하는거야? 어쨌든이 Phaser 오디오 지연의 원인은 무엇입니까? 미리로드 된 경우에도 재생하는 데 몇 초가 걸리는 이유는 무엇입니까? 음, 나는이 게시물에서 오디오가 디코딩되어야 할뿐만 아니라로드 될 필요가 있음을 지적하는 몇 가지 해답을 발견했습니다. 브라우저가 재생되기를 기다리는 동안 브라우저가 수행하는 작업입니다.


Phaser는 음악 파일이 디코딩되었는지 여부를 감지 할 수 있습니다.

game.cache.isSoundDecoded('music');


이 함수는 진실 또는 거짓을 돌려 줄 것입니다. 따라서 우리가 사용할 수있는 솔루션은 stateLoad라는 별도의 상태에서 모든 것을 로드하는 것입니다.

사전로드가 완료되면 업데이트 기능을 사용하여 음악이 디코딩되었는지 확인합니다.

그렇다면 상태를 stateMain으로 전환합니다. 사용자가 게임을 시작한 후보다 로딩 화면에서 기다리는 것이 게임 업계에서 잘 받아 들여지고 있습니다.

일반적으로 로딩 화면에는로드 바 또는 일부 메시지가 포함되지만 기술적 인 예에서는 충분합니다.


var StateLoad = {

        preload: function() {

            game.load.audio("music", "audio/music.mp3");

            game.load.image("title", "images/Cool-Game-Title.png");

        },

        create: function() {

         //only fires after preload is done

            var statText = game.add.text(game.width / 2, 100, "Decoding....", {

                fill: '#ffffff'

            });

            statText.anchor.set(.5, .5);

        },

        update: function() {

         //check to see if the audio is decoded

            if (game.cache.isSoundDecoded('music')) {

                    game.state.start("StateMain");

                }

            }

        }

var StateMain = {

    preload: function() {

       //moved loading here to stateLoad

    },

    create: function() {

        this.secs = 0;

        //create the music

        var music = game.add.audio("music");

        //play the music

        music.play();

        //

        //

        //

        //put the title on screen

        var title = game.add.image(game.width / 2, game.height / 2, "title");

        title.anchor.set(0.5, 0.5);

        //make the timer text

        this.timeText = game.add.text(game.width / 2, 100, "0",{fill:'#ffffff'});

        this.timeText.anchor.set(0.5, 0.5);

        //start counting seconds

        game.time.events.loop(Phaser.Timer.SECOND, this.tick, this);

    },

    tick: function() {

     this.secs++;

        this.timeText.text = this.secs;

    },

    update: function() {}

}


결과는 다를 수 있지만 내 로컬 호스트에서 음악은 두 번째 테스트에서는 0으로, 첫 번째 테스트에서는 약 3에서 재생됩니다.


Posted by HammerOh
|

대부분 우리가 Phaser에서 게임을 만들때 우리는 스프라이트, 텍스트 또는 버튼 같은 간단한 객체를 사용하고 있습니다. Phaser에 글쓰기를 정말 좋아하지만 플래시 게임을 만들 때 사용하지 않을 때가 있습니다. 수업 내에서 다양한 요소를 만들 수 있습니다. Phaser로는 똑같은 일을 할 수는 없지만 복잡한 대상을 만드는 함수를 만드는 것이 가능합니다. 복잡한 객체는 단순히 자식 요소가 포함 된 그룹을 설명하는 데 사용하는 구문입니다. 이런 식으로, 나는 기본적으로 내가했던 것과 똑같은 결과를 얻을 수있었습니다.


이 예제에서는 버튼 객체를 만드는 함수를 작성했습니다. 이 경우 Phaser 프레임 워크에 내장 된 버튼이 아니라 텍스트 필드와 스프라이트가 포함 된 그룹입니다. 이것은 필요한 버튼이 무엇인지 모르는 상황에서 유용하기 때문에 한 줄의 코드로 새로운 버튼을 제작 할수 있습니다.


나는 최근에 한 게임에서 우주선 내부의 글자와 다른 게임에서의 거품으로 된 글자로 알파벳을 배우는 아이들을 위해 쓰고있는 몇 가지 게임에 대해이 기술을 사용했습니다. 나는 단순히 makeBubble 또는 makeShip 함수를 작성하고 필요한 모든 것을 만들기 위해 알파벳을 반복했습니다.


이 기술을 사용하려면 4 가지 작업을 수행해야합니다.

1. 스타일 (텍스트, 색상, 크기, 프레임)에 대한 매개 변수가있는 함수 만들기

2. 그 스타일 선택을 반영하는 자식 요소 만들기 (스프라이트, 텍스트 필드)

3. 그룹을 만들고 그 안에 요소들을 넣으십시오.

4. 그 그룹을 객체로 반환한다.


makeButton 함수로이 작업을 수행하고 create 함수에 버튼을 만들었습니다.





var StateMain = {

    preload: function () {

     game.load.spritesheet("colors","images/colors.png",150,50);

    },

    create: function () {      

       var btnYes=this.makeButton("YES",1);

       btnYes.y=game.height*.25;

       btnYes.x=game.world.centerX;

       var btnNo=this.makeButton("NO",0);

       btnNo.y=game.height*.75;

       btnNo.x=game.world.centerX;

       this.statusText=game.add.text(game.world.centerX,game.world.centerY,"");

       this.statusText.fill="#ffffff";

       this.statusText.anchor.set(0.5,0.5);      

    },

    makeButton:function(text,color)

    {

     //create the back for the button

     var back=game.add.image(0,0,"colors");

     back.frame=color;

     //create the label for the button

     //and set the text to the text parameter passed down

     var label=game.add.text(0,0,text);

     back.anchor.set(0.5,0.5);

     label.anchor.set(0.5,0.5); 

     //create the group

     var buttonGroup=game.add.group(); 

     //add the sprite and the label to the group

     buttonGroup.add(back);

     buttonGroup.add(label); 

     //groups can not take input so we need to add the

     //listener for the click

     back.inputEnabled=true;

     back.events.onInputDown.add(this.buttonClicked,this);

     //return the group as the button

     return buttonGroup;

    },

    buttonClicked:function(target)

    {

     //since the target is the sprite

     //we get the parent of the target

     //

     var group=target.parent;

     //the label is the second child we added to the

     //group so we can find it at index 1

     //the back sprite is found at index 0

     var label=group.getChildAt(1); 

     this.statusText.text=label.text; 

    },

    update: function () {

    }

}


Posted by HammerOh
|

모바일의 부상으로, 나는 더 자주 객체의 크기를 조정해야한다는 것을 알게되었습니다. 이것은 화면 크기의 차이를 보완하기위한 것입니다. 높이나 너비와 같은 속성 하나를 변경하는 것은 쉽지만 이미지 비율이 비례해야하는 것이 더 좋으므로 다음과 같은 공식이 필요합니다.

new_width = old_width*(new_height/old_height);


가로 세로 비율 유지하기

Phaser에서 걱정할 필요가 없습니다.스프라이트의 높이나 너비를 변경하면 스케일 객체 속성이 업데이트됩니다. 예를 들어 스프라이트의 너비를 변경하면 scale.x 속성이 변경됩니다.


너비를 변경하면 scale.x를 scale.y로 복사합니다.

mySprite.scale.y=mySprite.scale.x;


높이를 변경하면 반대로 하면됩니다.

mySprite.scale.x=mySprite.scale.y;



실제 샘플 코드 입니다.

var StateMain = {

 

    preload: function () {

     game.load.image("doughnut","images/doughnut.png");

    },

 

    create: function () {

        

     this.makeDoughnuts();

     game.input.onDown.add(this.makeDoughnuts, this);

    },

    makeDoughnuts:function()

    {

     for (var i = 0; i &lt; 5; i++) {

     var doughnut=game.add.sprite(game.world.randomX,game.world.randomY,"doughnut");

 

     doughnut.width=game.rnd.integerInRange(50, 150);

     //when we change the width, we automatically change the scale.x

     //setting the scale.y to scale.x will make the

     //object proportional

     doughnut.scale.y=doughnut.scale.x;

     }

    },

    update: function () {

 

    }

 

}


'PHASER.JS' 카테고리의 다른 글

Phaser Audio Delay  (0) 2018.10.12
Complex Objects – Phaser  (0) 2018.10.12
Phaser Js 코드 템플레이트 (Text)  (0) 2018.10.12
Phaser Js 코드 템플레이트 (Button)  (0) 2018.10.12
Phaser Js 코드 템플레이트 (Physics)  (0) 2018.10.11
Posted by HammerOh
|

Add Text

설명 : 스테이지에 텍스트 입력란 추가

var myText=game.add.text(x,y,text);


Center text

설명 : x 앵커를 너비의 50 %로 설정하여 텍스트 위치를 가운데로 맞춤

myText.anchor.x = Math.round(myText.width * 0.5) / myText.width;


Text font

설명: 텍스트의 폰트명 설정

myText.font="font_name";


Set text color

설명 : 텍스트 필드 색상을 설정합니다.

myText.fill="#textColor";


Font size

설명 : 텍스트 필드의 글꼴 크기를 설정합니다.

myText.fontSize=64;


Fancy Fonts

설명 : 텍스트 추가 기능의 네 번째 매개 변수를 사용하여 고급 글꼴 속성을 설정합니다.

this.titleText=game.add.text(x,y,text,{ font: "size fontName", fill: "color", stroke: "color", strokeThickness: number, align:string });

Posted by HammerOh
|

Add a button

섫명:

game.add.button(x,y,imageKey,clickFunction,this,over_frame,normal_frame,down_frame)



Sprite click

설명:

this.char1.events.onInputUp.add(this.clickHandler,scope);



Enable a sprite for input

설명 : 스프라이트에서 클릭 이벤트를 사용할 수 있으려면 먼저 입력에 사용하도록 설정해야합니다.

this.spriteName.inputEnabled=true;



Canvas click

설명 : 전체 게임에 리스너 추가

game.input.onUp.add(functionName, this);


Posted by HammerOh
|

Start the physics engine

설명 : Arcade Physics 엔진을 시작합니다.

game.physics.startSystem(Phaser.Physics.ARCADE);



Enable an object for physics

설명 : Phaser에게 선택된 객체에 물리엔진을 사용하도록 알려줍니다.

game.physics.enable(sprite, Phaser.Physics.ARCADE);



Set velocity

설명 : 객체의 속도를 설정합니다.

this.char.body.velocity.setTo(200,200);



Set bounce

설명 : 객체가 충돌 할 때 바운스를 설정합니다. 1은 100 % 바운스입니다. .5는 50 %

this.body.bounce.set(1,1);



Set Global Gravity

설명 : 모든 객체의 기본 중력을 설정합니다.

game.physics.arcade.gravity.y = 100;



Set object gravity

설명 : 개별 스프라이트의 중력을 설정합니다.

this.char.body.gravity.y = 50;



Set group physics

설명 : 그룹에 물리엔진을 설정합니다.

myGroup.enableBody = true;

myGroup.physicsBodyType = Phaser.Physics.ARCADE;





Posted by HammerOh
|