What I want to achieve is to calculate the real object position based on its speed and a destination position.
In my server, I have a MapInstance
that have a list of MapLayer
that have MapRegion
s.
To resume we have:
- 1
MapInstance
- N
MapLayer
s - X
MapRegion
s
- N
Each MapInstance
will update in an asynchronous task all his map layers and the common object such as NPCs and the MapLayer
will update his regions of entities (monsters/items).
On the client side, when I click somewhere on the map, it sends a packet to the server with the destination position.
Then, on the server-side I receive the position and set the entity.Movable.DestinationPosition
property.
As I said earlier, each map instance are updated in an asynchronous task and updates the map layers and common entities. My problem is, my realtime position calculation formula is wrong somewhere, and I can't find where.
To understand the problem, there is some inputs:
- Entity speed: 0.08 (8%)
Position
andDestinationPosition
areVector3
(class) instance, whereX
,Y
andZ
are properties.
This is my code:
public void StartUpdateTask(int delay)
{
Task.Run(async () =>
{
const double FrameRatePerSeconds = 0.66666f;
double previousTime = Environment.TickCount;
while (true)
{
if (this._cancellationToken.IsCancellationRequested)
break;
double currentTime = Environment.TickCount;
double deltaTime = currentTime - previousTime;
previousTime = currentTime;
this.GameTime = (deltaTime * FrameRatePerSeconds) / 1000f;
lock (SyncRoot)
{
foreach (var entity in this.Entities)
Walk(entity);
foreach (var mapLayer in this._layers)
mapLayer.Update();
}
await Task.Delay(delay, this._cancellationToken).ConfigureAwait(false);
}
}, this._cancellationToken);
}
mapLayer.Update()
method:
public override void Update()
{
this.GameTime = this.Parent.GameTime;
foreach (var entity in this.Entities)
Walk(entity);
foreach (var region in this._regions)
{
if (region.IsActive && region is IMapRespawnRegion respawnRegion)
{
foreach (var entity in respawnRegion.Entities)
{
Walk(entity);
}
}
}
}
And the calculation formula:
private void Walk(IMovableEntity entity)
{
if (entity.MovableComponent.DestinationPosition.IsZero())
return;
if (entity.MovableComponent.DestinationPosition.IsInCircle(entity.Object.Position, 0.1f))
{
entity.MovableComponent.HasArrived = true;
entity.MovableComponent.DestinationPosition.Reset();
}
else
{
entity.MovableComponent.HasArrived = false;
double entitySpeed = entity.MovableComponent.Speed * entity.MovableComponent.SpeedFactor;
double speed = ((entitySpeed * 100f) * entity.Context.GameTime);
float distanceX = entity.MovableComponent.DestinationPosition.X - entity.Object.Position.X;
float distanceZ = entity.MovableComponent.DestinationPosition.Z - entity.Object.Position.Z;
double distance = Math.Sqrt(distanceX * distanceX + distanceZ * distanceZ);
// Normalize
double deltaX = distanceX / distance;
double deltaZ = distanceZ / distance;
double offsetX = deltaX * speed;
double offsetZ = deltaZ * speed;
if (Math.Abs(offsetX) > Math.Abs(distanceX))
offsetX = distanceX;
if (Math.Abs(offsetZ) > Math.Abs(distanceZ))
offsetZ = distanceZ;
entity.Object.Position.X += (float)offsetX;
entity.Object.Position.Z += (float)offsetZ;
}
}
With this current formula, my players and monsters arrive to destination between 1-2 seconds sooner on the server side compared to the client-side... Do you have any idea what I'm doing wrong ? Appriciate if someone could guide me and explain me how to solve my problem. :-)
Thank you