Multiplayer Game Ball Pickup and Throw Physics Replication

I am working on a game that is fairly simple in scope, but has one fairly complicated aspect. The game revolves around two teams (4-5 players) grabbing/passing/throwing a game ball into opposing goals. I am running into issues with replicating the game ball itself and keeping the action inputs from the players in sync with the game ball with any kind of real world packet lag/effects factored in. It is simulating physics, which I know is very complicated and can only be handled on a case by case basis, but I was wondering if anyone could point me in the right direction for a solution to my issues. If anyone has comments on a better way to handle the interaction with the game ball from the client characters, I am open to all suggestions and would love to hear peoples thoughts and ideas.

Now for a detailed view on my setup so far:

  1. Client actors walk over to the ball and the ball generates overlap events.
  • In the begin overlap, the ball actor passes a reference to itself to the character, and sets a flag on the character that indicates to the character that the ball can be picked up

  • In the end overlap, the ball actor sets the ball reference on the character to null, and sets the character flag from the begin overlap to false, indicating the ball can no longer be picked up.

  1. On the client character, the character has an input event for pickup, and an input event for throw. Both check for validity of the ball reference and if the ball can be picked up/is currently being carried.
  • the pickup event calls a function (on the server and locally) using the ball reference in the ball actor class that attaches the ball to a socket in the player’s hand. This function is passed a reference to the character, and the name of the socket to attach to. So, the actual attaching takes place in the ball actor class.

  • This pickup function in the ball actor class turns off physics and attaches to the character hand socket.

  1. the throw event calls a function (on the server and locally) using the ball reference to call a function in that class to detach from the socket, reactivate physics and add an impulse to the ball. The function is passed a direction vector that is computed using the camera direction at time of throw.

My issues with this, are if I only call the attach and throw functions on the server, there is an unresponsive lag (as would be expected) for picking up the ball and throwing it. If I call the pickup and throw functions on the server and locally, sometimes the ball will disappear on the client side and be seen jittering around somewhere on the map (usually in the middle) and throwing the ball has the obvious server corrections on the client side.

Any help or guidance would be greatly appreciated. Not really looking for anyone to solve my problems for me, more looking for guidance or a point in the right direction if any of you have run into similar issues or heard of solutions working for other people for similar problems.

For attaching:

This is pretty complicated, since you will have to deal with mispredictions. It is very possible that you pick up the ball on the client but the server disagrees, you will then need a clean way to rewind this without causing havoc. There is no easy way to do this, you will have to understand the involved systems on a fairly low level and come up with a creative solution that works for your game. If that sounds like too much, the best option would be to simply accept the lag in this case. You can mask the lag a little by creating local cosmetic effects (e.g. a sound effect and maybe some particles) whenever the client thinks they picked up the ball, although this could be confusing in cases where the pickup does not actually happen. A common pattern is to create one local effect when the prediction happens, and another local effect when the action was confirmed by the server. An example would be a predicted hit detection system that displays blood splatters on a predicted hit, but only plays a hit sound once the hit was confirmed by the server.

For throwing:

This is a much simpler case. If you don’t want this to lag you will have to disable the built-in replication (at least for throws that the player initiated) and build your own prediction system. This isn’t too complicated, you’ll just have to start the movement on the client and server separately, then frequently update the client position and fast-forward based on a timestamp sent by the server after each correction (otherwise the correction would “pull back” the ball).

Mispredictions will still happen, but you can reduce that by implementing your own simple ball physics that behave more deterministically, and you can also smooth out corrections by interpolating between the predicted and corrected positions.

One thing to consider however is that this means that your own throws will behave differently (predicted ahead of time, with occasional corrections) to balls thrown by other players (lagging behind reality, but smooth). One way to make this more consistent would be to also fast-forward throws of other players, but since you can’t predict when they will throw a ball, this means that the initial movement would be a huge sudden jump forward. Yet another possibility would be to use either method only for the beginning of a throw, and then slow down or speed up the local simulation as required until it matches the desired consistent behaviour.

As you already expected there is no simple one-size-fits-all solution, and because of that Unreal can’t provide you any ready made solution out of the box. Thankfully simulating and predicting a simple ball movement is probably the easiest case there is, but since this requires a custom solution it still requires quite a bit of thought and some expertise.

This also might be a solution for you. Something I’m looking at for ocean physics Snapshot Interpolation | Gaffer On Games