Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Non-player objects with fast physics interaction: like a ball in pong

Discussion in 'Multiplayer' started by Yany, Sep 13, 2017.

  1. Yany

    Yany

    Joined:
    May 24, 2013
    Posts:
    96
    Dear Unity fellows, I have been thinking of the following problem a lot (really), but to be honest, I found rather few info to achieve a good result.

    Imagine a two player 3D game where you have a ball and two opposing players. Their task to hit the ball (something like in the classic pong) and to win the duel by making the opponent to miss it. One of the player is the host+client, the other is a client. The whole game is based on the Unity's basic physics.

    My problem is: one of the player will be always handicapped because of the latency to the host, as one of the players are the host as I mentioned, and there's the ball too, and the other player, the remote client is far away from the ball. If I want to create a competitive, real-time, fast paced duel, that is just not allowable to present such a bias.

    My questions will concentrate on the ball, as I believe we have a chance to improve the situation only by tricking the net code of that particular object.
    1. What's Unet's basic concept for handling such an object that it physically interacted with the players?
    2. Can and should we pass the ball to the player to which the ball is closer to by using AssignClientAuthority()? E.g: Left is host, right is client. When the ball is on the left half of the field, assign it to the host, when it's to the right, assign it to the client? Can it help on the latency issues at all?
    3. Should we use 2 instances of the ball at each client and sync their move somehow and only show the one which is closer to the given player with the authority (just like the version I described in #2)
    4. Should the ball be spawned like an enemy object using a spawner or should we use other mechanism?
    I already solved the players' latency issue by using a rather basic but effective prediction method, but for the ball I just have no idea yet how to create and handle it. I would like to make the game enjoyable even with 100~150ms of latency, only the seemingly correct physics interaction is the huge question. If there's no solution to eliminate this issue, but can be improved by sacrificing the hosts 0-latency, that's fair to me. I'd like to take both player's chance close to each other as much as I can.

    Quick notes:
    1. The ball is affected by gravity and other physics based effects and the players also a bit more complex than in the original pong, thus any hack to avoid using physics wont work.
    2. The game technologically is in 3D, but the match is played in 2D only with Z-position constraints using 3D physics and 3D objects.
    Thanks for you hints.
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I like your idea of handing off authority of the ball at the field's mid point. That should allow any player hitting the ball to place their paddle correctly based on the position as they see the ball, instead of a prediction of its position on the host. I'm wondering though if you may have to come up with a solution for handling a bit of jitter when authority is transferred (I've never tried transferring authority of a fast moving object in flight).
     
  3. Yany

    Yany

    Joined:
    May 24, 2013
    Posts:
    96
    Okay, I'm advancing with the basic idea, however I have a little(?) issue. I wrote a TargetRpc method that I call on the server of course. AFAIK the TargetRpc functions executed on the client belonging to the specified NetworkConnection in the first argument. Well, whenever I call it, I can see it runs on the host whatever the NetworkConnection is. Is it a bug in 2017.1.1? Or do I misunderstand the concept of TargetRpc functions?

    Code (csharp):
    1.  
    2. [TargetRpc]
    3. void TargetSyncStates(NetworkConnection p_Target, BallNetStates p_BallStates)
    4. {
    5.         Debug.Log ("TargetSyncStates: " + p_Target);
    6.         ReceiveStates (p_BallStates);
    7. }
    8.  
    9. [Command]
    10. void CmdWhatEver()
    11. {
    12.         NetworkConnection l_NetConn = GetOtherPlayerConnection ();
    13.         TargetSyncStates(l_NetConn, m_BallStates);
    14. }
    15.  
    16.  
    In the Log you can see:

    Code (csharp):
    1.  
    2.   TargetSyncStates: hostId: 0 connectionId: 1 isReady: True channel count: 2
    3.   TargetSyncStates: hostId: -1 connectionId: 0 isReady: True channel count: 0
    4. ...
    5.  
    And so on, so I can see that the networkconnection value is changing as I wanted, but the log is printed on the host only and the client does not show any sign of running the TargetRpc function in the log.
     
    Last edited: Sep 22, 2017
  4. Yany

    Yany

    Joined:
    May 24, 2013
    Posts:
    96
    Okay, forget my last notes, I called the methods on the wrong objects.

    Well about the final result:
    - The I do not transfer positions and any info constantly, but only on collisions.
    - In the middle of the playground I change the authority for the ball to the player who the ball approaches to.
    - The "passover" is fluid, smooth like silk. :)
    - The only visual glitch is when the other player hits the ball, as this is the first time that player sends transformation info back to "my" player. But as it is at the farther side of the screen, this is the best place to have this sync-glitch. I could work on it too, but the effort it may need is not worth it.

    The the theory works quite well in practice, thus every time I get the ball I don't see any sync-mess, the movement of the ball is perfectly smooth and the network transmission requires low bandwidth. I hope soon I can show you the working demo.
     
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'm glad you've got this working pretty well. :)