Random.Range is causing me problems

Well, it’s connected to using Random.Range(). I’ll try to explain…

I wanted to add a bit of interest to my extended text game by having the player get into a fight with the guards here and there. I thought I would use Random.Range() to generate a value and use it to decide the outcome of the fight.

Here’s an example, you’ve just come down the steps and run into a guard.

void steps_1()
{
        MainText.text = "The guard in the hallway looks up and sees you, \"Oi! You!\" he shouts "+
                        "as he draws his tazer.\n\n"+
			"Press T to draw your Tazer against the guard.\n";
					
	if( Input.GetKeyDown (KeyCode.T) )  myState = States.steps_2;
						}
}

void steps_2( )
{
	int myFightResult = Random.Range( 0, 10 ); 
	print( "myFightResult: " +myFightResult);
	//odds are stacked slightly in your favour
	if( myFightResult <= 6 ) myState = States.steps_3;
	else if( myFightResult >= 7 ) myState = States.steps_4;
	}
	
void steps_3()    //you won the tazer fight
{
	MainText.text = "You zap the guard with your tazer. He falls to the "+
			"ground and lies there twitching and grunting. "+
			"You drag him into a corner and leave him.\n\n"+
			"Press H to return to the Hallway";
	if( Input.GetKeyDown (KeyCode.H) )	myState = States.hallway_0; 
}
	
	
void steps_4()    //you lost the tazer fight
{
	MainText.text = "The guard is a quicker draw than you and shoots you with his tazer. "+
			 "As you fall to the floor, twitching and dribbling, you see the other "+
			 "guards arriving.\n\n"+
			 "Press C to Continue";
	if( Input.GetKeyDown (KeyCode.C) )	myState = States.cell_6;
}

Sometimes it works as intended and sometimes not. It seems to me that the steps_2() method is run several times before moving on to the next method.

In the screenshot you can see that steps_2() has run four times. On the first three times, it generates a value less than 6 indicating that you win the fight, but on the fourth it generates 7, meaning that you lost. In the last two lines of the console it looks like steps_3() AND steps_4() are both executing.

method_runs_four_times

If you press C to continue, you go back to the cell as expected, but the console shows that steps_3() is still being called over and over. Sooner or later this trips the game up because you press a key (in this case the H key) expecting something to happen, but it’s a race between steps_3 and whichever other method you think you’ve called, to respond the keypress.

At the time of writing, I’ve been banging my head on the desk about this, between other things, for nearly two weeks.

I’ve tried rewriting my code in as many ways as I can think of, including:

  • setting up a global variable for fightResult so that I can generate its value before leaving the steps_1() method, so that all steps_2() has to do is examine the result and decide which method to call and call it. But before long I come up against the same problem.

  • moving the three methods I have shown above into one longer method, I get a problem where Random.Range is being called with every update and it causes the text messages to change faster than you can read them as Random.Range generates different results.

I thought about making each option in the game have a different letter to try to remove the race condition, but that doesn’t sit well with me because it’s just trying to cover up the problem instead of fixing it and sooner or later the menu choices are going to look pretty silly, for example: “Press X to Open such and such.”

I’ve also looked at the man pages for Execution Order of Events, Time, the Time Manager and Time and Framerate Management because I thought one of the settings there might solve my problem, but so far I cannot find it.

I thought that update() was run once per frame, so I don’t understand why steps_2 seems to be executed multiple times.

Has anyone else come across this, know a better way to do it or have any suggestions as to what I might try next?

1 Like

Hi Sandry,

could you post your whole script here maybe? I copied and pasted your example and made the necessary adjustments to my script and it worked as expected for me, so your problem is probably elsewhere in your script.

3 Likes

Another possibility is that you might have more than one script running this code, but as Sebastian said, the whole script would be very useful since don’t seems to be a problem in the code you shared

2 Likes

Thank you Sebastian and Johnny for getting back to me.

I had been wondering whether it would be necessary to post the whole script. By this stage my code had become quite long and repetitive - not my proudest programming moment, but probably par for the course as a Unity and C# newbie - and I was reluctant to ask anyone to wade through it looking for the problem.

But, it is solved and this is due in no small part to your having responded.

After you guys suggested I post the whole script, I decided to try to strip it back to the barest minimum that would reproduce the problem so that there would be less for you to have to read and maybe I’d spot the root of the problem myself in the process. In fact, rather than strip it back bit by bit, I started with a new project and added only the code that was needed for the fight scene. Much like the code example in my original post, there was no problem. Little by little I added in the code for the other rooms and sections, playing each time and watching out for the problem to occur. The more code I added back in, the more apparent it became that the problem wasn’t going to be reproduced.

As I was doing this, the comment that Johnny had made about more than one script running the code was nagging away at me in the back of my mind. There is definitely only one script in the entire project, it wasn’t that I’d left an older version in my assets folder or something like that and they were both running at once. But nevertheless, this idea stuck in my mind.

Finally, it struck me. The difference between my original version (with the problem), and the rebuilt version (without it), was that in the original I had some extra text boxes that I was using to show the player’s health and the number of enemies remaining. When I first set up the additional text boxes, I was getting errors. I don’t remember the exact error, but it amounted to the new boxes not being found. It was probably “Object reference not set to an instance of an object”, like Ben shows in Section 3, Lecture 30 at about 10:23.

I remember dragging from the names of the text elements on the left, to the slots beneath the script component for MainText in the Inspector on the right so that it looked like this…

But, for some reason I still got the compilation errors. So, I added a script component for each of the text boxes and connected them all up so that each of the four text boxes had the same four slots. Everything started to work as I wanted (or so I thought) and I carried on working on the game.

Anyway, when I realised that my four sets of script to text box components/attachments kinda matched my four results from Random.Range() , the penny finally dropped. I removed the extra components and the problems I described in the original post went away. As you probably already guessed, Random.Range() was never at fault; Sandry, the Unity Newbie was ;c)

Thanks once again for replying, you provided the impetus to get me thinking clearly and find the solution.

3 Likes

I’m glad that you spotted the problem and fixed it :smiley:
Awesome debugging process breakdown btw, I wish more people done that :smiley: it really helps understanding how to approach debugging.

2 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms