This is my first post here and also my first game and attempt at learning C# scripting with Unity. I am loving it so far.
I’m making a 3D board game, and I have created the board and a die, and set up nodes for the player to move to given a set number of steps which is determined by rolling a die.
When I first roll the die, the player moves properly (Say, they roll a 5, and then can move 5 spaces.)
However, after the first roll, every other roll just makes the player continue to move the first number that was rolled, regardless of what the die lands on. (In this example 5 spaces.) I cannot figure out why the die’s value is not resetting. I will do my best to describe how I have the game setup so far.
Firstly, I have the movement controlled by a script called ‘SpaceController.cs’
The code for that is right here:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpaceController : MonoBehaviour
{
public Movement currentSpace; //The current space the player is on.
int spacePosition; //The space position.
public int steps; //The number of steps the player has to take on their turn.
bool isMoving; //Whether the player is currently moving or not.
public GameObject dice; //Referencing the die for later usage.
void Update()
{
Dice diceValue = dice.GetComponent<Dice>(); //Getting the Dice script from the die game object.
if(Input.GetKeyDown(KeyCode.W) && !isMoving) //If W is pressed and the player is not moving.
{
steps = diceValue.diceValue; //Set the steps to the value of the die.
if (spacePosition + steps < currentSpace.childSpaceList.Count) //If the current position plus the number of steps is less than the finish
{
StartCoroutine(Move()); //Move the player.
}
else
{
Debug.Log("You have won!"); //Tell the player they have won the game.
}
}
}
IEnumerator Move()
{
if(isMoving) //Checks if the player is already moving.
{
yield break; //Stops the coroutine.
}
isMoving = true; //Sets the player to be moving.
while(steps>0) //While the available steps is more than 0.
{
Vector3 nextSpace = currentSpace.childSpaceList[spacePosition + 1].position; //Sets the current position to be the next space.
while(MoveToNextSpace(nextSpace)){yield return null;} //Checks if the next space is not the finish.
yield return new WaitForSeconds(0.1f); //Wait for some time between moves.
steps--; //Subtract the used step from the available ones.
spacePosition++; //Add to the current space count.
}
isMoving = false; //Reset moving to be false.
steps = 0; //Manually set the steps to 0 if not done so by running out of available steps.
}
bool MoveToNextSpace(Vector3 goal) //Checks if the next space is the finish line or not.
{
return goal != (transform.position = Vector3.MoveTowards(transform.position, goal, 10f * Time.deltaTime)); //Allows the player to move.
}
}
I also have the die GameObject which has 6 sides, each of the sides has a sphere collider set as a trigger attached to it, to detect collisions with the floor of the box the die rolls inside of. When one side is down, the opposite side is up. Each sphere has the following ‘DiceSides.cs’ script attached to them, and the value of each side is set manually in the inspector.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiceSides : MonoBehaviour
{
bool onGround; //Is the side on the ground.
public int sideValue; //The value of the side, set manually in the inspector.
void OnTriggerStay(Collider col) //When continually colliding with a trigger.
{
if(col.tag == "RollBox") //If the trigger is tagged the RollBox.
{
onGround = true; //Set that the side is on the ground.
}
}
void onTriggerExit(Collider col) //When no longer colliding with a trigger.
{
if(col.tag == "RollBox") //If the trigger we are not colliding with is tagged the RollBox.
{
onGround = false; //Set that the side is not on the ground.
}
}
public bool OnGround() //A public Method to check if the side is on the ground.
{
return onGround; //Return whether the side is on the ground or not.
}
}
And then I have the actual die itself, which has the logic of rolling the die attached to it, which grabs the value of the side that landed on the ground. The following script ‘Dice.cs’ is attached to it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Dice : MonoBehaviour
{
Rigidbody rb; //Access the rigidbody of the die.
bool hasLanded; //Checks if the die has landed.
bool thrown; //Checks if the die has been thrown.
Vector3 initPosition; //Captures the initial position of the die.
public int diceValue; //The face value the die lands on.
public DiceSides[] diceSides; //The array of the sides of the die.
void Start()
{
rb = GetComponent<Rigidbody>(); //Initializing the rigidbody component.
initPosition = transform.position; //Sets the initial position to be the position the die is currently at.
rb.useGravity = false; //Disables the gravity of the die to begin with.
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space)) //If the Space bar is pressed.
{
Roll(); //Calls the Roll method.
}
if(rb.IsSleeping() && !hasLanded && thrown) //If the die's rigidbody is still and it has not landed but was thrown
{
hasLanded = true; //Set the die to has landed
rb.useGravity = false; //Disables gravity for the die while it is on the ground.
ValueCheck();
}
else if (rb.IsSleeping() && hasLanded && diceValue == 0) //If the die's rigidbody is still and has landed but the value is uncertain
{
RollAgain(); //Re-rolls the die.
}
else if (rb.IsSleeping() && hasLanded && diceValue != 0) //If the die's rigidbody is still and has landed but the value is certain
{
ValueCheck(); //Check the value of the die.
}
}
void Roll() //Roll the die.
{
if(!thrown && !hasLanded) //If the die has not been thrown or landed already
{
thrown = true; //Set the die to thrown.
rb.useGravity = true; //Enable the gravity of the die.
rb.AddTorque(Random.Range(0,1500),Random.Range(0,1500),Random.Range(0,1500)); //Adds a random force and spin to the die.
}
else if(thrown && hasLanded) //If the die has been thrown and has successfully landed.
{
Reset(); //Reset the die.
}
}
void Reset() //Reset the die.
{
diceValue = 0;
transform.position = initPosition; //Reset the position to the original position of the die.
thrown = false; //Reset the thrown value so the die is counted as not being thrown yet.
hasLanded = false; //Reset the landed value so the die is not counted as landed yet.
rb.useGravity = false; //Turn off the gravity until the next roll.
}
void RollAgain() //Re-roll the die.
{
Reset(); //Reset the die.
thrown = true; //Set the die to be thrown.
rb.useGravity = true; //Turn on gravity.
rb.AddTorque(Random.Range(0,1500),Random.Range(0,1500),Random.Range(0,1500)); //Add the random force and spin to the die.
}
void ValueCheck() //Check for the face value of the die.
{
diceValue = 0; //Set the die value to 0 until the die is certain of the face value.
foreach(DiceSides side in diceSides) //Run through the array of die sides.
{
if(side.OnGround()) //If the specified side is on the ground.
{
diceValue = side.sideValue; //Set the value to the opposite side that is on the ground.
}
}
}
}
So, basically, I cannot for the life of me think of why the value is not changing after the first roll. I have watched in the inspector on the die gameobject and the value shows the first rolled value, then when re-rolling it goes back to 0 as it should, then when it completes the next roll, it goes back to the first value that was rolled, regardless of what was actually rolled. I have spent at least 45 minutes scouring this code to try to find the problem and I just cannot think of it.
Any help would be greatly appreciated and if you need me to elaborate on anything, please just let me know.
Thank you for your time.