I'm sure I'm doing something wrong; but this has been driving me crazy for a while now.
I've made a small Silverlight game (an old Galaxian clone). When the game starts ~90% of the time, a bunch of stars are randomly positioned in the game area. There are three types of stars - bigger stars more faster, smaller stars move slower.
It looks like this:
~10% of the time all of the stars appear in 'bands'
I think it's worth mentioning that even though they are in narrow bands; they aren't all in the same exact position. So it's like it is still generating a random number - just a tiny one.
To reproduce the error, I simply hit 'f5' in the browser. Nearly all the time, it works as expected. Rarely, I get the bands. Hitting 'f5' again will fix the issue.
Without posting a giant wall of code; I think this is the most relevant code. It appears in the Base class that all of my stars inherit from. It's called once, when each star is created.
Protected Sub SetInitialPosition()
myElipse.Height = GetStarSize()
myElipse.Width = GetStarSize()
_location.X = GetRandom.Next(-1 * Settings.StarEdge, CType(GameCanvas.Width, Integer) + Settings.StarEdge)
_location.Y = GetRandom.Next(0, CType(GameCanvas.Height, Integer))
myElipse.Fill = New SolidColorBrush(GetStarColor)
End Sub
I don't see anything wrong. GetRandom() returns a singleton Random class, and I'm depending on the GameCanvas.Height and GameCanvas.Width being valid - but again, the .Width appears to work exactly as expected.
Does anyone have a potential explanation for this behavior? Are there any gotchas to watch out for when generating random numbers? Every time I step through the code, everything is fine and the game works as expected.
If it would help I can post a link to the game.
(http://robdude.weebly.com/cci.html)
EDIT #1:
Here is the code from GetRandom()
Protected Shared Function GetRandom() As Random
If _random Is Nothing Then _random = New Random()
Return _random
End Function
EDIT #2: I really appreciate everyones thoughts/advice on this.
I wanted to make this answer as generic as possible, in the hopes that it might be helpful to someone else. I've consolidated other answers here (along with the actual fix for my problem) that might be helpful for someone experiencing weird behavior with randomly generated numbers.
Using Different Instances Of Random
An instance of the Random class has an associated seed. Generally speaking, you want to reuse the same instance of Random or ensure that the seeds are different. If you have 2 different Random instances created with the same seed, the first .Next will return the same result.
Thread-Safety
Random is not thread-safe.
Conditional Breakpoint
I sometimes forget that this is an option. In some cases, the act of 'stepping through code' will hide bugs that appear when you run-though. Setting a conditional break-point is a good way to check for this. In my case 'CType(GameCanvas.Height, Integer) < 750' was the condition I used.
Logging
Along those same lines, logging can be invaluable for a bug like this. I don't know why I didn't think of it before asking the question.
In the end, for reasons I don't understand, rarely, the value of GameCanvas.Height
was not set correctly. My theory is that I'm doing something else incorrectly or inappropriately somewhere else when I create/position/size the GameCanvas.
Stepping through the code, line-by-line, seemed to make it impossible to get to the problem. In my situation, the size of the playing field is fixed; so instead of inspecting the size from the GameCanvas control - I'm now pulling it from my Settings object.
Thanks for the team-debug everyone. It was very much appreciated.
If GetRandom() returns a new instance of Random every time, then this explains the fault. You should have only instance of Random.
If it returns a new instance, then there is good chance that the new instances get the same seed value on repeated calls. If the seeds are the same then two different instances will return the same "random" values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With