具体详细参考书:游戏编程精粹1
为了在一个游戏世界中给出无限空间的幻觉,我们需要满足两个分解条件。
宏无限(macro-infinite)和微无限(micro-infinite)
宏无限涉及到问题的空间规模,或者说离散的实体数目。
微无限表明每一个对象所支持的细节级别。
本文根据书中内容使用同一种重要的技术同时满足这两个条件。
宏无限:可以针对特定的游戏中的区域来确定某一个给定的特性。
书中用恒星举例,在一个区域随机生成种子,得到一个可重复的数字序列。
程序语言自带的随机数API,给定同一个种子就能生成同一个数字序列。
//自定义简单的伪随机:限制()生成的最大值为ulong的最大值),根据需要自行调整
public class PseudoRandomizer
{
private ulong ulGen1;
private ulong ulGen2;
private ulong ulSeed;
private ulong ulMax;
public PseudoRandomizer(ulong ulGen1, ulong ulSeed, ulong ulMax)
{
this.ulGen1 = ulGen1;
this.ulGen2 = ulGen1 * 2;
this.ulSeed = ulSeed;
this.ulMax = ulMax;
}
public ulong Random()
{
ulong ulNewSeed = (ulGen1 * ulSeed) + ulGen2;
ulNewSeed = ulNewSeed % ulMax;
ulSeed = ulNewSeed;
return ulSeed;
}
}
总结:
给定一个输入和一个种子,再加上一个最大值,我们可以得到一个确定的数字序列。
可以利用这个生成无限恒星的坐标,实时生成游戏世界,而不用存储大量的关卡数据。
微无限分解:如何使用伪随机数来处理游戏对象的特征和细节。
本质上来讲,微无限分解对应于用户在某一点进行放大已查看那个地方有什么东西。
举个现在的例子,每个恒星被零个或多个行星环绕运行,这些行星轨道距这个恒星有一个确定的距离。为了确定这个距离,我们给恒星类添加一个属性,该属性给出了行星的数目。
public class Star
{
private int x, y;
private int planetNum;
public int PlanetNum
{
get { return planetNum; }
set
{
//用恒星的坐标初始化随机种子
System.Random rand = new System.Random(x + x * y);
//给定一个范围,得到一个行星数量
planetNum = rand.Next(0, 100);
}
}
}
说明:种子数是源自一个恒星的唯一值,基于给定的恒星对象的坐标x,y来决定的位置。这样可以减少在循环中有两个同样的恒星对象的可能性。
使用类似的技术来为给定的行星产生距离值。重点是用来决定对象特征的种子。
每一个可能行星的种子应该是唯一的,我们必须结合其所属的恒星与此行星的位置来得到它。
public class Planet
{
private int distanceFromStar;
public void SetDistance(int planetNum, int starX, int starY)
{
//初始化随机种子:根据特定的属性
System.Random rand = new System.Random(planetNum + (starX + starX * starY));
//设定范围
distanceFromStar = rand.Next(0, 1000);
}
}
给更多的特性,生成更多的属性。
结论:我们已经看到了如何使用宏无限和微无限分解技术、通过伪随机数序列进行繁殖,以及在一个唯一对象的基准上进行播种。这些技术使我们能够在一个资源有限的环境约束下创造近乎无限的游戏世界,并且在运行时生成。
成功运用可预测随机数的关键就在于如何能正确地在对象属性与游戏状态上同时使用好种子数。