Shared object (a ball) between clients

Options
Pier
Pier
Hi everyone.

After at least 2 weeks spent trying to solve this issue I have decided to use the mighty jolly: You.

I am developing a top down game similar to Air Hockey.
I have successfully initialized the two players and smoothed their movements thanks to Lerp().

The question is simple: How should I deal with the ball?

Should it be Instantiated through PhotonNetwork.Instantiate() or should it be already part of the game scene?
Should I use RPCs or OnPhotonSerializeView() with Unreliable on Change/Unreliable?

The closest decent result I could achieve had been with RPCs:
In the BallScript, in the Update(), I was checking if the ball position had changed and in if yes I was calling the RPC method UpdatePositionRotation.
Two problems with this:

1. It is laggy.
2. If a player touch the ball and while the ball is still moving another player touches it, some weird jittering effects start

God bless whoever is so patience to enlighten me!

Pier

Comments

  • Tobias
    Options
    Actually, PUN is not extremely well prepared to do physics in networking.
    To make things easier, each object has an owner. Only the owner is able to send updates about an object to the others.
    That has an implication for this case: If the owner doesn't recognize you are moving the game object, it won't send those updates accordingly!
    If you inform the owner of the ball first, things tend to become laggy: Your hit goes to the owner who updates and then sends the new movement.
    Neither is optimal.

    You need some way to transfer ownership automatically. Example: When the ball is in your half, then you own it and isMine should be true for the ball. You write the updates.
    Alternatively you can also get rid of the direct ball sync via PhotonView. Each player can send "hits". Send where and when it happened how hard and each player might be able to run the physics on some ball and get to (more or less) the same conclusion where the ball is?!
    The latter is tricky. You need to figure out which hit did actually happen when both players hit the ball at about the same time. If you send RPCs to everyone (including the sender) then the server defines a sequence of RPCs, which can be used to determine which ones happened...
  • Pier
    Options
    Thank you for your reply Tobias.

    I will work on it and share the outcome in a (hopefully) nearly future.

    Regards,
    Pier
  • Pier
    Options
    Hi everyone!

    I am almost there..

    I have decided to go for the tricky option: Sending a "Hit" with all the information regarding direction, velocity..
    As you predicted, each player then runs the physics on the ball and gets almost at same conclusion.

    However I haven't understood exactly how to make the server defining a sequence of RPCs and therefore check which happened first. Is there a function in Photon that stores a list of all the RPCs sent?
    At the moment in fact the ball gets a bit "confused" when two players hit it at almost the same time..

    Can you please en-light me on that part Tobias?

    Thank you in advance for your time and cooperation.

    Pier
  • Tobias
    Options
    There is a new option PhotonTargets.AllViaServer. If you send the RPC with that, the client who sends the RPC will also execute it when it comes back from the server.
    This way, the order of RPCs is automatically guaranteed: The RPC order in which the server sends them is guaranteed on all clients.

    You might want to make up an sequence number for the hits, which you can increase for each hit:
    Start with 1. Any player who got the RPC 1 will send the next action a 2. Only the first RPC with 1 must be executed, all other discarded (by your code).
    Use a byte (really small) and prepare it to "wrap around" on overflow.
  • Pier
    Options
    Hi guys!

    After almost two week I am updating you regarding the evolution of this journey.

    I have decided to change the game play of my game:
    1. The player doesn't kick the ball as soon as he/she touches it but instead the ball is grabbed by the player.
    2. Then he/she will get rid of it by pressing the 'kick/pass' button.

    The second part follows exactly the same logic I have used for the previous kick: As soon a the player presses the 'kick/pass' button a RPC is sent to all the others with information such as direction, speed, position and then each player runs the ball movement locally. (Bytheway, having changed the ball Update() to FixedUpdate() has increased dramatically the precision of the ball movement: Now it ends up in the same position for all players!)

    The first part instead (the ball possession) is driving me crazy!

    I successfully switch ball ownership among players by sending an RPC: If a player collides with the ball he/she sends an RPC to everyone saying that he/she is now the owner.

    Then, in the Update() of "PlayerController.cs" I am setting the position of the ball equal the player position it collided with.

    [code2=csharp]if(m_oBallScript.g_bBallPossession)
    {
    m_oBallScript.transform.position = transform.position;
    }[/code2]

    Beautiful, the player who touches the ball now grabs it and can move around with it.

    The question is: How do I update the ball position across the network for all the other players??

    The ball is an object which is already part of the scene. It has a PhotonView attached which is not observing anything. the [RPC] function "UpdateBallOwnership(bool isOwner)" is declared in its "BallScript.cs".

    The player is instantiated with PhotonNetwork.Instantiate() and it has a photon view component attached which is observing its "PlayerNetwork.cs" script. Observe option is on unreliable.

    While the Player is updating his position smoothly across the network, the ball is really laggy and always in late, behind all the players position. Even on the local player the ball seems to slides back from its position.

    [code2=csharp]void FixedUpdate ()
    {
    //only move the other players on the network
    if(!photonView.isMine)
    {
    transform.position = Vector3.Lerp(transform.position, m_vPlayerRealPosition, Time.deltaTime * 5);
    transform.rotation = Quaternion.Lerp(transform.rotation, m_qPlayerRealRotation, Time.deltaTime * 50);

    // UNSURE!!
    m_oBallTransform.position = Vector3.Lerp(m_oBallTransform.position, m_vBallRealPosition, Time.deltaTime * 5);
    }
    }

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
    if(stream.isWriting)
    {
    stream.SendNext(transform.position);
    stream.SendNext(transform.rotation);

    // UNSURE!!
    stream.SendNext(m_oBallTransform.position);
    }
    else
    {
    m_vPlayerRealPosition = (Vector3)stream.ReceiveNext();
    m_qPlayerRealRotation = (Quaternion)stream.ReceiveNext();

    // UNSURE!!
    m_vBallRealPosition = (Vector3)stream.ReceiveNext();
    }
    }[/code2]

    This is the code inside my "PlayerNetwork.cs". The part I am absolutely not sure of are the one regarding the ball.

    Has anyone a better way to send the ball information across the network?

    Sorry for this novel I have written but I am from Italy and when we want to express a simple concept we need thousands of words!

    PS. I have decided to purchase the PUN plus because I want to export the game to Android and iOS. This plugin is truly amazing!

    Regards,
    Pier
  • barry100
    barry100
    edited September 2017
    Options
    hi - sorry to nechro this post but if you are still doing this you need to make it that when another player grabs the ball in the scene (not you), they then have to make the ball the child of themselves so that the ball follows them on other peoples screens. I had a similar problem with cars.