使用perlin噪音生成随机地图

引言

还是随机地图的问题,除了细胞自动机的生成方式以外,一般3D游戏中的地形大部分是使用某个噪音原图,这个原图大部分是由perlin噪音产生的(perlin noise),perlin噪音的主要作用可参考Perlin噪音

Perlin噪音的实现方式有点复杂,一时间不是很好看懂,我个人理解的是,噪音不太可能是完全随机的,自然界的很多东西虽然看起来是随机的,但是随机中间又蕴藏着很多规则,这些规则导致出现随机实际上是有些规则的,不可能出现类似电视雪花点的噪音。

所以为了用计算机图形来更好的描述自然界的这一随机现象,perlin创造了perlin噪音这么个自然随机算法。perlin噪音包含了平滑差值及八阶分形的内容,有点复杂,不好在这里展开。

实现思路

通过perlin噪音生成随机的灰度(即只有黑白的)噪音图,然后一定比率的颜色变成可通行区域颜色,一定比例的成为障碍物颜色。如0~100为陆地,101~255为障碍物。然后,神奇的一幕发生了。

效果

PerlinNoiseRandomMap.swf

高清无码

PerlinNoiseRandomMap1.swf

像不像地球呢?

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package {
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.geom.Rectangle;
    import flash.geom.Point;
    import flash.events.Event;
    import flash.display.Sprite;
    import flash.events.MouseEvent;

    public class PerlinNoiseRandomMap extends Sprite {
        protected var bmTerrain:Bitmap;
        protected var bmpTerrain:BitmapData;
        protected var freq:Number = 0.5;
        protected var octs:Number = 8;
        protected var seed:Number = 12;
        protected var stitch:Boolean = true;
        protected var fractal:Boolean = true;
        protected var channels:Number = 7;
        protected var gray:Boolean = true;
        protected var red:Array = new Array(256);
        protected var green:Array = new Array(256);
        protected var blue:Array = new Array(256);
        protected var land:Number = 0xff00ff00;
        protected var water:Number = 0xff0000ff;
     
        public function PerlinNoiseRandomMap() {
            init();
            stage.addEventListener(MouseEvent.CLICK, reset);
        }
     
        public function init():void {
            for (var i:Number = 0; i < 128; i++) {
                red[i]=green[i]=blue[i]=land;
            }
            for (i = 128; i < 256; i++) {
                red[i]=green[i]=blue[i]=water;
            }
            bmpTerrain = new BitmapData(800,600);
            // perlin噪音
            bmpTerrain.perlinNoise(bmpTerrain.width * freq,bmpTerrain.height * freq, octs, seed, stitch, fractal, channels, gray);
            // 以红色通道举例,0-128的红色值重新映射到red[0]到red[128]的数组值
            bmpTerrain.paletteMap(bmpTerrain,new Rectangle(0,0,bmpTerrain.width,bmpTerrain.height),new Point(0,0),red,green,blue);
            bmTerrain = new Bitmap(bmpTerrain);
            bmTerrain.width = stage.stageWidth;
            bmTerrain.height = stage.stageHeight;
            addChild(bmTerrain);
        }
     
        public function destroy():void {
            removeChild(bmTerrain);
            bmTerrain = null;
            bmpTerrain = null;
        }
     
        public function reset(e:MouseEvent):void {
            destroy();
            seed = Math.random();
            init();
        }
     
    }
}

参考文献

updatedupdated2021-01-202021-01-20