WhiteBall.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using Mirror;
  3. using UnityEngine;
  4. namespace Mirror.Examples.Billiards
  5. {
  6. public class WhiteBall : NetworkBehaviour
  7. {
  8. public LineRenderer dragIndicator;
  9. public Rigidbody rigidBody;
  10. public float forceMultiplier = 2;
  11. public float maxForce = 40;
  12. // remember start position to reset to after entering a pocket
  13. Vector3 startPosition;
  14. // cast mouse position on screen to world position
  15. bool MouseToWorld(out Vector3 position)
  16. {
  17. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  18. Plane plane = new Plane(Vector3.up, transform.position);
  19. if (plane.Raycast(ray, out float distance))
  20. {
  21. position = ray.GetPoint(distance);
  22. return true;
  23. }
  24. position = default;
  25. return false;
  26. }
  27. void Awake()
  28. {
  29. startPosition = transform.position;
  30. }
  31. [ClientCallback]
  32. void OnMouseDown()
  33. {
  34. // enable drag indicator
  35. dragIndicator.SetPosition(0, transform.position);
  36. dragIndicator.SetPosition(1, transform.position);
  37. dragIndicator.gameObject.SetActive(true);
  38. }
  39. [ClientCallback]
  40. void OnMouseDrag()
  41. {
  42. // cast mouse position to world
  43. if (!MouseToWorld(out Vector3 current)) return;
  44. // drag indicator
  45. dragIndicator.SetPosition(0, transform.position);
  46. dragIndicator.SetPosition(1, current);
  47. }
  48. // all players can apply force to the white ball.
  49. // (this is not cheat safe)
  50. [Command(requiresAuthority = false)]
  51. void CmdApplyForce(Vector3 force)
  52. {
  53. // AddForce has different force modes, see this excellent diagram:
  54. // https://www.reddit.com/r/Unity3D/comments/psukm1/know_the_difference_between_forcemodes_a_little/
  55. // when applying a one-time force to the ball, we need 'Impulse'.
  56. rigidBody.AddForce(force, ForceMode.Impulse);
  57. }
  58. [ClientCallback]
  59. void OnMouseUp()
  60. {
  61. // cast mouse position to world
  62. if (!MouseToWorld(out Vector3 current)) return;
  63. // calculate delta from ball to mouse
  64. // ball may have moved since we started dragging,
  65. // so always use current ball position here.
  66. Vector3 from = transform.position;
  67. // debug drawing: only works if Gizmos are enabled!
  68. Debug.DrawLine(from, current, Color.white, 2);
  69. // calculate pending force delta
  70. Vector3 delta = from - current;
  71. Vector3 force = delta * forceMultiplier;
  72. // there should be a maximum allowed force
  73. force = Vector3.ClampMagnitude(force, maxForce);
  74. // apply force to rigidbody.
  75. // it will take a round trip to show the effect.
  76. // the goal for prediction will be to show it immediately.
  77. CmdApplyForce(force);
  78. // disable drag indicator
  79. dragIndicator.gameObject.SetActive(false);
  80. }
  81. // reset position when entering a pocket.
  82. // there's only one trigger in the scene (the pocket).
  83. [ServerCallback]
  84. void OnTriggerEnter(Collider other)
  85. {
  86. rigidBody.position = startPosition;
  87. rigidBody.Sleep(); // reset forces
  88. GetComponent<NetworkRigidbodyUnreliable>().RpcTeleport(startPosition);
  89. }
  90. }
  91. }