0
\$\begingroup\$

I'm making a billiard game and I wanna implement multiplayer in it. Since updating the movement in every frame is inefficient and laggy, I thought I could remake the events in game happen in all clients but for some reason they differ from one another.

The direction that the ball launches is correct but it starts to differ for different users when it collides with other balls(if it collides only with the wall it's fine). Technically this shouldn't happen IMO.

This is the code I use to add force to the player ball:

I use this to launch the player ball

photonView.RPC("FireBall", PhotonTargets.All, storedDirection, power);

This is the function that adds the force to the player ball.

[PunRPC]
    public void FireBall(Vector3 stordDir , float poww)
    {
        rigidbody.AddForce(stordDir.normalized * poww, ForceMode.Impulse);
    }

I use this function to get the desired direction of the player.

public void UpdateStickPosition()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
        { 
            if (Input.GetKeyDown(KeyCode.Mouse0)  
            {
                storedDirection = hit.point - transform.position;
            }
        }

    }

I appreciate all help given, don't hesitate to ask me any questions.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Unity's physics engine, NVIDIA's PhysX, is not deterministic. You're not going to get the same physics simulation twice even on the same machine because the physics engine was just not made to work that way (for good reasons)[1].

The solution? You'll need to update the positions and other physics attributes periodically on the clients from whatever client/server has authority. This wouldn't be done every frame but at some coarser time step.

In Photon you need to take these steps to sync your data.

  • Implement OnPhotonSerializeView() to send position, rotation, velocity, angular velocity, etc.
  • Modify your PhotonView to use an observer option of Unreliable on Change (as is suggested by Photon's documentation for frequent updates, and probably the best for your use case).
  • When the stream is deserialized on the client, sync the values as necessary by linear interpolating the current client values with the new values.

If you're using Unity's UNET (needs Unity 5), then it's as simple as just adding a NetworkTransform to the objects that you want to sync and changing the sync mode and sync timestep for your particular use case.


[1] As for why it isn't deterministic, is refer to the PhysX knowledge base...

The first problem here is that the PhysX SDK is not deterministic.Especially when running different hardware setups, bus latencies can vary between runs, or on different machines. Even without hardware in the machine, we do not guarantee any type of determinism.

...and to this post on Unity's forums:

In order for the physics to be completely deterministic then absolutely everything has to happen in the same manor, including the order of collision detection and resolution etc which will require everything to be added or arranged in memory in the same order. As far as I know, Unity's wrapper around the PhysX system makes it impossible for you to garauntee this.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .