so I'm working on a dice game, at firs I thought it'll be easy but I just found 1 major "bug". So this is my main script with the problem:
using System.Collections.Generic;
using UnityEngine;
public class BoardController : MonoBehaviour
{
#region VAR
[SerializeField] private List<Transform> diceRestPositions = new List<Transform>();
[SerializeField] private List<Transform> dices = new List<Transform>();
[SerializeField] private Transform throwPosition;
[SerializeField] private float throwRange;
#endregion
#region MONO
private void Update()
{
LaunchDices();
if(Input.GetKeyDown(KeyCode.Alpha2))
{
ResetDicesPos();
}
}
private void Start()
{
}
#endregion
#region CUSTOM
private Vector3 GetRandomThrowPos()
{
return new Vector3(Random.Range(throwPosition.position.x- throwRange, throwPosition.position.x + throwRange), 1.2f, Random.Range(throwPosition.position.z - throwRange, throwPosition.position.z + throwRange));
}
private void ResetDicesPos()
{
StopDiceMovement();
for (int i = 0; i < diceRestPositions.Count; i++)
{
dices[i].position = diceRestPositions[i].localPosition;
dices[i].rotation = diceRestPositions[i].localRotation;
}
}
private void StopDiceMovement()
{
foreach(Transform dice in dices)
{
if(dice.TryGetComponent<Rigidbody>(out Rigidbody rb))
{
rb.velocity = Vector3.zero;
dice.rotation = Quaternion.identity;
rb.angularVelocity = Vector3.zero;
}
}
}
private void LaunchDices()
{
if(Input.GetKeyDown(KeyCode.Alpha1))
{
StopDiceMovement();
foreach (Transform dice in dices)
{
dice.position = GetRandomThrowPos();
if(dice.TryGetComponent<DiceAddForce>(out DiceAddForce comp))
{
comp.ApplyRandomForce();
}
}
}
}
#endregion
}
So just to explain "diceRestPosition" is a list where dices are resting before getting launched. "dices" is just a list with dice Transform. "throwPosition" is just the middle point of throwingArea and "throwRange" defines the range.
So when i press "Alpha1" 5 dices are launching from a random position with rigidbody.AddForce and rigidbody.AddTorque so they are spinning. And when I press "alpha2" every dice is returning to its position defined in "diceRestPosition". But sometimes when I play with theses buttons some errors accure like: -> when I'm double pressing 1 sometimes they just doubleJump like if so StopDiceMovement() isn't working -> sometimes dices are launching from "diceRestPosition" and not random pos -> and the last one is when I press 2 and dices are still moving they just stop but don't return to "diceRestPosition"
I'm quite new in programming and not really sure what to do but first i thought it was ressource error like foreach is too heavy and is skipped? But i have only 5 dices and I don't think it's causing it. I aslo saw that when dices are moving it's more probable to accure when they are still moving/rolling or when stopped are tilted. If you read this I'm greatefull for your attention and ask you to help me resolve this strange error :)
I'm quite new in programming and not really sure what to do but first i thought it was ressource error like foreach is too heavy and is skipped?
No code will ever simply be skipped just because it is heavy. It will maybe lower the frame-rate or in extreme cases freeze your application - or if your device runs out of memory yes actually throw an exception - but it will never simply be skipped ;)
If you want to be sure whether things are being executed Debug your code!
One thing I can tell is: You are using a weird mix of going through Rigidbody
and Transform
of your dice.
As a rule of thumb: As soon as any physics is involved you want to go only through Rigidbody
!
For instance instead of assigning
dice.position = wx;
dice.rotation = yz;
you will rather want to go through Rigidbody.position
and Rigidbody.rotation
.
Also some side notes
It seems a bit odd that you also mix world position
and localPosition
in
dices[i].position = diceRestPositions[i].localPosition;
dices[i].rotation = diceRestPositions[i].localRotation;
you will probably rather want to stick to either use the local space or the global space for both.
You will also not want to repeatedly using GetComponent
all the time so rather store them in a List<Rigidbody>
right away.
OR in fact even better than having two independent lists and just hoping they will have the same size always I would even have a custom wrapper type like e.g.
[Serializable]
private class DiceSetup
{
public Rigidbody Dice;
public Transform RestPosition;
}
[SerializeField] private List<DiceSetup> dices = new();
and then stick to a foreach
everywhere