【发布时间】:2011-05-13 00:31:55
【问题描述】:
在我的游戏中,我将使用随机值来选择玩家从箱子中获得的奖励。问题是你可以快速保存和快速加载,这意味着他们可以继续重新加载以重新随机化,直到他们得到他们想要的。有什么方法可以让我获得Random 对象的当前种子值,并在它们加载时返回到同一点,这样它们就不会滥用随机化?
【问题讨论】:
在我的游戏中,我将使用随机值来选择玩家从箱子中获得的奖励。问题是你可以快速保存和快速加载,这意味着他们可以继续重新加载以重新随机化,直到他们得到他们想要的。有什么方法可以让我获得Random 对象的当前种子值,并在它们加载时返回到同一点,这样它们就不会滥用随机化?
【问题讨论】:
不确定获取种子,但您可以保存您给Random 对象的值。请记住,有两个构造函数。第二个是Random(Int32),所以如果你自己设置种子(一个足够简单的值是Environment.TickCount),你可以在将它传递给构造函数之前将该值存储在某个地方。如果您还没有阅读它,请查看位于https://docs.microsoft.com/en-us/dotnet/api/system.random 的 MSDN 文档。
【讨论】:
public Random() : this(Environment.TickCount) { } 所以您所要做的就是将Environment.TickCount 存储在类字段中并将其提供给构造函数。 你去,你已经保存了种子。 :)
System.DateTime.Now.Millisecond 仅从 0 变为 1000,这不是很好。更好地使用Environemt.TickCount(正如@Shakaron 指出的那样)(每 ± 50 天滚动一次,精度为 15 毫秒)
这是不可能的。
相反,您可以使用二进制序列化来序列化 Random 实例。Random 是 [Serializable],种子和内部状态将保持不变。
但是请注意,保存随机种子可以让您的玩家预测未来,如果您允许在战斗中保存,这将非常有用。
另外请注意,用户仍然可以保存、打开宝箱、加载、执行生成随机数的操作,然后从宝箱中获取不同的物品。
【讨论】:
This is not possible. 这正是我要寻找的。span>
您可以将随机奖励计算为以下哈希函数:
此方法的优点是,无论您保存和重玩多少次,即使箱子以不同的顺序打开或触发了其他“随机”事件,给定的箱子在给定的游戏中总是会产生相同的奖励以不同的顺序。此外,每个箱子的奖励与其他箱子的奖励无关,只要在哈希中使用的箱子的属性是独立的。
在以下示例中,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 坐标进行异或来选择不同的属性或使用其他尺寸。
【讨论】:
确实,Seedisn't stored 与初始化后的算法无关。它的派生词之一 mj 存储在 SeedArray 中,但您可以检查使用反射来比较两个 Random 实例:
int subtraction = (Seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(Seed);
mj = MSEED - subtraction;
SeedArray[55]=mj;
所以您所要做的就是检查SeedArray 中的最后一个元素(索引55)。这是唯一使用Seed 的地方。
[已删除问题How to determine if two Random instances have the same seed?的移动答案]
【讨论】:
SeedArray 似乎更好,以确定它们将产生相同的序列,而不仅仅是最后一项。因为这个数组在Next 调用期间被修改(包括最后一个元素),所以最后一个元素可能相同,但其余元素不同。
inext。 SeedArray + inext 似乎完全确定了输出,因此它们在两个 Random 实例中相等应该证明它们将产生相同的输出。
不幸的是,在 Microsoft 的参考实现中,甚至没有保存 no arg ctor 的种子值,更不用说公开访问了: http://referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca
但是,正如您在参考实现中看到的那样,您可以传入的值(可能应该 -- 我知道我知道)是:Environment.TickCount
所以将它保存到一个变量中,然后将该变量传递给接受 arg 的 ctor,您现在就知道了种子。不是事后,但这应该足以满足您的意图。
【讨论】:
我建议您生成一个随机数并将其用作真实随机数生成器的种子数。通过这种方法,您有一个实际上是随机数的种子编号,您可以保存您的种子编号以供进一步使用。
【讨论】:
这仅与切线相关,但如果有人想知道为什么 Random 没有名为 Seed 的属性或名为 GetSeed() 的方法,我愿意打赌这可能是由于安全问题:您想将“随机”数字生成器的内部工作原理暴露给外界吗?绝对不!否则,一些客户端代码可能会四处乱窜,直到它获得您正在使用的值,然后对它们进行令人讨厌和意想不到的事情。
【讨论】:
System.Security.Cryptography-namespace 中找到的内容混淆了。
我可能只是按照 MSDN 使用这个:http://msdn.microsoft.com/en-us/library/ctssatww.aspx
Random(seed)
其中种子是我从存储中加载的一些值。
【讨论】: