Hello, I’m exploring various things nowadays regarding multiplayer using babylon.js and colyseus. So, I came across:
- Real-time Multiplayer with Colyseus.
- Character animation with input keys like(WASD) while using .gtlf/ .glb model.
Which looks very promising. I tried and integrate both things together to achieve multiplayer character animation. In the current scenario, I am able to get a new character on joining the room and on leaving the room it’s deleting the character. But, some issues that I’m facing are:
- Player is not moving perfectly when two clients are connected.
- On pressing WASD they are colliding with each other not moving.
room.state.players.onAdd = async (player, sessionId) => {
// Local entity map
var inputMap = {};
// This sceneloader is for loading gltf models it constructor takes : location, name, scene
scene.actionManager = new BABYLON.ActionManager(scene);
scene.actionManager.registerAction(
new BABYLON.ExecuteCodeAction(
BABYLON.ActionManager.OnKeyDownTrigger,
function (evt) {
inputMap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
}
)
);
scene.actionManager.registerAction(
new BABYLON.ExecuteCodeAction(
BABYLON.ActionManager.OnKeyUpTrigger,
function (evt) {
inputMap[evt.sourceEvent.key] = evt.sourceEvent.type == "keydown";
}
)
);
//Adding character
playerEntities[sessionId] = await BABYLON.SceneLoader.ImportMeshAsync(
null,
"./assets/",
"orange.glb",
scene
);
// playerEntities[sessionId] = character;
var hero = playerEntities[sessionId].meshes[0];
hero.scaling.scaleInPlace(1);
// Lock the camera on character
camera1.target = hero;
var heroSpeed = 0.04;
var heroSpeedBackwards = 0.02;
var heroRotationSpeed = 0.1;
var animating = true;
const walkAnim = scene.getAnimationGroupByName("Walk");
const raiseHandAnim = scene.getAnimationGroupByName("Raise");
const idleAnim = scene.getAnimationGroupByName("Idle");
const waveHandAnim = scene.getAnimationGroupByName("Raise");
const sitAnim = scene.getAnimationGroupByName("Sit");
var isCurrentPlayer = sessionId === room.sessionId;
scene.onBeforeRenderObservable.add(() => {
var keyDown = false;
if (inputMap["w"]) {
hero.moveWithCollisions(hero.forward.scaleInPlace(heroSpeed));
// Send position update to the server
room.send("updatePosition", {
x: hero.position.x,
y: hero.position.y,
z: hero.position.z,
rx: hero.rotation.x,
ry: hero.rotation.y,
rz: hero.rotation.z,
});
keyDown = true;
}
if (inputMap["s"]) {
hero.moveWithCollisions(
hero.forward.scaleInPlace(-heroSpeedBackwards)
);
// Send position update to the server
room.send("updatePosition", {
x: hero.position.x,
y: hero.position.y,
z: hero.position.z,
rx: hero.rotation.x,
ry: hero.rotation.y,
rz: hero.rotation.z,
});
keyDown = true;
}
if (inputMap["a"]) {
hero.rotate(BABYLON.Vector3.Up(), -heroRotationSpeed);
// Send position update to the server
room.send("updatePosition", {
x: hero.position.x,
y: hero.position.y,
z: hero.position.z,
rx: hero.rotation.x,
ry: hero.rotation.y,
rz: hero.rotation.z,
});
keyDown = true;
}
if (inputMap["d"]) {
hero.rotate(BABYLON.Vector3.Up(), heroRotationSpeed);
// Send position update to the server
room.send("updatePosition", {
x: hero.position.x,
y: hero.position.y,
z: hero.position.z,
rx: hero.rotation.x,
ry: hero.rotation.y,
rz: hero.rotation.z,
});
keyDown = true;
}
if (inputMap["r"]) {
keyDown = true;
}
if (inputMap["z"]) {
keyDown = true;
}
if (inputMap["h"]) {
keyDown = true;
}
if (keyDown) {
if (!animating) {
animating = true;
if (inputMap["s"]) {
walkAnim.start(true, 1.0, walkAnim.from, walkAnim.to, false);
} else if (inputMap["r"]) {
raiseHandAnim.start(
true,
1.0,
raiseHandAnim.from,
raiseHandAnim.to,
false
);
} else if (inputMap["h"]) {
waveHandAnim.start(
true,
1.0,
waveHandAnim.from,
waveHandAnim.to,
false
);
} else if (inputMap["z"]) {
sitAnim.start(true, 1.0, sitAnim.from, sitAnim.to, false);
}
} else {
walkAnim.start(true, 1.0, walkAnim.from, walkAnim.to, false);
// Send position update to the server
room.send("updatePosition", {
x: hero.position.x,
y: hero.position.y,
z: hero.position.z,
rx: hero.rotation.x,
ry: hero.rotation.y,
rz: hero.rotation.z,
});
keyDown = true;
}
} else {
if (animating) {
//Default animation is idle when no key is down
idleAnim.start(true, 1.0, idleAnim.from, idleAnim.to, false);
//Stop all animations besides Idle Anim when no key is down
walkAnim.stop();
sitAnim.stop();
raiseHandAnim.stop();
waveHandAnim.stop();
//Ensure animation are played only once per rendering loop
animating = false;
}
}
});
playerNextPosition[sessionId] = hero.position.clone();
player.onChange = () => {
playerNextPosition[sessionId].set(player.x, player.y, player.z);
hero.position.set(player.x, player.y, player.z);
hero.rotation.set(player.rx, player.ry, player.rz);
};
scene.registerBeforeRender(() => {
for (let sessionId in playerEntities) {
var targetPosition = playerNextPosition[sessionId];
hero.position = BABYLON.Vector3.Lerp(
hero.position,
targetPosition,
0.05
);
}
});
};
This is the code I’ve made. Please help me out to get proper positioning and WASD controls.