渲染效果
源代码
作者将柏林噪声用了python和JavaScript两种语言实现
两种语言效果基本一样
python
import random
def ave(a, b):# 计算平均值
return round((a + b) / 2)
def ave_list(lst):# 计算一个全为数字的列表的平均值
return round(sum(lst) / len(lst))
def smooth_list(input_list, width)->list:# 将整个列表进行平滑处理
result_list = input_list.copy()
for i in range(len(input_list)):
if i != 0 and i % width != 0 and i != len(input_list) - 1:
neighbors_sum = input_list[i - 1] + input_list[i + 1]
before_width = max(0, i - width)
after_width = min(len(input_list) - 1, i + width)
neighbors_sum += input_list[before_width] + input_list[after_width]
result_list[i] = neighbors_sum / 4
return result_list
def random_map(width, height, average, gaocha)->list:
'''
随机生成
'''
'''将所有输入值转换为int类型,放置后期报错'''
average = int(average)
width = int(width)
height = int(height)
gaocha = int(gaocha)
print('开始随机生成!')# 打印一条消息方便调试
next_value = 0# 下一个列表值的存档
return_list = []# 返回的列表最初为空
'''第一项:在平均值的基础上加或减一个“gaocha”范围内的数'''
return_list.append(min(height, max(0, average + random.randint(-gaocha, gaocha))))
'''生成列表1~256项(第一排)'''
while len(return_list) < width:# 意思很简单,当列表长度小于宽度(256)时就重复生成
'''控制整个列表的平均值,避免数值一直上升或下降'''
if ave_list(return_list) >= average + gaocha:# 如果整个列表的平均值大于等于传入的平均值+高差(整体太高了)就只能在列表最后一项的基础上减去一个小于高差(当然大于0)的数
next_value = return_list[-1] + random.randint(-gaocha, 0)
elif ave_list(return_list) < average - gaocha:# 反之
next_value = return_list[-1] + random.randint(0, gaocha)
else:# 否则加或减都行
next_value = return_list[-1] + random.randint(-gaocha, gaocha)
next_value = min(height, max(0, next_value))
if next_value > 0 and next_value <= height:# 为了防止亮度太高或太低(负数),检测next_value的值是否符合要求
return_list.append(next_value)
'''生成257以及以后的项'''
while len(return_list) / width < width:# 当行数小于给定width时就不断生成
return_list.append(return_list[-1] + random.randint(-gaocha, gaocha))
'''分别生成每一行'''
while len(return_list) % width != 0:
'''根据不同的列表平均值情况“分类讨论”
唯一的不同就是,257及以后的项需要考虑到上方一行自己对应的位置(前面第256项)和左边(上一项)'''
if ave_list(return_list) >= average + gaocha:
next_value = ave(return_list[-1], return_list[-1 - width]) + random.randint(-gaocha, 0)
elif ave_list(return_list) < average - gaocha:
next_value = ave(return_list[-1], return_list[-1 - width]) + random.randint(0, gaocha)
else:
next_value = ave(return_list[-1], return_list[-1 - width]) + random.randint(-gaocha, gaocha)
if next_value > 0 and next_value <= height:
return_list.append(next_value)
return smooth_list(return_list, width)# 最后返回之前再次平滑一下列表
# 示例
map = random_map(256, 63, 10, 5)
JavaScript
function random(min, max) {
return Math.round(Math.random() * (max - min) + min)
}
function ave(a,b) {
return Math.round((a+b)/2)
}
function ave_list(list){
let sum = 0;
for(let i=0;i<list.length;i++){
sum+=list[i];
}
return Math.round(sum/list.length);
}
function smoothList(inputList, width) {
let resultList = inputList.slice(); // 创建一个副本,以免修改原始列表
for (let i = 0; i < inputList.length; i++) {
if (i !== 0 && i % width !== 0 && i !== inputList.length - 1) { // 只处理非边缘和指定间隔的项
let neighborsSum = inputList[i-1] + inputList[i+1];
let beforeWidth = Math.max(0, i-width);
let afterWidth = Math.min(inputList.length-1, i+width);
neighborsSum += inputList[beforeWidth] + inputList[afterWidth];
resultList[i] = neighborsSum / 4; // 将当前项替换为相邻项和指定间隔项的平均值
}
}
return resultList;
}
// 柏林噪声地形生成
/**
* @description 生成柏林噪声地形
* @param {number} width 长
* @param {number} height 宽
* @param {number} average 平均高度
* @param {number} gaocha 最大高差
*/
async function randomMap(width, height, average, gaocha) {
await sleep(1000)
var nextValue = 0;
let return_list = [];
return_list.push(Math.min(height, Math.max(0, average + random(-gaocha, gaocha))));
while (return_list.length < width) {
if(ave_list(return_list)>=average+gaocha){
nextValue = return_list[return_list.length - 1] + random(-gaocha, 0);
}
else if(ave_list(return_list)<average-gaocha){
nextValue = return_list[return_list.length - 1] + random(0, gaocha);
}
else{
nextValue = return_list[return_list.length - 1] + random(-gaocha, gaocha);
}
nextValue = Math.min(height, Math.max(0, nextValue));
if(nextValue>0&&nextValue<=height){
return_list.push(nextValue);
}
}
while(return_list.length/width < width){
return_list.push(return_list[return_list.length-1]+random(-gaocha, gaocha))
while(return_list.length%width!=0){
if(ave_list(return_list)>=average+gaocha){
nextValue = ave(return_list[return_list.length-1],return_list[return_list.length-width])+random(-gaocha, 0)
}
else if(ave_list(return_list)<average-gaocha){
nextValue = ave(return_list[return_list.length-1],return_list[return_list.length-width])+random(0, gaocha)
}
else{
nextValue = ave(return_list[return_list.length-1],return_list[return_list.length-width]+random(-gaocha, gaocha))
}
if(nextValue>0&&nextValue<=height){
return_list.push(nextValue);
if(return_list.length%50==0){
await sleep(1)
}
}
}
}
return smoothList(return_list,width)
}
// 示例
map = randomMap(256, 63, 10, 5)
调用
ccw共创世界
将python代码进行一点小修改后弄到共创世界里面,用画笔呈现结果:
dao3.fun神奇代码岛
将JavaScript代码进行修改后弄到神奇代码岛的地图作品里面,可以实现3D渲染
神奇代码岛 (dao3.fun)(代码未开源,详情见链接)
原理
单看代码似乎不那么好理解,我们通过文字来讲解一下!
举个例子:我们将一个256*256(=65536,也可以是其他尺寸,具体尺寸依照传入的width值)的方形区域存储在一个长65536项的列表里
那么,每一项分别代表那一个地方呢?
举个栗子:第1项代表第一行的最左边的那个位置,第256项代表第一行最右边的位置;第257项代表第2行最左边的位置……第65536项代表最右下角的位置
也可以通过下方表格来理解(每个数字代表列表的第几项):
1 | 2 | 3 | 4 | ... | 256 |
257 | 258 | 259 | 260 | ... | 512 |
513 | 514 | 515 | 516 | ... | 768 |
... | ... | ... | ... | ... | ... |
... | ... | ... | ... | ... | ... |
... | ... | ... | ... | ... | ... |
65281 | 65282 | 65283 | 65284 | ... | 65536 |
那么,我们现在要做的就是生成这个超级大的列表了!
(生成列表的原理在上方python源代码中通过注释解释)
标签:...,return,低配,噪声,random,list,width,gaocha,柏林 From: https://blog.csdn.net/azkbbys/article/details/139030293