你如何在C#中获得Random的当前种子?
在我的游戏中,我将使用随机值来选择玩家从胸部获得的奖励。 问题是你可以快速保存并快速加载,这意味着他们可以继续重新加载以重新随机化,直到他们得到他们想要的东西。 有没有办法让我可以获取我的Random
对象的当前种子值,并在加载时可能返回到同一点,这样他们就不会滥用随机化?
获取种子时不确定,但您可以保存您为Random
对象赋予的值。 请记住,有两个构造函数。 第二个是Random(Int32)
,所以如果你自己设置种子(一个足够简单的值是System.DateTime.Now.Millisecond
),你可以在将它传递给构造函数之前将其存储在某处。 如果您尚未阅读,请查看MSDN文档, url为http://msdn.microsoft.com/en-us/library/system.random.aspx 。
这是不可能的。
相反,您可以使用二进制序列化序列化Random
实例。
Random
是[Serializable]
,种子和内部状态将持续存在。
但请注意,保存随机种子可让您的玩家预测未来,如果您允许在战斗中保存,这非常有用。
另请注意,用户仍然可以保存,打开胸部,加载,执行生成随机数的动作,然后从胸部获取不同的项目。
这只与切线有关,但是如果有人想知道为什么Random
没有名为Seed
的属性或者叫做GetSeed()
的方法,我愿意下注这可能是出于安全问题:你想要吗?将“随机”数字生成器的内部工作暴露给外界? 绝对不! 否则,一些客户端代码可能会四处寻找,直到它获得您正在使用的值,然后使用它们执行令人讨厌和无意义的事情。
实际上, 没有存储 Seed
因为它与初始化后的算法无关。 它的一个衍生物mj
存储在SeedArray
,你可以检查使用Reflection来比较两个Random
实例:
int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed); mj = MSEED - subtraction; SeedArray[55]=mj;
所以你要做的就是检查SeedArray
的最后一个元素(索引55)。 这是Seed
唯一使用的地方。
[从已删除的问题中移出答案如何确定两个Random实例是否具有相同的种子? ]
我可能只是按照MSDN使用它: http : //msdn.microsoft.com/en-us/library/ctssatww.aspx
Random(seed)
种子是一些价值我从存储装载。
您可以将随机奖励计算为以下哈希函数:
- 开始新游戏时分配的种子,并保存在已保存的游戏中; 和
- 胸部的一些恒定属性,在所有游戏中都是不变的(例如,固定的ID,或者如果它从未移动的话,它的位置)。
这种方法的优点是,无论您保存和重放多少次,给定的胸部总会在给定的游戏中产生相同的奖励,即使在不同的顺序打开胸部,或者在不同的顺序中触发其他“随机”事件。 此外,每个胸部的奖励都独立于其他胸部的奖励,只要哈希中使用的胸部属性是独立的。
在以下示例中, GetRewardId
生成奖励ID作为与胸部的x坐标异或的游戏种子的散列。 它使用Random
来执行散列,使用散列输入作为Random
对象的种子,并将第一个随机生成的数字作为输出。
private static int GetRewardId(int seed, float coord, int numRewards) { int tempSeed = BitConverter.ToInt32(BitConverter.GetBytes(coord), 0) ^ seed; return new Random(tempSeed).Next(numRewards); } int seed = new Random().Next(); int numDifferentRewards = 5; float xCoordinate = chest.Position.X; int rewardId = GetRewardId(seed, xCoordinate, numDifferentRewards);
如果您的许多箱子可能在sace中对齐,您可能想要选择不同的属性,或使用其他尺寸,也可以使用y和/或z坐标进行异或。
不幸的是,在Microsoft的参考实现中,甚至没有保存no arg ctor的种子值,更不用说暴露访问了: http : //referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca
但是,您也可以在参考实现中看到,您可以传入的值(可能应该 – 我知道我这样做),就像它们一样,是: Environment.TickCount
所以将它保存到变量中,然后将该变量传递给带有arg的ctor,你现在知道了种子。 事实并非如此,但无论您的意图是什么,这都应该足够了。
我建议你生成一个随机数,并将其用作真实随机数生成器的种子数。 通过此方法,您有一个实际上是随机数的种子编号,您可以保存种子编号以供进一步使用。