I am building a 2d top-down mmo. very lightweight.
I have a master client that determines everythings position, and actions and send this information to all other clients.
Now I have made a great deal of different solutions to movement of my NPCs across the network and some solutions are better than others but noone have been perfect. So I would love some feedback on this.
Master client sends information to server:
void Start () {
InvokeRepeating("CheckForMove", 1.0f, 1f);
}
void CheckForMove()
{
var distance = Vector3.Distance(lastPos, transform.position);
if (distance > 0.02) // Dont send information if movement is very small i.e bumping into a wall repeatedly etc
{
socket.Emit("enemyMove", Network.MobIdAndLocationToJson(gameObject.name, transform.position));
moveEmit = true;
lastPos = transform.position;
spawnScript.spawnedEnemies[gameObject.name] = transform.position;
}
}
Server reveives the information:
socket.on('enemyMove', function(data){
// moves the monster that matches the given ID
console.log('enemy is moving', data);
socket.broadcast.emit('enemyMove', data);
});
Player Clients receive the move information:
private void OnEnemyMove(SocketIOEvent e)
{
var position = new Vector3(e.data["x"].n, e.data["y"].n, -0.5f);
var enemy = enemySpawner.FindEnemy(e.data["id"].str);
var enemyNavigator = enemy.GetComponent<EnemyNavigator>();
enemyNavigator.MoveThisEnemy(position);
}
now the question becomes what is the best way to go from here to smooth this movement best I can?
The solutions I have tried are as follows:
------------------ solution 1 ----------------------
public void MoveThisEnemy(Vector3 position)
{
anim.SetBool("walk", true);
startTime = Time.time;
DistanceToDest = Vector3.Distance(transform.position, position);
destPos = position;
isMoving = true;
}
and in update:
if (isMoving)
{
if (currentTarget != null)
{
float currentDuration = Time.time - startTime;
float journeyFraction = currentDuration / totalDistanceToDestination;
transform.position = Vector3.Lerp(transform.position, destPos, journeyFraction);
}
although this works fine the NPcs movement is wonky as in it finishes its movement faster than the next update can come no matter what and therefore although lerping it seems to move faster than I can provide it with updates. imagine a cartoon slug that moves fast, stops, moves again, stops. so Npc is always there and not just teleporting but still not the effect I am looking for.
------------------ solution 2 ----------------------
Here I simply try to just reproduce on the player client what I am doing on the master client but I make sure to correct the position of the NPC ever so often to guarantee its in the correct position.
public void MoveThisEnemy(Vector3 position)
{
anim.SetBool("walk", true);
transform.position = position;
isMoving = true;
}
and in update:
if (isMoving)
{
if (currentTarget != null)
{
var targetDistance = Vector3.Distance(transform.position, currentTarget.transform.position);
if (targetDistance > minDist)
{
Vector3 direction = (currentTarget.transform.position - transform.position).normalized;
rigid.MovePosition(transform.position + direction * speed * Time.deltaTime);
}
}
this is actually a very good solution as I can get the position correct with minimal amounts of data sent over the network. but since I have obstacles in my game it gets very weird as moving the NPCs transform doesnt include collisions and it can perform weird movements when colliding. Furthermore it seems to teleport to its position because of the transform.position updates when playing in full screen. barely visible in smaller resolution for some reason.
I have also tried using rigidbody.moveposition in the MoveThisEnemy function but this just means it doesnt get updated correctly as moveposition seems to be less precise than transform.position.
any feedback would be greatly appreciated.
thank you.