2024-10-17 17:23:05 +03:00

108 lines
3.5 KiB
C#

using System;
using Mirror;
using UnityEngine;
namespace Mirror.Examples.Billiards
{
public class WhiteBall : NetworkBehaviour
{
public LineRenderer dragIndicator;
public Rigidbody rigidBody;
public float forceMultiplier = 2;
public float maxForce = 40;
// remember start position to reset to after entering a pocket
Vector3 startPosition;
// cast mouse position on screen to world position
bool MouseToWorld(out Vector3 position)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Plane plane = new Plane(Vector3.up, transform.position);
if (plane.Raycast(ray, out float distance))
{
position = ray.GetPoint(distance);
return true;
}
position = default;
return false;
}
void Awake()
{
startPosition = transform.position;
}
[ClientCallback]
void OnMouseDown()
{
// enable drag indicator
dragIndicator.SetPosition(0, transform.position);
dragIndicator.SetPosition(1, transform.position);
dragIndicator.gameObject.SetActive(true);
}
[ClientCallback]
void OnMouseDrag()
{
// cast mouse position to world
if (!MouseToWorld(out Vector3 current)) return;
// drag indicator
dragIndicator.SetPosition(0, transform.position);
dragIndicator.SetPosition(1, current);
}
// all players can apply force to the white ball.
// (this is not cheat safe)
[Command(requiresAuthority = false)]
void CmdApplyForce(Vector3 force)
{
// AddForce has different force modes, see this excellent diagram:
// https://www.reddit.com/r/Unity3D/comments/psukm1/know_the_difference_between_forcemodes_a_little/
// when applying a one-time force to the ball, we need 'Impulse'.
rigidBody.AddForce(force, ForceMode.Impulse);
}
[ClientCallback]
void OnMouseUp()
{
// cast mouse position to world
if (!MouseToWorld(out Vector3 current)) return;
// calculate delta from ball to mouse
// ball may have moved since we started dragging,
// so always use current ball position here.
Vector3 from = transform.position;
// debug drawing: only works if Gizmos are enabled!
Debug.DrawLine(from, current, Color.white, 2);
// calculate pending force delta
Vector3 delta = from - current;
Vector3 force = delta * forceMultiplier;
// there should be a maximum allowed force
force = Vector3.ClampMagnitude(force, maxForce);
// apply force to rigidbody.
// it will take a round trip to show the effect.
// the goal for prediction will be to show it immediately.
CmdApplyForce(force);
// disable drag indicator
dragIndicator.gameObject.SetActive(false);
}
// reset position when entering a pocket.
// there's only one trigger in the scene (the pocket).
[ServerCallback]
void OnTriggerEnter(Collider other)
{
rigidBody.position = startPosition;
rigidBody.Sleep(); // reset forces
GetComponent<NetworkRigidbodyUnreliable>().RpcTeleport(startPosition);
}
}
}