首先剧透一下,Minecraft生成地形的主要算法就是噪声函数,Notch本人也早就回答过了。但是我一直没有仔细研究MC生成世界的整个过程,最近有时间就好好研究一下
使用的MC版本是1.8.9,反编译、反混淆用Forge
本篇内容从玩家点击“创建世界”开始,到具体的生成区块前为止
Minecraft中的世界生成
世界设置
首先从创建世界的GUI开始看,类名net.minecraft.client.gui.GuiCreateWorld
,以下是点击按钮的代码
/**
* Called by the controls from the buttonList when activated. (Mouse pressed for buttons)
*/
protected void actionPerformed(GuiButton button) throws IOException
{
// ...
else if (button.id == 0) // 判断点击的是不是“创建新的世界”按钮
{
this.mc.displayGuiScreen((GuiScreen)null);
if (this.field_146345_x) // 已经点击了这个按钮,不再重复以下代码
{
return;
}
this.field_146345_x = true;
// 这个i就是随机数种子,初始化为随机数
long i = (new Random()).nextLong();
// s是玩家输入的种子
String s = this.field_146335_h.getText();
// 如果玩家输入了种子,使用玩家输入的种子
if (!StringUtils.isEmpty(s))
{
try
{
long j = Long.parseLong(s);
if (j != 0L)
{
i = j;
}
}
catch (NumberFormatException var7)
{
// 如果输入的不是数字,使用字符串的哈希值
i = (long)s.hashCode();
}
}
WorldType.worldTypes[this.selectedIndex].onGUICreateWorldPress(); // 目前版本这个函数为空
// 游戏模式(生存、创造等),这个决定玩家的能力(飞行、无敌等)
WorldSettings.GameType worldsettings$gametype = WorldSettings.GameType.getByName(this.gameMode);
// 这里传入了各种游戏设置,就是你在GUI上看到的那些设置(生成建筑、超平坦等)
WorldSettings worldsettings = new WorldSettings(i, worldsettings$gametype, this.field_146341_s, this.field_146337_w, WorldType.worldTypes[this.selectedIndex]);
worldsettings.setWorldName(this.chunkProviderSettingsJson); // 世界名称
if (this.field_146338_v && !this.field_146337_w)
{
worldsettings.enableBonusChest(); // 奖励箱
}
if (this.allowCheats && !this.field_146337_w)
{
worldsettings.enableCommands(); // 允许作弊
}
// 启动游戏服务器,参数为存档文件夹路径、世界(文件夹)名、游戏设置
this.mc.launchIntegratedServer(this.field_146336_i, this.field_146333_g.getText().trim(), worldsettings);
}
// ...
启动游戏服务器
这里补充一些小知识,MC的单人游戏其实是在本进程内建了服务器,服务器才是负责生成世界的,客户端只负责操作输入、渲染等
类名net.minecraft.client.Minecraft
/**
* Arguments: World foldername, World ingame name, WorldSettings
*/
public void launchIntegratedServer(String folderName, String worldName, WorldSettings worldSettingsIn)
{
net.minecraftforge.fml.client.FMLClientHandler.instance().startIntegratedServer(folderName, worldName, worldSettingsIn);
// 首先卸载已经加载的世界