using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using Random = UnityEngine.Random; public class DiceView : MonoBehaviour, IBase { private Rigidbody rb; private bool rolling; [SerializeField] private DiceSide[] diceSides; [SerializeField] private float sideValueTime = 1.2f; [SerializeField] private Vector3 startPos = new Vector3(0, 20, 0); [SerializeField] private Button diceButton; [Header("Physics Randomness")] [SerializeField] private float baseSpinForce = 900f; [SerializeField] private float sideForce = 0.18f; [SerializeField] private float liftForce = 0.1f; private List probabilityValues = new List() { 3, 4, 5 }; private Quaternion startRotation; private Action onRollingComplete = null; private IRollBase rollBase = null; private bool hasNoActionOnRoll = false; private void Awake() { rb = GetComponent(); rb.useGravity = false; transform.localPosition = startPos; startRotation = transform.localRotation; } public void Roll(Action onComplete, bool isBot) { Debug.Log($"Start rolling: {rolling}"); if (!rolling) { Debug.Log($"isBot: {isBot}"); onRollingComplete = onComplete; StartCoroutine(RollRoutine()); } } private IEnumerator RollRoutine() { rolling = true; // MICRO DELAY → breaks physics sync between dice yield return new WaitForSeconds(Random.Range(0.01f, 0.06f)); rb.useGravity = true; // PER-DICE FORCE MULTIPLIER float spinMultiplier = Random.Range(0.8f, 1.25f); // RANDOM TORQUE rb.AddTorque( Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, ForceMode.Impulse ); // RANDOM SIDE FORCE Vector3 sideDir = new Vector3( Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f) ).normalized; rb.AddForce(sideDir * sideForce, ForceMode.Impulse); // SMALL UPWARD FORCE rb.AddForce(Vector3.up * liftForce, ForceMode.Impulse); yield return new WaitForSeconds(sideValueTime); int rolledVal = 0; if (hasNoActionOnRoll) { if (rollBase.SixRollCount == 0) { rollBase.UpdateMaxRollCount(probabilityValues[Random.Range(0, probabilityValues.Count)]); } rollBase.UpdateSixRollCount(); rolledVal = rollBase.SixRollCount == rollBase.MaxRollCount ? Ludo_3D_Constants.Max_Dice_Rolls : GetDiceValue(); } else { rolledVal = GetDiceValue(); } if (rolledVal == Ludo_3D_Constants.Max_Dice_Rolls) ResetRollData(); ResetDice(); Debug.Log($"Dice rolled: {rolledVal}"); onRollingComplete?.Invoke(rolledVal); } private int GetDiceValue() { return Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1); } public void ResetRollData() { if (rollBase != null) rollBase.ResetRollData(); } public void ResetDice() { rollBase = null; rb.useGravity = false; rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; transform.localPosition = startPos; rolling = false; } public void SetDiceButtonInteraction(bool status) { diceButton.interactable = status; } public void ResetOnSessionEnd() { ResetDice(); transform.localRotation = startRotation; onRollingComplete = null; } public void InitOnNoActionsAfterRoll(IRollBase rollBase, bool state) { hasNoActionOnRoll = state; if (!state) return; this.rollBase = rollBase; } }