微程序控制器实验实验报告_程序性景观实验

微程序控制器实验实验报告

Rust的99 LoC中快速而又肮脏的过程生成

几天前,我尝试创建一个过程景观生成器。 这是实际结果: https : //rap2hpoutre.github.io/landscape-site/

我想知道事情是如何运作的。 这就是我建造那个的方式。

山脉

我不是一个优秀的程序员,也不知道如何创建山脉。 我在Stack Exchange上找到了这个答案: https : //gamedev.stackexchange.com/a/93531/81351

因此,我将此代码转换为Rust,因为出于某些原因我喜欢Rust。 首先,我创建了一个Mountain结构。

struct Mountain { 
    points: Vec < u32 >,
}

这些points是每个峰的“ y”位置:在640x480图像上,有640个点从0(最高)到480(最低)不等。

然后,我创建了两个关联的函数:一种用于初始化点的new方法和一种用于绘制山脉的每个像素的draw方法。

impl Mountain {
    fn new (y_amp: ( f64 , f64 )) -> Mountain {
        let mut rng = rand::thread_rng();
        let step_max = rng.gen_range( 0.9 , 1.1 );
        let step_change = rng.gen_range( 0.15 , 0.35 );
        let (height_min, height_max) = y_amp;
        let mut height = rng.gen_range( 0.0 , height_max);
        let mut slope = rng.gen_range( 0.0 , step_max) * 2.0 - step_max;
        let mut points: Vec < u32 > = Vec ::new();

        for _ in 0 .. 640 {
            height = height + slope;
            slope = slope + (rng.gen_range( 0.0 , step_change) * 2.0 - step_change);

            if slope > step_max {
                slope = step_max;
            } else if slope < -step_max {
                slope = -step_max;
            }

            if height > height_max {
                height = height_max;
                slope = slope * - 1.0 ;
            } else if height < height_min {
                height = height_min;
                slope = slope * - 1.0 ;
            }
            points.push(height as u32 );
        }
        Mountain {
            points: points
        }
    }
    fn draw (& self , img: & mut RgbImage, color: Rgb< u8 >, c_fog: Rgb< u8 >) {
        let mut i = 0 ;
        for &point in self .points.iter() {
            img.put_pixel(i, point, color);
            for j in point.. 480 {
                img.put_pixel(i, j, interpolate(c_fog, color, j as f32 / 480.0 ));
            }
            i = i + 1 ;
        }
    }
}

这是最长的部分(虽然很脏,但不是最丑的!),认为这只是我提到的StackExchange帖子中的改编副本/粘贴。

new方法采用参数y_amp的元组,该参数y_amp是当前山脉的边界(最大高度和最小高度)。 用随机的相邻值初始化这些点。

draw方法会参考要绘制的图像和两种颜色:山脉的初始颜色( color )和雾的颜色( c_fog ),这是创建渐变所必需的。 对于每个点,从图像的顶点到顶点绘制一条渐变“线”,将雾色与初始色混合。

我可以使用常量(用于640、480等),为变量选择更好的名称并添加注释,但是,嘿! 没时间! 快点,脏点。

随机颜色帮手

该程序的主要任务是生成随机颜色。 我创建了一个小助手来生成颜色:

fn rgb_rand (rng: & mut ThreadRng, r: ( u8 , u8 ), g: ( u8 , u8 ), b: ( u8 , u8 )) -> Rgb< u8 > {
    Rgb([rng.gen_range(r. 0 , r. 1 ), rng.gen_range(g. 0 , g. 1 ), rng.gen_range(b. 0 , b. 1 )])
}

我忘了提及所有功能和结构,如 Rgb RgbImage interpolate 等,都来自于出色的,部分记录的或多或少稳定的“ image ”和“ imageproc ”板条箱(板条箱是Rust lib)。

我编写的rgb_rand函数可以从红色范围,绿色范围和蓝色范围生成随机颜色。 从现在开始,我将在任何地方使用它。

渐变的天空和随机的月亮

借助rgb_rand函数,我可以初始化随机的天空颜色,随机的雾颜色和随机的月亮颜色。

天空。 它可以是浅色,深色或浅蓝色,让我们抛出1D3:

let mut rng = rand::thread_rng();
let c_sky = match rng.gen_range( 1 , 4 ) {
    1 => rgb_rand(& mut rng, ( 1 , 40 ), ( 1 , 40 ), ( 1 , 40 )),
    2 => rgb_rand(& mut rng, ( 215 , 225 ), ( 215 , 225 ), ( 230 , 255 )),
    _ => rgb_rand(& mut rng, ( 200 , 255 ), ( 200 , 255 ), ( 200 , 255 )),
};

雾的颜色是完全随机的,而行星(月亮?太阳?谁在乎?)颜色是天空和随机颜色的混合:

let c_fog = rgb_rand(& mut rng, ( 1 , 255 ), ( 1 , 255 ), ( 1 , 255 ));
let c_planet = interpolate(rgb_rand(& mut rng, ( 1 , 255 ), ( 1 , 255 ), ( 1 , 255 )), c_sky, 0.1 );

现在让我们绘制所有内容。 所以我从天空开始(我们的基本图像缓冲区):

let mut img = ImageBuffer::from_pixel( 640 , 480 , c_sky);

然后,该程序会在用gen_weighted_bool投掷硬币后尽可能不频繁地绘制行星。 行星只是一个实心圆。 有时,会在天空之后立即绘制另一个实心圆,以创建新月形效果。

if rng.gen_weighted_bool( 2 ) {
    let x = rng.gen_range( 101 , 520 );
    let y = rng.gen_range( 81 , 200 );
    let rad = rng.gen_range( 20 , 80 );
    draw_filled_circle_mut(& mut img, (x, y), rad, c_planet);
    if !rng.gen_weighted_bool( 5 ) {
        draw_filled_circle_mut(& mut img, (x + rng.gen_range(- 2 , 4 ) * 10 , y), rad, c_sky);
    }
}

然后将渐变应用于我们绘制的所有内容。

for (_, y, pixel) in img.enumerate_pixels_mut() {
    *pixel = interpolate(c_fog, *pixel, y as f32 / 1000.0 );
}

有了所有这些代码后,我们现在有了一个带有月亮的渐变天空。

无声的山脉,在渐变的天空

现在是时候在此渐变天空上添加一些山脉了。

let mountain_count: u32 = rng.gen_range( 4 , 7 );
let c_mountain = rgb_rand(& mut rng, ( 1 , 255 ), ( 1 , 255 ), ( 1 , 255 ));
for i in 0 ..mountain_count {
    let c = interpolate(c_mountain, c_sky, (i + 1 ) as f32 / mountain_count as f32 );
    let y_amp = ( ( 399 - 480 / 2 / mountain_count * (mountain_count - i)) as f64 , 401.0 );
    Mountain::new(y_amp).draw(& mut img, c, c_fog);
}

简而言之,我只是定义了一个随机数的山脉mountain_count ,然后定义了基色c_mountain 。 然后,我们对每个山脉进行迭代,构建和绘制第一步中创建的Mountain

高山越深,天空的色彩越柔和。 请记住,雾色还与山脉混合在一起,使它们显得不太平坦。

也许我忘记了一些,整个代码可以在这里找到: https : //github.com/rap2hpoutre/landscape/blob/master/src/main.rs

最后的想法

我喜欢程序生成,即使我大部分时间都不了解,我也喜欢阅读有关如何创建程序性内容的信息。 这篇文章是我编写代码的描述,显然不是Rust的使用方法或教程。 结果不是超级性感,但我喜欢创建它。 我还建立了一个小型网站,每分钟都会产生一个新鲜的风景。 在框架中,因为我希望它看起来像艺术品! 它在这里: https : //rap2hpoutre.github.io/landscape-site/

我的主要灵感来自纳瓦拉山脉。 这里列出的项目远比我的要好,我也掠夺了他们的想法:

我很乐意回答问题,听取建议或面对批评。

感谢@dorhan_的评论!

翻译自: https://hackernoon.com/a-procedural-landscape-experiment-4efe1826906f

微程序控制器实验实验报告

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值