u3d honey hex framework 代碼解讀記錄(一)

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;
} 


待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章