Code Context:
Phaser3
Socket.io
Multiplayer game similar to Agar.io
On socket connection, server broadcasts: player id, skin, x pos, y pos, "mass"
Server also sends previous room data on connection for player
Client creates sprites from data "point 4" declares, renders and stores copy locally
Position is emitted when Phaser3's update() function loops
Issue:
When creating the sprites, creates them all in one spot and not at the randomly assigned x,y coords
(could be separate issue) it seems to render the sprite twice, one of which don't move with controls
server.js:
function hypotenuse(x,y,x1,y1)
{
deltaX = x1-x;
deltaY = y1-y;
a = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
return a;
}
function randomInt() {
min = Math.ceil(0.1);
max = Math.floor(8000);
return Math.floor(Math.random() * (max - min) + min);
}
io.on('connection',(socket)=>
{
console.log(`${socket.id} joined the universe!`);
universe['0'].players[socket.id] = {playerID:socket.id,x:randomInt(),y:randomInt(),mass:50}; //assign an arbitrary value for x and y, set it client side.
socket.emit('client',socket.id,universe['0'].players[socket.id].x,universe['0'].players[socket.id].y,null,universe['0'].players[socket.id].mass);
socket.broadcast.emit('join',socket.id,universe['0'].players[socket.id].x,universe['0'].players[socket.id].y, null,universe['0'].players[socket.id].mass);
socket.emit('loadUniverse', universe['0'].players); //sending to client only
socket.on('updatePos',({player,vx,vy,x,y})=> //make into object
{
if(universe['0'].gameRules.mass<200)
{
let id = 'mass:'+ randomInt() + randomInt() + randomInt();
console.log(`mass id: ${id}`);
universe['0'].players[id] = {playerID:id,x:randomInt(),y:randomInt(),mass:10};
//do not use this, broadcast to individual rooms with io.to(room).emit(channel,content)
io.emit('spawnMass',id,universe['0'].players[id].x,universe['0'].players[id].y,null,universe['0'].players[id].mass);
universe['0'].gameRules.mass+=1;
}
if(player in universe['0'].players)
{
universe['0'].players[player].x = x;
universe['0'].players[player].y = y;
for(const player1 in universe['0'].players)
{
if(player1!==player)
{
//distance between two coord pairs
let distance = hypotenuse(universe['0'].players[player1].x,universe['0'].players[player1].y,x,y);
//console.log(distance);
//console.log('debugging NaN1')
if(distance < 100)
{
console.log('overlapping')
if(universe['0'].players[player].mass>universe['0'].players[player1].mass)
{
universe['0'].players[player].mass+=universe['0'].players[player1].mass
socket.emit('attracted',universe['0'].players[player].playerID,universe['0'].players[player1].playerID)
socket.emit('eliminated',universe['0'].players[player1].playerID) //have all state change in same socket event
delete universe['0'].players[player1]
}
else
{
universe['0'].players[player1].mass+=universe['0'].players[player].mass
socket.emit('attracted',universe['0'].players[player1].playerID,universe['0'].players[player].playerID)
socket.emit('eliminated',universe['0'].players[player].playerID) //have all state change in same socket event
delete universe['0'].players[player]
}
}
//if in radius, remove player from room and add points to winner
}
}
}
socket.broadcast.emit("updatePos1", player,vx,vy);
})
socket.on('disconnect',()=>
{
delete universe['0'].players[socket.id]
//emit a delete event
console.log(`${socket.id}player left the universe!`)
})
})
Relevant Client Code:
scene.socket.on('connect',()=> //needs to chain from the connect
{
this.scene.socket.emit('join',this.socketID) //gives id to server, server chooses skin, server broadcasts
console.log(`connected`);
})
scene.socket.on('updatePos1',(socketID1,vx,vy)=>
{
if(this.socketID!==socketID1)
{
//console.log('socket was not yours!');
this.scene.gameHandler.players[socketID1].sprite.body.setVelocity(vx,vy);
}
})
//ITEM BREAKS UP INTO SMALLER CHUNKS IF GRAVITY IS "VIOLENT" ENOUGH
scene.socket.on('attracted',(player,player1)=>
{
this.scene.gameHandler.players[player].mass+=this.scene.gameHandler.players[player1].mass
})
scene.socket.on('eliminated',(player)=>
{
console.log('eliminated',player,this.scene.gameHandler.players[player])
this.scene.gameHandler.players[player].sprite.destroy(true);
delete this.scene.gameHandler.players[player];
})
scene.socket.on('join',(socketID0,x,y,skin,mass)=>
{
console.log(`Player ${socketID0} joined`);
this.scene.gameHandler.loadPlayer(socketID0,x,y,skin,mass);
})
scene.socket.on('client',(socketID0,x,y,skin,mass)=>
{
this.socketID = socketID0;
this.scene.gameHandler.loadPlayer(socketID0,x,y,skin,mass);
})
scene.socket.on('loadUniverse',(universe)=>
{
for(const property in universe)
{
console.log(`propery:${property}`);
console.log(universe[property].x,universe[property].y)
this.scene.gameHandler.loadPlayer(property,universe[property].x,universe[property].y,null,universe[property].mass);//make this dynamic
}
})
scene.socket.on('spawnMass',(id,x,y,skin,mass)=>
{
this.scene.gameHandler.loadPlayer(id,x,y,skin,mass);
this.scene.gameHandler.players[id].sprite.setScale(0.2,0.2)
})
}
updatePos()
{
console.log(`${this.socketID} for updatePos()`)
this.scene.socket.emit(
'updatePos',
{
player:this.socketID,
vx:this.scene.gameHandler.players[this.socketID].sprite.body.velocity.x,
vy:this.scene.gameHandler.players[this.socketID].sprite.body.velocity.y,
x:this.scene.gameHandler.players[this.socketID].sprite.body.x,
y:this.scene.gameHandler.players[this.socketID].sprite.body.y
}
)
}
loadPlayer function in gameHandler.js:
loadPlayer(socketID,x,y,skin,mass) //get websocket to load player
{
if(socketID)
{ //id:{sprite:x}
this.players[socketID] =
{
sprite: this.scene.physics.add.sprite
(
x,//this.scene.game.config.width * 0.5,
y,//this.scene.game.config.height * 0.5,
"arc_pink"
),
mass: mass
}
}
console.log(`Load player returned: ${this.players[socketID].mass}`)
this.players[socketID].sprite.x = x;
this.players[socketID].sprite.y = y;
this.players[socketID].sprite.setOrigin(0.5,0.5);
this.players[socketID].sprite.body.setCollideWorldBounds(true);
socketID == this.scene.socketsHandler.socketID?this.scene.cameras.main.startFollow(this.players[socketID].sprite):null;
console.log(`Load player returned: ${this.players[socketID]}`)
}
In index.js I have this phaser config:
const config = {
parent: "phaser-example",
type: Phaser.AUTO,
scale:
{
mode: Phaser.Scale.FIT,
width: 1800,
height: 1600
},
autoCenter: Phaser.Scale.CENTER_BOTH,
physics: {
default: "arcade",
arcade: {
Gravity: { x: 0, y: 0 },
debug: false,
},
},
scene: MyGame,
};
Bounds to world: -90000, -90000, 90000, 90000
Question:
What am I doing wrong, and how is it wrong? I'm dedicated to learning how multiplayer games are made, any input helps. Thanks.
Well the double drawing is due to the call of socket.emit('loadUniverse',...);
since the player gets to create the player sprite twice (the first time socket.emit('client',...);
).
The rest seems fine, at least my recreated demo, with your code.
btw.: a compact phaser multiplayer game tutorial can be found here https://gamedevacademy.org/create-a-basic-multiplayer-game-in-phaser-3-with-socket-io-part-1/ uses phaser headless on the server side.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.