【问题标题】:Weird Random Number Bug In .Net.Net 中的奇怪随机数错误
【发布时间】:2011-05-05 00:17:42
【问题描述】:

我确定我做错了什么;但这已经让我发疯了一段时间。

我制作了一个小型 Silverlight 游戏(一个古老的 Galaxian 克隆)。当游戏开始时,大约 90% 的时间里,一堆星星随机放置在游戏区域中。有三种类型的恒星 - 较大的恒星速度更快,较小的恒星移动速度较慢。

看起来像这样:

~10% 的时间所有星星都出现在“带状”中

我认为值得一提的是,即使它们处于窄带中;他们并不都处于相同的确切位置。所以它就像在生成一个随机数——只是一个很小的数。

要重现该错误,我只需在浏览器中按“f5”即可。几乎所有时间,它都按预期工作。很少,我得到乐队。再次按“f5”将解决此问题。

无需发布巨大的代码墙;我认为这是最相关的代码。它出现在我所有的星星都继承自的 Base 类中。它会在每颗星创建时调用一次。

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

我看不出有什么问题。 GetRandom() 返回一个单例 Random 类,我依赖于 GameCanvas.Height 和 GameCanvas.Width 是否有效 - 但同样, .Width 似乎完全按预期工作。

有人对此行为有潜在的解释吗?生成随机数时有什么需要注意的地方吗?每次我单步执行代码时,一切都很好,游戏按预期运行。

如果有帮助,我可以发布游戏链接。
(http://robdude.weebly.com/cci.html)

编辑 #1:
这是来自 GetRandom() 的代码

Protected Shared Function GetRandom() As Random
    If _random Is Nothing Then _random = New Random()

    Return _random
End Function

编辑#2: 我非常感谢大家对此的想法/建议。

【问题讨论】:

  • 您是否每次都从GetRandom 返回一个新的Random 实例?
  • 为传递给 GetRandom.Next 函数的值添加一些日志记录。特别是 StarEdge、Width 等,以便您可以重现它。同时存储结果
  • 显示您的GetRandom 课程。此外,虽然您在椭圆上设置了HeightWidth 属性,但您在哪里设置它的位置?你需要在某处设置myElipse.Location吗?
  • 就像 Adrian 提到的,保持使用相同的 Random 实例而不是每次都使用新实例很重要。否则,您将继续获得相同的结果。但我不认为这会是问题,但你有时只会得到它。但还是值得一提的
  • @RobP - 这里涉及很多线程吗? Random 不是线程安全的;例如,你对Parallel 有什么帮助吗?

标签: .net vb.net silverlight random


【解决方案1】:

我想让这个答案尽可能通用,希望对其他人有所帮助。我在这里合并了其他答案(以及对我的问题的实际修复),这可能对遇到随机生成数字的奇怪行为的人有所帮助。

使用不同的随机实例

Random 类的实例具有关联的种子。一般来说,您希望重用 Random 的相同实例或确保种子不同。如果您使用相同的种子创建了 2 个不同的 Random 实例,则第一个 .Next 将返回相同的结果。

线程安全

随机不是线程安全的。

条件断点

我有时会忘记这是一个选项。在某些情况下,“单步执行代码”的行为会隐藏运行时出现的错误。设置条件断点是检查这一点的好方法。在我的例子中 'CType(GameCanvas.Height, Integer) 是我使用的条件。

日志记录

按照同样的思路,对于这样的错误,日志记录可能是无价的。我不知道为什么我在问这个问题之前没有想到它。

最后,由于我不明白的原因,GameCanvas.Height 的值很少设置不正确。我的理论是,当我创建/定位/调整 GameCanvas 大小时,我在其他地方做错了或不恰当的事情。

逐行逐行查看代码似乎无法解决问题。在我的情况下,比赛场地的大小是固定的;所以不是从 GameCanvas 控件中检查大小 - 我现在从我的 Settings 对象中拉出它。

感谢大家的团队调试。非常感谢。

【讨论】:

    【解决方案2】:

    如果 GetRandom() 每次都返回一个新的 Random 实例,那么这就解释了错误。你应该只有 Random 的实例。

    如果它返回一个新实例,那么新实例很有可能在重复调用时获得相同的种子值。如果种子相同,则两个不同的实例将返回相同的“随机”值。

    【讨论】:

    • 我相信它每次都返回相同的实例。我添加了 GetRandom 的代码
    • 用相同的种子值播种 Random 的两个不同实例将产生完全相同的序列,而不是像这样带状排列的序列。
    猜你喜欢
    • 2010-12-26
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多