我的世界Bukkit服务器插件开发教程(十五)世界生成器
十五、世界生成器
如果你仔细观察,会发现有个叫saves
的文件夹,这个文件夹是用来存放存档的,即我们平常说的世界。
显然,服务器承担了创建世界、加载世界的任务。Bukkit 中也有专门生成世界的生成器,所以我们可以继承这些类写一个世界生成器。
世界生成器有很多种,但在这之前,我们需要了解一下生成的原理。
0.原理
Minecraft 地形生成是分为两部分:Generation
和Population
。Generation
部分负责生成最基本的地形,Population
部分是负责在这个地形上加装饰(花、草、树等等)。
区块是世界中长和宽为 161616,高为 256256256 的部分。两个部分都是以区块作为最基本的单位,Generation
再使用柏林噪声(Perlin noise)算法生成基础地形。
柏林噪声算法有很多版本,从 1980 年始的原始算法,到如今的改进算法,各种各样呢。柏林噪声实质上是一个函数。省流就是,传入之间相差不大的参数,最后返回一个随机数,
public double perlin(double x,double y,double z);
如上,传入三个参数,最后返回一个 [0,1][0,1][0,1] 区间的一个浮点数,即柏林噪声值。传入相同的参数,最后得到的柏林噪声值也相同,这也就是为什么 Minecraft 中相同的种子总是生成相同的地形。
除此之外还有分形噪声,分形噪声将不同频率的噪声函数合并为一个更为复杂的噪声函数。
但这个函数图像是粗略的,我们可以将某个噪声值进行放大再生成,得到的地形就精细的得多了。
柏林噪声算法不是这一章的重要部分,如果你有兴趣,可以自行阅读其他文章。
1.装饰
在世界开始加载时会触发一个WorldInit
事件,我们可以监听这一事件,然后来完成一次“点缀”。
public class DiamondGenerator implements Listener {@EventHandlerpublic void onWorldInit(WorldInitEvent e) {e.getWorld().getPopulators().add(new DiamondPopulator());}
}
前面说过,Population
就是给原本的地形上加点装饰,当然加的装饰不止一种,我们可以自己添加一种,重点在于实现DiamondPopulator
类。
public class DiamondPopulator extends BlockPopulator {@Overridepublic void populate(World world, Random random, Chunk source) {}
}
首先判断我们需要添加什么,比如随处可见的钻石块,假设我们一个区块需要5个钻石块,对于每一个钻石块而言,只需确定它的横纵坐标,遍历一遍所有 yyy 轴坐标判断是否符合我们要的条件即可。
int count = 5;
for(int i = 0; i <= 5; i++) {//随机确定x,z坐标int x = random.nextInt(16);int z = random.nextInt(16);//遍历我们所要的y坐标for(int y = 128; y >= 0; y--) {//我们的钻石块要在天空上,即空气方块上if(source.getBlock(x, y, z).getType() == Material.AIR) {world.getBlockAt(x, y, z).setType(Material.DIAMOND_BLOCK);}}
}
运用上面的例子你就可以加一些小型建筑来丰富你的插件。
只要你能够理解上面的Populator
就差不多行了,但差不多达不到完美。实际我们一般很少很少会用到世界生成器,而且生成器较为复杂,需要一些基础。
2.地形
2.1.简单区块地形生成
前面说过,Generation
以区块作为基本单位生成,所以我们可以用ChunkGenerator
来生成一个最最简单的地形,比如说钻石大陆。
在你的主类中重写:
@Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {return new DiamondGenerator();
}
老规矩,重在实现DiamondGenerator
:
public class DiamondGenerator extends ChunkGenerator {@Overridepublic ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) {ChunkData chunkData = createChunkData(world);chunkData.setRegion(0, 0, 0, 16, 1, 16, Material.BEDROCK);chunkData.setRegion(0, 1, 0, 16, 16, 16, Material.DIAMOND_BLOCK);return chunkData;}
}
setRegion
方法是用于填充方块,传入两个三维坐标,然后对选中的部分进行填充。
如上,对于每个区块,我们只需将它填充为钻石块就行了。对于每个区块的最底层,我们将它填充为基岩就好了。
我们只是用一个小区块,然后用它拼合成一个大世界。这是最简单的地形生成。
2.2.噪声地形生成
接着就来到了本章的重头戏,对于噪声算法,我们提到了柏林(Perlin)噪声,但还有一个 2.0 版本——Simplex,是对 Perlin算法进行的优化。
private SimplexOctaveGenerator simplex;
@Override
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome) {ChunkData chunkData = createChunkData(world);if(simplex == null) {//传入种子simplex = new SimplexOctaveGenerator(world.getSeed(), 1);simplex.setScale(0.001D);}return chunkData;
}
SimplexOctaveGenerator
就是我们说的分形噪声。同时也可以用setScale
调整噪声函数的频率,可以调的小一些,地形更平坦,或者调大一些,地形更陡峭,甚至完全混乱。
这次我们不需要随机取一个方块的横纵坐标了,我们只需改变一个方块的高度既可,因为最终形成的地形是跌宕起伏的,不可能有个大窟窿吧。
for(int i = 0; i < 16; i++) {for(int j = 0; j < 16; j++) {//设置x,z坐标int xx = x * 16 + i;int zz = z * 16 + j;//获取噪声值double noise = simplex.noise(xx, zz, 0.3D, 0.4D);//将噪声值放大int y = (int) (noise * 35D + 150D);//底层基岩chunkData.setBlock(x, 0, z, Material.BEDROCK);//1~y层全为钻石块for(int k = 1; k <= y; k++) {chunkData.setBlock(x, y, z, Material.DIAMOND_BLOCK);}}
}
以上就是Generation
部分,至于Populartion
部分,我们可以用getDefaultPopulators
方法:
@Override
public List<BlockPopulator> getDefaultPopulators(World world) {return ImmutableList.of(....);//你的装饰生成器
}
3.结束了?
编者一开始想重点讲噪声算法,但是我觉得由于低龄化太过严重,噪声算法过于深奥,不利理解,并且现在随便搜搜都一大堆,也就偷个懒了。原定分为上下稿,现在硬是压缩成一稿,属实不易。
基本上所有要讲的都讲完了,并且还额外扩充了一些。
当然现在不会草草了结这个系列的,应粉丝要求,还有实战呢(恼)。
上一篇:我的世界Bukkit服务器插件开发教程(十四)消息和命令补全器
下一篇:我的世界Bukkit服务器插件开发教程(实战一)起床战争
我的世界Bukkit服务器插件开发教程(十五)世界生成器相关推荐
- 我的世界Bukkit服务器插件开发教程(五)方块Blocks
五.方块Blocks 我怕不更新会被骂,所以更了. 坐标系 小伙纸,求一下∑i=0∞i2\sum_{i=0}^\infty i^2∑i=0∞i2(bushi 是的,你没猜错,我们要涉及到史上最NB超 ...
- 我的世界Bukkit服务器插件开发教程(十一)粒子、药水效果与音效
十一.粒子.药水效果与音效 太简单了吧! 1.粒子效果 1.1.基本操作 播放粒子,首先需要确定粒子需要播放的位置.需要注意,我们一次只能播放一个粒子,如果需要播放多个粒子的话--也不麻烦. 播放粒子 ...
- 我的世界Bukkit服务器插件开发教程(十三)资源包与玩家资料
十三.资源包与玩家资料 1.资源包(Resource Pack) 早期的 Minecraft 并没有资源包一说,而是被叫做材质包.有些服务器为了让玩家拥有更好的游戏体验,一般会在自己特制的客户端中存放 ...
- 我的世界Bukkit服务器插件开发教程(七)计分板
七.计分板 写在前面 对于计分板,相信大部分人会认为这是一个计分的玩意.但不然,它的用处远远不止计分那样简单,计分板在服务器中起着重要的作用,在大部分插件中都有着它的身影. 另注:本章节有大量干货,请 ...
- 我的世界Bukkit服务器插件开发教程(一)第一个插件
一.第一个插件 这一章节,我们会开发第一个属于自己的插件 在这之前,我们还需了解plugin.yml和config.yml,并大概了解插件的原理 plugin.yml 这个文件必须存在,否则读不出来. ...
- 我的世界Bukkit服务器插件开发教程(八)进度条与自定义合成表
八.进度条与自定义合成表 写在前面 本来我想将进度放入本章节当中,但无奈进度牵扯到json文件,估计我又要叽叽喳喳讲一堆json,出于人最基本的性格,这章节暂且不讲. 进度条 说起进度条,打个最简单的 ...
- 我的世界bukkit服务器开发教程第一章——开发环境
提示:如果图片看不见或者文字有乱码,请到我的网站:www.xiaoguaimao.cn 前言: 本教程共分为两个部分: 1.服务器插件开发 2.服务器专属启动器开发 如果你学过编程,那你会很轻松,如果 ...
- 我的世界虚拟服务器架设,我的世界Minecraft服务器架设教程_服务器怎么建立
[导读]我的世界Minecraft服务器架设教程. 下面给大家带来<我的世界>Minecraft服务器的架设教程,让大家对我的世界服务器建立有一个不错的认识,从怎么建立,到怎么维护做一个系 ...
- 【Visual C++】游戏开发笔记四十七 浅墨DirectX教程十五 翱翔于三维世界 摄像机的实现
分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 本系列文章由zhm ...
最新文章
- MacBook Air写代码真香!包邮送一台!
- 计算机英语基础课程论文,计算机专业英语课程教学论文
- C/C++浮点数在内存中的存储方式
- 二值图片连续区域检测
- Java集合和泛型练习及面试题——博客园:师妹开讲啦
- 简记用ArcGIS处理某项目需求中数据的步骤
- 文件上传java逻辑_Java 文件上传 实例
- form表单属性名相同java_java – 将表单字段注入具有相同属性名称的多个bean中
- php cksql,金蝶KSQL规范
- C# 图片处理之:旋转图片任意角度
- python中的itemgetter函数
- Vue.js的IoC容器模式探索
- markdown 书写代码
- mac系统历史版本汇总_苹果发布会 WWDC20 主要更新汇总
- IDEA使用教程汇总
- 51单片机之一套完整的实验流程
- 深度学习mindspore --- rescale(rescale, shift)
- [技术讨论]从ERP免费开始到做人做事的讨论
- 科学的失控与范式的超越——《侏罗纪公园》读后感
- 解决viewer.js预览PDF文件 无法展示PDF水印的问题
热门文章
- Tekla二次开发的各个模块介绍
- 2021年kali-linux壁纸[超清]
- loj 6197. 法克 最小路径覆盖 好题
- 软件设计师备考笔记(二)计算机组成与体系结构
- 网盘系统|基于SpringBoot的网盘系统的设计与实现
- Android在ImageView上直接显示网络图片
- Fedora17硬盘安装
- PyCharm 添加 外键的时候 报错 TypeError:__init__()missing 1 required positional argument:‘on_delete‘
- ZYNQ使用10G Ethernet Subsystem万兆网光通信
- 江南大学计算机专业考研压分吗,考研专业课压分,不保护一志愿考生?20考研的我该如何避坑?...