トップページ > ゲーム制作 > ワールドマップ自動生成



概要

島(陸)と海だけがあるワールドマップを自動生成します。


プログラム

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.Point;
 
	public class Main extends Sprite
	{
		private const WIDTH:int = 100;
		private const HEIGHT:int = 100;
		private const ITERATIONS:int = 50000;
		private const SEA:int = 0;
		private const LAND:int = 1;
		private var map:Array;
 
		public function Main()
		{
			map = [];
			for (var y:int = 0; y < HEIGHT; y++)
			{
				map[y] = [];
				for (var x:int = 0; x < WIDTH; x++)
				{
					if (Math.random() < 0.5) map[y][x] = SEA;
					else map[y][x] = LAND;
				}
			}
 
			for (var i:int = 0; i < ITERATIONS; i++)
			{
				var randomX:int = Math.random() * WIDTH;
				var randomY:int = Math.random() * HEIGHT;
				map[randomY][randomX] = (landCount(randomX, randomY) > 4) ? LAND : SEA;
			}
 
			var bd:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0xACBCD7);
			var bitmap:Bitmap = new Bitmap(bd);
			bitmap.scaleX = stage.stageWidth / bitmap.width;
			bitmap.scaleY = stage.stageHeight / bitmap.height;
			addChild(bitmap);
			for (y = 0; y < HEIGHT; y++)
			{
				for (x = 0; x < WIDTH; x++)
				{
					if (map[y][x]) bd.setPixel(x, y, 0x0);
				}
			}
		}
 
		private function landCount(tx:int, ty:int):int
		{
			var count:int = 0;
 
			for (var y:int = -1; y <= 1; y++)
			{
				for (var x:int = -1; x <= 1; x++)
				{
					if (checkTile(tx + x, ty + y)) 
					{
						count++;
					}
				}
			}
			return count;
		}
 
		private function checkTile(x:int, y:int):Boolean
		{
			if (0 <= x && x < WIDTH &&
				0 <= y && y < HEIGHT)
			{
				if (map[y][x] == LAND) return true;
				else return false;
 
			}
			return false;
		}
	}
}
 

プログラムの解説
private const WIDTH:int = 100;		// 幅
private const HEIGHT:int = 100;		// 高さ
private const ITERATIONS:int = 50000;	// 生成を繰り返す回数
private const SEA:int = 0;		// 海
private const LAND:int = 1;		// 島(陸)
private var map:Array;			// マップを入れる二次元配列
 


map = [];
for (var y:int = 0; y < HEIGHT; y++)
{
	map[y] = [];
	for (var x:int = 0; x < WIDTH; x++)
	{
		if (Math.random() < 0.5) map[y][x] = SEA;
		else map[y][x] = LAND;
	}
}
 
二次元配列を生成し、ランダムでSEA(1)かLAND(0)を入れておきます。


for (var i:int = 0; i < ITERATIONS; i++)
{
	var randomX:int = Math.random() * WIDTH;
	var randomY:int = Math.random() * HEIGHT;
	map[randomY][randomX] = (landCount(randomX, randomY) > 4) ? LAND : SEA;
}
 
ランダムに座標を選び、その座標のタイルと隣接している周りの8タイルの中で、
  • 島のタイルが5つ以上ある
    • その座標のマスを島にする
  • 島のタイルが5つ未満しかない
    • その座標のマスを海にする
という処理をITERATIONS回繰り返します。


実行結果

flash on 2011-10-7 - wonderfl build flash online

ITERATIONSを100000、BitmapDataでオートタイルを付けた実行結果です。
クリックするたびにワールドマップを再生成します。


flash on 2011-10-7 - wonderfl build flash online

地形が生成される様子を見ることが出来るコード例です。


検証用コード

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	public class Main extends Sprite
	{
		private const WIDTH:int = 100;
		private const HEIGHT:int = 100;
		private const SEA:int = 0;
		private const LAND:int = 1;
		private const SEA_COLOR:int = 0xACBCD7;
		private const LAND_COLOR:int = 0x0;
		private var map:Array;
		private var bd:BitmapData;
 
		public function Main()
		{
			bd = new BitmapData(WIDTH, HEIGHT, false, SEA_COLOR);
			var bitmap:Bitmap = new Bitmap(bd);
			bitmap.scaleX = stage.stageWidth / bitmap.width;
			bitmap.scaleY = stage.stageHeight / bitmap.height;
			addChild(bitmap);
 
			map = [];
			for (var y:int = 0; y < HEIGHT; y++)
			{
				map[y] = [];
				for (var x:int = 0; x < WIDTH; x++)
				{
					if (Math.random() < 0.5)
					{
						map[y][x] = SEA;
					}
					else
					{
						map[y][x] = LAND;
						bd.setPixel(x, y, LAND_COLOR);
					}
				}
			}
 
			var timer:Timer = new Timer(1, 5000);
			timer.addEventListener(TimerEvent.TIMER, generateMap);
			timer.start();
		}
 
		private function generateMap(event:TimerEvent = null):void
		{
			for (var i:int = 0; i < 20; i++)
			{
				var randomX:int = Math.random() * WIDTH;
				var randomY:int = Math.random() * HEIGHT;
				map[randomY][randomX] = (landCount(randomX, randomY) > 4) ? LAND : SEA;
				var value:int = map[randomY][randomX];
				if (value == LAND) bd.setPixel(randomX, randomY, LAND_COLOR);
				else bd.setPixel(randomX, randomY, SEA_COLOR);
			}
		}
 
		private function landCount(tx:int, ty:int):int
		{
			var count:int = 0;
 
			for (var y:int = -1; y <= 1; y++)
			{
				for (var x:int = -1; x <= 1; x++)
				{
					if (checkTile(tx + x, ty + y)) 
					{
						count++;
					}
				}
			}
			return count;
		}
 
		private function checkTile(x:int, y:int):Boolean
		{
			if (0 <= x && x < WIDTH &&
				0 <= y && y < HEIGHT)
			{
				if (map[y][x] == LAND) return true;
				else return false;
 
			}
			return false;
		}
	}
}