ワールドマップ生成

ayumegu(プログラマー)
よろしくお願いします。

はい、今回も何かソースを書きます
前回マップチップいじったのでそれ系でもうひとつ
今回は簡単にワールドマップ作ってみます

##完成サンプル

参考サイトはこちら
地上マップの自動生成をFlashで作ってみた

今回は参考コードがないので生成ルールから勝手に作成。
引用になりますが作成ルールは下記

  • 1:任意の割合でチップをランダムに配置する
  • 2:隣接色のいずれかにランダムチェンジ
  • 3:隣接色がすべて同じ色だったら浸食
  • 4:2〜3を繰り返す

これだけでできます
ちなみに参考サイトでは回りにを海にしていたのでそれもまねました

##手順 1:任意の割合でチップをランダムに配置する
画像でいうとこんな感じ
簡易的なので完全ランダムで配置しています

のこりをやるw
残りと行っても処理はシンプルなので最後にソースをのせて完了にします
最初の画像から1回実行

2回目

3回目

5回目

10回目

39回くらい

ソースは1ファイル

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class CreateWorld : MonoBehaviour {
public Transform worldMap;
private const int MAP_WIDTH = 50;
private const int MAP_HEIGHT = 50;
private const int TILE_SIZE = 32;
private const int IMG_ID_ARETI = 0;
private const int IMG_ID_GRASS = 1;
private const int IMG_ID_DESEART = 2;
private const int IMG_ID_DART = 3;
private const int IMG_ID_SNOW = 4;
private const int IMG_ID_SEA = 5;
private const int IMG_ID_DARK = 6;
private List<WorldTileData> tileList;
Vector2[] dir = new Vector2[]
{
new Vector2(1, 0),
new Vector2(-1, 0),
new Vector2(0, 1),
new Vector2(0, -1),
};
public enum TileType
{
NONE = 0,
ARETI,
GRASS,
DESEART,
DART,
SNOW,
SEA,
DARK,
}
// Use this for initialization
void Start () {
tileList = new List<WorldTileData>();
// 外側を海にする
for(int x = -1; x <= MAP_WIDTH; x++)
{
CreateSea(x, -1);
CreateSea(x, MAP_HEIGHT);
}
for(int y = -1; y < MAP_HEIGHT; y++)
{
CreateSea(-1, y);
CreateSea(MAP_WIDTH, y);
}
// ランダムで初期化
for(int y = 0; y < MAP_HEIGHT; y++)
{
for(int x = 0; x < MAP_WIDTH; x++)
{
WorldTileData tile = new WorldTileData();
tile.SetTileType((TileType)Random.Range(1, 9));
tile.Obj.transform.parent = worldMap;
tile.Obj.transform.position = new Vector3(x * TILE_SIZE * 0.01f, y * TILE_SIZE * 0.01f, 0);
tileList.Add(tile);
}
}
}
private void CreateSea(int x, int y)
{
GameObject tileObj = Instantiate(Resources.Load("Prefabs/WorldTile")) as GameObject;
tileObj.name = "Sea";
tileObj.transform.position = new Vector3(x * TILE_SIZE * 0.01f, y * TILE_SIZE * 0.01f, 0);
tileObj.GetComponent<tk2dSprite>().spriteId = IMG_ID_SEA;
tileObj.transform.parent = worldMap;
}
private void UpdateWorld()
{
for(int y = 0; y < MAP_HEIGHT; y++)
{
for(int x = 0; x < MAP_WIDTH; x++)
{
// 隣接チップのいずれかにランダムチェンジ
int dx = (int)dir[Random.Range(0,4)].x;
int dy = (int)dir[Random.Range(0,4)].y;
TileType type;
if(x + dx < 0 || MAP_WIDTH <= x + dx || y + dy < 0 || MAP_HEIGHT <= y + dy)
type = TileType.SEA;
else
type = GetTile(x + dx, y + dy).TileType;
SetTile(x, y, type);
// 隣接タイルが同じだったら浸食
bool isSame = true;
TileType sameTileType = TileType.NONE;
for(int i = 0; i < 4; i++)
{
dx = (int)dir[i].x;
dy = (int)dir[i].y;
if(x + dx < 0 || MAP_WIDTH <= x + dx || y + dy < 0 || MAP_HEIGHT <= y + dy)
type = TileType.SEA;
else
type = GetTile(x + dx, y + dy).TileType;
if(sameTileType == TileType.NONE)
sameTileType = type;
else if(sameTileType != type)
{
isSame = false;
break;
}
}
// 浸食
if(isSame)
{
SetTile(x, y, sameTileType);
}
}
}
}
// Update is called once per frame
void Update () {
}
private WorldTileData GetTile(int x, int y)
{
return tileList[x + MAP_WIDTH * y];
}
private void SetTile(int x, int y, TileType type)
{
tileList[x + MAP_WIDTH * y].SetTileType(type);
}
public class WorldTileData
{
private TileType tileType;
private GameObject obj;
public WorldTileData()
{
obj = Instantiate(Resources.Load("Prefabs/WorldTile")) as GameObject;
obj.name = "Tile";
tileType = TileType.ARETI;
}
public void SetTileType(TileType tileType)
{
this.tileType = tileType;
if(tileType == TileType.ARETI)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_ARETI;
else if(tileType == TileType.GRASS)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_GRASS;
else if(tileType == TileType.DESEART)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_DESEART;
else if(tileType == TileType.GRASS)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_GRASS;
else if(tileType == TileType.DART)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_DART;
else if(tileType == TileType.SNOW)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_SNOW;
else if(tileType == TileType.SEA)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_SEA;
else if(tileType == TileType.DARK)
obj.GetComponent<tk2dSprite>().spriteId = IMG_ID_DARK;
}
public TileType TileType
{
get { return tileType; }
}
public GameObject Obj
{
get { return obj; }
set { obj = value; }
}
}
}

今回作ったものUnityPlayer版
左の方の看板クリックするとUpdateWorldメソッドが一回呼ばれます
あ、ちなみに画像表示周りは2dToolKitを使用しております。

あと2のループの中で3もやっちゃってますが・・・。

##感想 さくっとできました。
比率が完全ランダムなのでこれを指定できるようにしてマップチップも選択できるようにすればもう少しバラエティーにとんだマップが作れます。
今回はここまで〜