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