HTML5GAME :: 'ethereum' 태그의 글 목록

달력

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

이 프로젝트의 첫 번째 단계는 서버입니다. 아주 간단한 노드 환경을 설정하고 planck-js, socket.io 및 web3을 설치했습니다.


첫 번째 단계는 Imports 를 초기화 하는 것입니다.





var pl = require('planck-js'); var Vec2 = pl.Vec2
var server = require('http').createServer();
var io = require('socket.io')(server);

var Web3 = require('web3');

step1.js hosted with ❤ by GitHub

이것은 우리에게 중요한 플랙 변수 (우리의 물리 엔진), 우리의 서버, websocket.io(socket.io) 및 Web3(Ethereum)에 대한 액세스를 제공합니다.


이제 우리는 물리 엔진을 설정하고 Web3을 초기화하고 클라이언트를 추적 할 수있는 변수를 만들어야합니다.



// Initialize Web3 var web3 = new Web3(new Web3.providers.HttpProvider('https://ropsten.infura.io/'));
// The time step for the game loop and physics
var FIXED_TIME_STEP = 1/20
// Create a physics world, where bodies and constraints live
var world = new pl.World({
gravity : Vec2(0, 10)
});
// Create an infinite ground plane body
var ground = world.createBody();
ground.createFixture(pl.Edge(Vec2(0, 400), Vec2(500, 400)));
// Default stats for players
var DEFAULT_STATS = {
maxVel: 20
}
// Object to hold client information
var clients = {}

step2.js hosted with ❤ by GitHub


먼저 Ropsten testnet을 사용하여 Web3을 초기화합니다. 이것으로 실제로 Ethereum을 쓰지 않고 테스트 할 수 있습니다.


그런 다음 서버에 고정 된 시간 단계를 설정하고 물리 엔진을 초기화합니다. 


중력은 10으로 설정되지만 Planck의 기본값은 -9입니다. 우리는 Phaser와 함께 훌륭하게 연주하려면 긍정적 이어야 합니다.


우리는 클라이언트 정보를 보유 할 수있는 객체를 생성합니다.. 


이것은 연결 ID (socket.io에 의해 우리에게 주어진)를 Key로, 클라이언트 객체를 Value 로 사용하는 Map으로 작동합니다. 


따라서 특정 클라이언트와 상호 작용하는 것이 훨씬 쉬워집니다.


이제 게임에서 몇몇 플레이어를 얻고 Web3를 설정하십시오!


// Listen for connections io.on('connection', function(client){
// Let us know someone connected
console.log("Client connected!")
// When a player sends the join message
client.on('join', function(data) {
// TODO 1: Do something about a player joining
})
// TODO 2: Listen for more packets
});

part3.js hosted with ❤ by GitHub


누군가가 우리 서버에 연결할 때 io.on ( 'connection')이 호출됩니다. 


일단 접속 이벤트가 발생하면 접속된 클라이언트와 관련된 특정 패킷에 대해 호출하는 함수를 설정할 수 있습니다. 


이 중 첫 번째 메시지는 Join 메시지입니다.


플레이어가 조인 할 때 클라이언트 객체에 정보를 추가하기만 하면됩니다. 


이제 플레이어가 단순히 연결될 때, 이 모든 작업을 수행 할 수 있지만 기다려야 할 것이 있습니다. 


특히 우리는 접속된 클라이언트가 유효한 이더리움 (ethereum) 계정을 갖고 있는지 확인하고, 


실제로 계정 정보를 보내어 게임에 참여하도록 해야 합니다.




클라이언트가 Join 메시지를 보낼 때


나머지는 TODO 1이 있는 곳으로 갑니다.


먼저, 플레이어의 상태 및 물리 엔진을 설정할 수 있습니다.


// Set the player's stats client.stats = DEFAULT_STATS
// Setup client body
client.body = world.createBody({fixedRotation: true}).setDynamic();
client.body.createFixture(pl.Box(1, 1), {friction: 2});
client.body.setPosition(Vec2(50, 50));
client.body.setMassData({
mass : 2,
center : Vec2(),
I : 1
})

statsAndPhysics.js hosted with ❤ by GitHub


일단 클라이언트가 Join 하면 우리는 위에서 설정 한 기본값으로 상태를 설정하고 (아직 스마트 계약을 설정하지 않았으므로) ,


새로운 물리 엔진을 설정합니다.


// Setup eth account info client.ethAccount = data.ethAccount
// test balance
web3.eth.getBalance(client.ethAccount).then( balance => {
var value = web3.utils.fromDecimal(balance);
var balanceInEther = web3.utils.fromWei(value, "ether")
client.balance = balanceInEther
})

ethBalance.js hosted with ❤ by GitHub


클라이언트가 Ethereum 계좌 주소를 보내면 속성으로 추가합니다.


우리의 Web3 기능성을 테스트하기 위해 계좌잔액을 속성으로 추가합니다. 나중에 우리는 클라이언트에게 보내어 표시 할 수 있습니다.


// add client to clients object clients[client.id] = client


// broadcast connection to players
client.broadcast.emit('playerConnected', {id: client.id});

addAndBroadcast.js hosted with ❤ by GitHub


접속된 클라이언트는 클라이언트 객체에 추가 한 다음, 다른 모든 클라이언트에 브로드 캐스팅합니다. 


그러면 다른 클라이언트에게 방금 접속된 플레이어가 표시됩니다.


client.broadcast.emit를 호출하면 socket.io는 현재 접속한 클라이언트를 제외하고 연결된 모든 클라이언트에게 메시지를 보냅니다.



다음 단계


다음 단계는 TODO 2가 있는 곳으로 갑니다.



입력


// add listener to input client.on('input', function(data){
clients[client.id].input = data
});

input.js hosted with ❤ by GitHub


이렇게하면 입력 패킷에 대한 데이터 처리가 추가됩니다. 이것은 각 방향 키 (WASD)에 대한 Bool 객체입니다. 


클라이언트는 입력이 변경 될 때만이 패킷을 보냅니다.  


이를 통해 우리는 매 20 분의 1 초마다 플레이어로부터 어떤 키가 눌려 있는지 추적 할 수 있습니다.



플레이어 상태 요청


// add listener to player state request client.on('playerStateRequest', function(data){
client.emit('requestedPlayerState', {id: client.id, state: {x: client.body.getPosition().x, y: client.body.getPosition().y}})
});

playerStateRequest.js hosted with ❤ by GitHub


일부 플레이어는 다른 플레이어 보다 나중에 접속하게 됩니다.  


우리는 플레이어의 위치 같은 것을 업데이트하기 위해 플레이어의 전체 상태를 끊임없이 보내고 싶지는 않습니다. 


클라이언트가 연결되면 다른 플레이어가 연결되어 있음을 볼 수 있지만 정보가 없습니다. 


클라이언트는 정보가없는 플레이어를 감지하면 playerStateRequest 패킷을 보냅니다.


이렇게 하면 해당 플레이어의 상태가 클라이언트에 전송되어 최신 상태가 될 수 있습니다.




플레이어 접속 해제


// add listener to disconnect client.on('disconnect', function(){
// broadcast player disconnect
client.broadcast.emit('playerDisconnected', {id: client.id});
// safely remove player
world.destroyBody(client.body)
delete clients[client.id]
console.log("Client disconnected!")
});

disconnect.js hosted with ❤ by GitHub


플레이어가 연결을 끊으면 몇 가지 작업을 수행해야합니다. 먼저, 다른 모든 플레이어에게 연결이 끊어 졌음을 알릴 필요가 있습니다. 


이것은 클라이언트에 의해 일종의 타임 아웃을 추가하여 추측 할 수 있었습니다 (플레이어가 잠시 동안 업데이트되지 않았을 수도 있음). 


플레이어가 잠시 동안 메시지를받지 못하면 단순히 플레이어를 삭제하지 말고 각 클라이언트의 접속유지 신호(Heart Beat)를 확인후 처리해 합니다.


이것은 UDP를 사용할 때 분명히 유용하지만 WebSocket (본질적으로 TCP)에서는 필요 없습니다.


우리가 보내는 모든 메시지는 믿을만 하므로 모든 플레이어를 신뢰할 수있게 만듭니다!


역자주) WebSocket 에서는 Keep Alive, Heart Beat 가 필요 없을 만큼 신뢰한다는 내용인것 같습니다. 


          그래도 모바일 환경에서 처럼 잦은 접속 변경 및 끊김에서는 신뢰 하기 힘들겠죠?




게임 루프


이 코드는 이제 io.on ( 'connection') 함수 외부에 있습니다.


function gameLoop() { // Add horizontal spring force

var clientIds = Object.keys(clients)
for (i = 0; i < clientIds.length; i++) {
// If we are trying to access a client who's recently been removed, do nothing
if (!clients[clientIds[i]] || !clients[clientIds[i]].body) {
continue
}
// Get the client and their input
var client = clients[clientIds[i]]
var { input } = client
// Update client with input
if (input.w) {
var f = client.body.getWorldVector(Vec2(0, -10));
var p = client.body.getWorldPoint(Vec2(0.0, 0.0));
client.body.applyLinearImpulse(f, p, true); }
if (input.a) {
var f = client.body.getWorldVector(Vec2(-0.5, 0));
var p = client.body.getWorldPoint(Vec2(0.0, 0.0));
client.body.applyLinearImpulse(f, p, true);
}
if (input.d) {
var f = client.body.getWorldVector(Vec2(0.5, 0));
var p = client.body.getWorldPoint(Vec2(0.0, 0.0));
client.body.applyLinearImpulse(f, p, true);
}
// Limit the players velocity
var linVel = client.body.getLinearVelocity()
if (Math.abs(linVel.x) > client.stats.maxVel) {
linVel.x = 10 * Math.sign(linVel.x)
}
if (Math.abs(linVel.y) > client.stats.maxVel) {
linVel.y = 10 * Math.sign(linVel.y)
}
// Emit the updated player's state to everyone
io.sockets.emit('updatePlayerState', {id: client.id, state: {...client.body.getPosition(), balance: client.balance} });
}
// Move physics forward in time
world.step(FIXED_TIME_STEP/2);
}

gameLoop.js hosted with ❤ by GitHub



이것이 우리 서버의 강점입니다. 1/20 초마다 실행됩니다 (FIXED_TIME_STEP). 


그것은 아주 간단합니다. 그래서 나는 단지 그것을 간단히 보겠습니다.



Lines 4-5 번 라인 모든 클라이언트 객체의 모든 키를 얻고 루프를 반복합니다.


Lines 7-9 클라이언트가 시간 내에 잠재적으로 제거되었을 수 있으므로  클라이언트가 여전히 존재하는지 확인합니다.


Lines 14-27 현재의 입력 상태에 따라 플레이어 물리 엔진을 조정합니다.


Lines 30-36 모든 플레이어가 플래시가 아닌지 확인하기 위해 속도를 제한합니다.


Lines 39 모든 클라이언트에게 새로운 상태를 전송합니다.  여기에는 우리가 방금 사용했던 클라이언트도 포함됩니다. 

           우리는 클라이언트의 속도를 높여야하기 때문입니다!


Line 42 물리엔진의 속도를 절반으로 줄여 게임을 조금 느리게 했다. 이 부분은 단지 환경 설정입니다.




마지막



setInterval(gameLoop, FIXED_TIME_STEP); server.listen(2217);

finalTouches.js hosted with ❤ by GitHub


우리가 작성한 모든 작업은 매 1/20 초마다 gameLoop 함수를 호출하도록 만든 다음 서버를 시작합니다!



결론


이제 우리는 Web3를 사용하여 Ethereum에 연결된 게임 서버를 갖게 되었습니다!


Part 3에서는 클라이언트를 설정하고 게임을 업로드하여 실제로 유저가 사용하는 방법을 보여줍니다.

Posted by 마스터킹
|

주의) 본 내용은https://itnext.io/making-a-multiplayer-blockchain-game-using-phaser-nodejs-and-ethereum-pt-1-d967aa714efe 를 구글번역기 및 개인적인 주관을 넣어 작성한 내용입니다.


Crypto Kitties는 훌륭합니다. 스마트 계약이 얼마나 강력하고 더 중요하게 재미 있는지 보여주는 첫 번째 dApp이었습니다.


Etheremon이라는 또 하나의 블록 체인 게임이 최근에 다소 생겨났습니다. 그것은 기본적으로 blockchain Pokemon입니다. 


이 게임의 유일한 문제는 비용입니다.


나는 Etheremon을 전투하기 위해 약 15 달러 소요 하였습니다.


이때 나에게 생각이 떠 올랐습니다. Ethereum 위에 재미있는 게임을 만드는 길은 있어야 합니다.  그러나 아직도 싸고 접근하기 쉽습니다.




게임 컨셉


게임은 베틀로얄 컨셉입니다. 플레이어는 캐릭터와 아이템 (각자 자신의 ERC721 토큰이 됨)을 가지고 게임에 참가하고 죽음에 맞서 싸웁니다.


그것을 균일하게 만들기 위해, 게임 플레이는 매우 기초적인 스킬이 될 것입니다. 이 게임은 2D 물리 기반 사이드 스크롤러가 될 것입니다. 


아이템은 플레이어에게 새로운 기술 세트를 제공하고 상태값 만 약간 늘립니다. 어쩌면 한 쌍의 부츠가 중력을 감소 시키거나 특정 샷건이 주위를 날아갈 수 있습니다.


훌륭한 아이템 세트로 게임에 참여하면 도움이되지만 전투를 이기기 위해 플레이어를 충분히 제어 할 수 있어야 합니다.


플레이어는 토큰이 될 세계의  상자를 찾을 수 있습니다. 이 상자는 게임 외부에서 열리며 플레이어에게 무작위로 하나 또는 두 개의 아이템을 생성합니다.


일단 플레이어가 무료로 게임을 즐길수 있어야 합니다. 그들이 거래에 돈을 쓸 필요가있는 유일한 시간은 상자를 열어 아이템을 획득하는 행위 입니다.




스택


클라이언트는 Phaser로 만들어집니다. 그러면 서버의 정보가 사용자에게 전달됩니다.


서버는 NodeJS로 만들어집니다. 사용자는 계정 자격 증명으로 작용하는 Ethereum 지갑을 사용하여 게임에 참여합니다. Web3를 사용하면 서버는 인벤토리 및 현재 로드와 같이 플레이어에 대한 모든 정보를 가져옵니다.


Smart Contract는 Solidity로 이루어질 것입니다. 이것은 모든 문자와 항목을 ERC721 토큰으로 처리합니다.  상자와 아이템 생성도 처리합니다.




이후에는 중요한 내용이 없습니다. 다음 회차로 이동하세요~



Posted by 마스터킹
|