Client running ahead of server?

id still just do it on server only and replicate the movement,

doing it on client can only have problems down the line, ie collisions would be wrong

How many tiles are being traversed in the videos shown ?

Is it a linear path of like 50 tiles, or is it just a single large path segment ?

The whole lane is 18x132 tiles. So you’re seeing unit move maybe 65 tiles.

This is how the process works: The server is holding an array of int points for each tile. Client requests server to make a unit. Server validates request, does pathfinding creating an array of int points, spawns unit and starts moving the unit. Then the server serializes the path into an 8 byte message, sends it to the clients so the client can have smooth client side prediction for unit movement.

How would you go about smoothing the replicated movement on the client in this case? When 500 units are moving it gets really choppy.

Ok so, if my observation is right, which is a long shot, but sounds plausible, here’s an illustration.

Unit is following path A->B->C, so there’s first a timeline doing A->B, and once completed another timeline starts for B->C.

The red lines represent frames. With this approach, there will always be some time wasted by the frame that finishes each timeline. The longer the frame time, the more time risk being wasted. In practice, the wasted time is very small there, but an accumulation of it over many segments will become noticeable.

As a workaround you could have server-only movement, or implement error correction, that would solve the desynchronization, but that wouldn’t really solve the underlying issue.

Personally I’d start by getting rid of the timeline. I feel like it’s only making things more complex. Timeline’s useful for curves, but here if you do any curve other than linear then your movement is gonna look very weird with unnecessary slowdowns and accelerations each tile.

So I’d just replace it with a more simple
Tick → AddActorLocation(Direction*MoveSpeed*DeltaTime)

This alone won’t solve the problem. It may appear to solve it on linear path, but in reality you’ll overshoot each tile’s destination by a fraction of frame, which will start causing problems once you have turns.

However with a tick-based approach, you can easily solve the overshoot.
The distance travelled in one frame is equal to MoveSpeed * DeltaTime.
Before moving with AddActorLocation, you can first calculate distance needed to reach end of segment, and see if it’s smaller than frame travel distance.
If it is, then you can end the current segment, start the next segment, and travel by the remainder. All in a single frame.

Alternatively, you can precalculate a spline for the entire path and simply follow that spline all the way to the end.
This way, no issue with intermediate destinations and overshoots.
Also, you’ll naturally get curved movement from this, which is nice, if that’s what you are after.
However this could be computationally expensive depending on the length of your paths, I don’t really know.


Final note, all of this is really only relevant if you want movement speed to be precisely what you want it to be.
In practice, server shouldn’t be running at 12fps, so the time wastes are gonna be really small. A simple movement correction approach to keep clients in sync should render the issue unnoticeable.

2 Likes

This is excellent! Thanks for taking the time. I’m reworking the movement system now. I’ll let you know how it pans out.

Hey Chatouille. I’ve tried to do this on my own but to no avail - When you say AddActorLocation(DirectionMoveSpeedDeltaTime) How would this look in blueprint? I’m not sure in what units direction or movespeed is. The only directions I’ve worked with is a vector and I have a custom movespeed I’ve been using for my actors, but I don’t believe that’s what you’re referencing. Here is how mine works in the old system:

I’m also struggling with you’re frame leftover piece. You’ve already done so much so I’m sorry to bother more on this.

Thanks

Direction is a vector. Basically a vector from unit position towards end of segment. So in code would be like (EndOfSegment - GetActorLocation).Normalize

Move speed is whatever you want your units move speed to be, in distance per second, so your variable seem appropriate.

At first it should look like this.
I suggest not bothering with rotation till you are satisfied with movement first.

Now need to add in check to detect if we reach end of segment, since without timeline we don’t have a “finished” event to rely on, we have to detect that manually.
I added some temp variables (TravelDistance and DestDistance) to reduce clutter.

This should handle “waypoints” system. Now to solve the overshoot, whenever I’ve reached a waypoint I need to travel towards next waypoint by the remaining travel distance.
I made a function to loop back into the code and reduce clutter.

1 Like

Wow, this community never ceases to amaze me! Thank you so much for taking the time to hash this out with me. I completely understand this now. Very clear explanation. I wish I could return the favor but you probably know everything I know XD.

Any Ideas on this one?