honey hex framework: 點擊打開鏈接
// file: CameralControl.cs
if (GUILayout.Button("Generate World"))
{
// 將地形和配置資源load到遊戲中
// 遊戲設置(MHGameSettings)和地形配置(MHTerrain)
// 代碼較簡單,先從StreamingAssets處尋找資源,如果沒有,就從Resource裏面尋找,然後load到內存中
// 地形數據會放入到MHTerrain.list中,在第2個函數執行時會用到
DataManager.Reload();
// 是生成地圖,框架主要內容
World.GetInstance().Initialize();
// a*尋路相關,暫時忽略
AstarPath.RegisterSafeUpdate(GameManager.instance.ActivatePathfinder);
}
public void Initialize()
{
status = Status.Preparation;
// load 地形配置
TerrainDefinition.ReloadDefinitions();
// 生成地圖數據
GenerateBasicWorld(hexRadius, GeneratorMode.Random);
// 創建河流數據,先不分析,跳過
RiverFactory.CreateRivers(this, hexRadius);
// 爲每一個chunk生成地形數據,以便worldoven烘焙
// x和y從-chunkRadius到+chunkRadius,chunkRadius爲1,即有9塊chunk
// -1,1 |0,1 |1,1
// -1,0 |0,0 |1,0
// -1,-1|0,-1|1,-1
for (int x = -chunkRadius; x <= chunkRadius; x++)
for (int y = -chunkRadius; y <= chunkRadius; y++)
{
PrepareChunkData(new Vector2i(x, y));
}
status = Status.TerrainGeneration;
}
static public void ReloadDefinitions()
{
// load地形配置和遊戲配置
if (!DataManager.isInitialized)
{
DataManager.GetInstance();
if (!DataManager.isInitialized)
{
Debug.LogError("Data Manager is not initialized! no definitions would be loaded...");
return;
}
}
definitions = new List<TerrainDefinition>();
// MHTerrain.list是DataManger.loadResource加載的地形配置數據,
// 填充到TerrainDefinition.definitions這個數組裏面
foreach (MHTerrain t in MHTerrain.list)
{
TerrainDefinition td = new TerrainDefinition();
td.source = t;
td.diffuse = LoadTexture(t.diffusePath);
td.height = LoadTexture(t.heightPath);
td.mixer = LoadTexture(t.mixerPath);
definitions.Add(td);
}
}
// 傳入的參數,radius是world類的變量hexRadius,默認值是15,mode是GeneratorMode.random
public void GenerateBasicWorld(int radius, GeneratorMode mode)
{
// 清空world對象中的hexes
hexes = new Dictionary<Vector3i, Hex>();
// 第一個參數爲全x,y,z都爲0的向量,所以此處獲取了0爲中心半徑爲radius(15)以內的所有hex的座標組成的數組
List<Vector3i> rangeHexes = HexNeighbors.GetRange(new Vector3i(), radius);
int terrainCount = TerrainDefinition.definitions.Count;
if (terrainCount < 1)
{
Debug.LogError("no terrain definitions to use!");
return;
}
// 從地形配置中找出所有地形類型爲normal的地形配置,類型一共有以下幾種:
// 1. normal; 2. IsBorderType; 3. IsRiverType; 4. DoNotUseThisTerrain
List<TerrainDefinition> tdList = TerrainDefinition.definitions.FindAll(o => o.source.mode == MHTerrain.Mode.normal);
foreach (Vector3i v in rangeHexes)
{
hexes.Add(v, GetHexDefinition(mode, v, tdList));
}
}
// 此處傳入的參數mode是GeneratorMode.random
static public Hex GetHexDefinition(GeneratorMode mode, Vector3i position, List<TerrainDefinition> tdList)
{
Hex hex = new Hex();
int index = 0;
// 隨機選擇順序和旋轉角度
hex.orderPosition = UnityEngine.Random.Range(0.0f, 1.0f);
hex.rotationAngle = UnityEngine.Random.Range(0.0f, 360.0f);
TerrainDefinition def = null;
switch (mode)
{
case GeneratorMode.Random:
// 隨機從list裏面選擇一個地形配置
index = UnityEngine.Random.Range(0, tdList.Count);
def = tdList[index];
break;
case GeneratorMode.Perlin:
// 柏林噪聲選擇地形配置
float xScale = .16f;
float yScale = .16f;
float value = Mathf.PerlinNoise(position.x * xScale, position.y * yScale);
index = (int)(value * (tdList.Count - 1));
def = tdList[index];
break;
}
// 設置地形配置和位置
hex.terrainType = def;
hex.position = position;
// 將當前hex加入到hexesToPolish這個list裏面
GetInstance().ReadyToPolishHex(hex);
return hex;
}
public bool PrepareChunkData(Vector2i pos)
{
Chunk chunk;
// chunks是world對象的字典,key是pos,value是chunk
if (chunks.ContainsKey(pos))
{
// 如果此位置chunk存在,則清除掉此chunk包含的hex數據
chunk = chunks[pos];
chunk.ClearHexesCovered();
}
else
{
chunk = new Chunk(pos, this);
}
Rect r = chunk.GetRect();
// 擴大chunk的覆蓋範圍
//expand its influence by the texture halfWidth (aka radius) which would let us find all hexes which influence our chunk even with border of their texture
r.xMin -= Hex.hexTexturePotentialReach;
r.yMin -= Hex.hexTexturePotentialReach;
r.xMax += Hex.hexTexturePotentialReach;
r.yMax += Hex.hexTexturePotentialReach;
// 獲取chunk區域包含的所有hex的中心點的座標
List<Vector3i> intersections = HexNeighbors.GetHexCentersWithinSquare(r);
bool foundAny = false;
foreach (Vector3i v in intersections)
{
// hexes是函數GenerateBasicWorld中將此區域中半徑爲radius(15)以內的所有hex
// 由於hexes是以0,0爲中心點,半徑爲15之內的hex的集合,所以hex將chunk(0,0)全部覆蓋完了,
// 其他chunk則只有很少的hex,對應生成的地圖就成爲中心處(chunk(0,0))是地形,周圍有部分地形,其餘全是海洋(邊界)
//if hex exists at those coordinates, add it to chunk management
if (hexes.ContainsKey(v))
{
chunk.hexesCovered[v] = hexes[v];
// 如果有任何類型不是邊界的hex,則foundAny是true
foundAny = foundAny || !(hexes[v].terrainType.source.mode == MHTerrain.Mode.IsBorderType);
}
else
{
// 如果hexes中不包含當前座標,則表示座標在邊界處(超出radius的半徑範圍),設置hex類型爲border
//produce border hexes which will fill empty space in chunk
Hex border = new Hex();
TerrainDefinition td = TerrainDefinition.definitions.Find(o => o.source.mode == MHTerrain.Mode.IsBorderType);
if (td == null) td = TerrainDefinition.definitions[0];
border.terrainType = td;
border.rotationAngle = 0;
border.orderPosition = UnityEngine.Random.Range(0.0f, 1.0f);
border.rotationAngle = UnityEngine.Random.Range(0.0f, 360.0f);
border.position = v;
hexes.Add(v, border);
chunk.hexesCovered[v] = border;
}
}
if (foundAny == false)
{
return false;
}
chunks[pos] = chunk;
// 將當前chunk設爲dirty,這樣worldoven可以baking了
WorldOven.AddDirtyChunk(chunk);
return true;
}
待續