3,417
个编辑
MCBBS Wiki欢迎您共同参与编辑!在参与编辑之前请先阅读Wiki方针。
如果在编辑的过程中遇到了什么问题,可以去讨论板提问。
为了您能够无阻碍地参与编辑 未验证/绑定过邮箱的用户,请尽快绑定/验证。
MCBBS Wiki GitHub群组已上线!
您可以在回声洞中发表吐槽!
服务器状态监控。点击进入
本站由MCBBS用户自行搭建,与MCBBS及东银河系漫游指南(北京)科技有限公司没有从属关系。点此了解 MCBBS Wiki 不是什么>>
| (未显示同一用户的2个中间版本) | |||
| 第277行: | 第277行: | ||
==== 实现generateChunk方法 ==== | ==== 实现generateChunk方法 ==== | ||
最难以理解的部分要来了。 | 最难以理解的部分要来了。 | ||
这一部分,笔者只能说尽力地为读者讲解了,因为笔者对这一部分也只是一知半解。其实大部分Modder对这部分估计也不懂,很多模组的这块代码几乎就是照搬原版。因为Mojang在这块的代码写得实在是太抽象了,就连MCP都无法反混淆这些离谱的局部变量。我估计MC圈子里能完全看懂这些代码的只有Mojang员工和极少数社区开发者了。 | |||
所以,这部分的代码,如果读者不想听原理,且自己做的维度的地形生成和主世界差不多的话,直接去GitHub上一些模组的源代码仓库Copy + Paste就可以了(当然请注意这么做可能会引发一些版权问题,请先看好哪些模组采取限制宽松的开源协议,不过话说回来,大家这块的代码都是抄的原版代码,真的会有人去追究这种事情吗)。 | |||
实现generateChunk方法,大概是这样的: | 实现generateChunk方法,大概是这样的: | ||
| 第303行: | 第307行: | ||
然后,新建一个ChunkPrimer对象。再接连调用三个方法:generateHeightMap、setBlocksInChunk和replaceBiomeBlocks。这三个方法都用private修饰,实际上这体现了ChunkPrimer对象写入数据的一些步骤,你当然也可以把这三个方法的代码全塞在generateChunk这个方法里,但是完全没必要。把这些代码分成三个方法,更能体现代码模块化的原则。 | 然后,新建一个ChunkPrimer对象。再接连调用三个方法:generateHeightMap、setBlocksInChunk和replaceBiomeBlocks。这三个方法都用private修饰,实际上这体现了ChunkPrimer对象写入数据的一些步骤,你当然也可以把这三个方法的代码全塞在generateChunk这个方法里,但是完全没必要。把这些代码分成三个方法,更能体现代码模块化的原则。 | ||
然后,就开始进行结构的生成了。 | |||
这一切工作都做完后,便可以构造Chunk对象了。但是别急着返回该对象——我们还需要调用Chunk类的generateSkylightMap实例方法,然后才能返回。如果你不这么做,你会发现,进入你的新维度后,维度的TPS和FPS都非常低,整个维度也非常昏暗,且如果你什么都不做,整个维度都不能生成生物;但如果你放置了一个方块,那么该方块所在的区块会疯狂生成生物,很可能造成Memory Leak。 | |||
===== generateHeightMap ===== | ===== generateHeightMap ===== | ||
通常你需要用到generateNoiseOctaves方法,但接下来的事笔者也不懂了,请自行去GitHub上找现成的代码看吧。 | |||
===== setBlocksInChunk ===== | ===== setBlocksInChunk ===== | ||
原版主世界的区块生成类中,这个方法的代码是最抽象的。它有一个六重循环,循环里有大量意义不明的局部变量,最内层循环还有让人十分看不懂的一些if语句。同样建议直接去参考别人的代码。不过如果你真的想搞明白其中的原理的话,推荐去看交错次元模组的ChunkGeneratorBetweenlands源代码,在其中,setBlocksInChunk中的每个局部变量都有了意义明确的名字,只能说Angry Pixel牛逼! | |||
===== replaceBiomeBlocks ===== | ===== replaceBiomeBlocks ===== | ||
这个方法的代码逻辑相对来说还算简单,原版主世界区块生成类中,Forge在这个方法的开头patch进去了一个事件,借此你可以操控主世界的表层方块替换。也建议在你的区块生成类中加上对于这个事件的判断。 | |||
这个方法中<code>surfaceNoise</code>开始发力,然后又是一个二重循环,在其中调用Biome类的genTerrainBlocks实例方法。 | |||
==== 实现populate方法 ==== | ==== 实现populate方法 ==== | ||
在原版的主世界区块生成类中,Forge在这里patch了三个事件。 | |||
* PopulateChunkEvent.Pre | |||
* PopulateChunkEvent.Populate | |||
* PopulateChunkEvent.Post | |||
实现该方法大致的流程是: | |||
* 令BlockFalling.fallInstantly的值为true | |||
* 执行PopulateChunkEvent.Pre事件 | |||
* 生成除了洞穴和峡谷以外的大型结构,之后反复判断PopulateChunkEvent.Populate事件,这用来决定那些由WorldGenerator控制的结构是否生成,且这段时间还会调用Biome类的decorate实例方法 | |||
* 执行PopulateChunkEvent.Post事件 | |||
* 令BlockFalling.fallInstantly的值为false | |||
由此可见,在主世界的区块生成过程中,只有通过WorldGenerator生成的结构的生成过程才可以通过监听事件来精确地干涉。在你自己的区块生成类中,你实现这个方法的时候,你可以不发布任何事件,但如果你要考虑你的模组和其他干涉世界生成的模组的交互的话,那么你最好还是把这些事件的发布都给加上。 | |||
=== 等等:我要做的维度的世界生成特性和主世界完全不一样啊! === | |||
的确,上述笔记仅仅是简单地说了一下如何生成一个类似于主世界的维度。 | |||
不过读者也该学会变通,比如如果你要创建一个全是空岛的维度,那么你就该去参考天境模组中的天境维度或深渊国度模组中的奥穆索维度的ChunkGenerator代码。 | |||
如果你要创建一个整个世界都是无边无际的建筑的维度(这种维度最常见的例子就是魔法金属模组中的亡灵古墓),那么你可以考虑先把每一种房间都硬编码出来,再通过一定的算法计算出这些房间各自的生成权重,最后把这些东西体现在generateChunk中即可。 | |||
如果你要创建一个整个世界只有一个建筑、其他地方全是虚空的维度(这种维度最常见的例子是虚无世界模组中的远古神殿),那么你可以考虑直接硬编码,也可以利用WorldGenerator在populate方法中生成该建筑。 | |||
如果…… | |||
总而言之,读者应该尽量变通。如果读者明明用手写代码的方式开发模组,却在遇到世界生成这种非常复杂的部分时,总期望着有一招能吃遍天下鲜,那我的评价是:不如去用MCreator。手写代码真是难为你了。 | |||
== 注释与外部链接 == | == 注释与外部链接 == | ||