/* * @Author: 白哉 * @Description: 地图生成器 * @Date: 2025年04月01日 星期二 11:04:43 * @Modify: */ using UnityEngine; using System; using System.Collections.Generic; using System.Linq; using RuntimeData; using TH1_Logic.Core; using Unity.VisualScripting; using Random = UnityEngine.Random; namespace Logic { public class MapGenerator { private Main _main; private MapData _mapData; //海陆层参数,柏林噪音 private const float Scale = 20f; // 噪声的缩放因子 private float _landThreshold; // 陆地的阈值 private float _mountainThreshold = 0.7f; // 山地的阈值 private float[,] _heightMap; private const int SmoothIterations = 3; //平滑次数 private uint _width, _height; private List _tribes; //用来避免treasure连着生成 private List _treasure; private List _innerCityGrid; private List _outerCityGrid; public List PlayerCivOri; List dir4 = new List() { Vector2.up, Vector2.right, Vector2.down, Vector2.left }; List dir8 = new List() { Vector2.down , Vector2.right , Vector2.left , Vector2.up ,Vector2.left+Vector2.up , Vector2.up+Vector2.right, Vector2.down+Vector2.right,Vector2.down+Vector2.left }; // 初始化地图 public MapGenerator(Main main,MapData mapData) { _main = main; _mapData = mapData; Table.Instance.GeoDataAssets.OnMapGenerator(); } public void GenerateMap(MapData mapData) { _width = mapData.MapConfig.Width; _height = mapData.MapConfig.Height; _heightMap = new float[_width, _height]; if (DebugCenter.Instance.DebugLandThreshold < 0) _landThreshold = new System.Random().Next(200, 400) / 1000f; else _landThreshold = DebugCenter.Instance.DebugLandThreshold; _tribes = new List(); _treasure = new List(); _innerCityGrid = new List(); _outerCityGrid = new List(); //用柏林噪音生成地图高度 GenerateHeightMap(); //平滑地图 SmoothHeightMap(); //归一化处理地图,均匀分布0~1范围 NormalizeHeightMap(); //在连续的大片海洋上生成岛屿 GenerateIsland(); //在连续的陆地上生成湖泊 GenerateLakes(); //生成所有tribe GenerateTribes(); //创建文明摇篮城市(每个玩家的原始首都) GenerateCradleCity(mapData); //初始化所有Grid信息 InitGridMapData(mapData); //修复摇篮城市附近的地形保底和资源保底 CivTerrainFeatureCountControl(mapData); //生成所有GeoInf Table.Instance.GeoDataAssets.InitGeoData(mapData); } //在MapRenderer初始化之后,再进行一些mapgenerator的其他操作 public void GenerateMapAfterMapRenderer(MapData mapData) { //初始化所有玩家的初始视野信息 InitAllPlayerSight(mapData); //初始化Debug的参数 InitDebugInfo(mapData); //初始化所有玩家的特殊领地技能(目前主要是kaguya) InitPlayerSpecialSkill(mapData); } //海陆层使用的地形高度数据 private void GenerateHeightMap() { for (var x = 0; x < _width; x++) { for (var y = 0; y < _height; y++) { float seda = new System.Random().Next(1, 30); float sedb = new System.Random().Next(2, 40); // 使用种子值来改变噪声的生成,保证每次生成的噪声不同 var xCoord = (float)x / _width * Scale / seda; var yCoord = (float)y / _height * Scale / sedb; _heightMap[x, y] = Mathf.PerlinNoise(xCoord, yCoord); //Debug.Log($"sed = {seda}\\{sedb} xC = {xCoord} yC = {yCoord} height = {heightMap[x, y]}"); } } } //海陆层使用的地形平滑工具 private void SmoothHeightMap() { for (var iteration = 0; iteration < SmoothIterations; iteration++) { var newHeightMap = new float[_width, _height]; for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { // 计算该位置的邻域平均值 var average = GetAverageHeight(x, y); newHeightMap[x, y] = average; } } _heightMap = newHeightMap; } } // 获取该位置的邻域平均高度值 private float GetAverageHeight(int x, int y) { var total = 0f; var count = 0; // 获取周围的邻域高度值 for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { var nx = x + dx; var ny = y + dy; if (nx < 0 || nx >= _width || ny < 0 || ny >= _height) continue; total += _heightMap[nx, ny]; count++; // 确保在有效范围内 } } return total / count; } //归一化处理高度 private void NormalizeHeightMap() { var minHeight = Mathf.Infinity; var maxHeight = -Mathf.Infinity; // 计算最小值和最大值 for (var x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { if (_heightMap[x, y] < minHeight) minHeight = _heightMap[x, y]; if (_heightMap[x, y] > maxHeight) maxHeight = _heightMap[x, y]; } } // 将高度图归一化到 [0, 1] 范围 for (var x = 0; x < _width; x++) { for (var y = 0; y < _height; y++) { _heightMap[x, y] = (_heightMap[x, y] - minHeight) / (maxHeight - minHeight); } } } //生成湖泊 private void GenerateLakes() { //Step #1 每次寻找一个最高的山,开始制造河流,每次流往附近最低的格子,直到格子周围没有比自己更低的格子,停下。 //每次找的山头,周围2格内不能有水流 List<(Vector2Int pos, float height)> sorth = GetSortedTilesByHeight(_heightMap); //目前先暂定river最多占掉0.05的陆地格子 int riverCount = (int)(sorth.Count * 0.05); for (int i = sorth.Count - 1; i >= 0; i--) if(sorth[i].height <= _landThreshold) { riverCount = (int)((sorth.Count - i) * 0.05); if (i * 2 < _width * _height) { //30%的概率是干旱图,70%的概率是多河图 if (Random.Range(0f, 1f) < 0.7) { riverCount = (int)((sorth.Count - i) * 0.2); //Debug.Log("More River!!"); } } break; } for(int i = sorth.Count - 1;i >= 0 && riverCount > 0; i-- ) { //寻找下一个河流源头 if (!CheckGridRiverHead(sorth[i].pos.x, sorth[i].pos.y, 2)) continue; var x = sorth[i].pos.x; var y = sorth[i].pos.y; for (;riverCount > 0;)//p用来保底 { //当前水流x,y,找四个方向最低的 int tx = x, ty = y; if (x - 1 >= 0 && _heightMap[x - 1, y] < _heightMap[tx, ty] && _heightMap[x - 1, y] > _landThreshold) {tx = x - 1; ty = y; } if (x + 1 < _width && _heightMap[x + 1, y] < _heightMap[tx, ty] && _heightMap[x + 1, y] > _landThreshold) {tx = x + 1; ty = y; } if (y - 1 >= 0 && _heightMap[x, y - 1] < _heightMap[tx, ty]&& _heightMap[x, y - 1] > _landThreshold) {tx = x; ty = y - 1; } if (y + 1 < _height && _heightMap[x, y + 1] < _heightMap[tx, ty] && _heightMap[x, y + 1] > _landThreshold) {tx = x; ty = y + 1; } //让当前格子变为水流 _heightMap[x, y] = 0; riverCount--; //如果不能再流 if (tx == x && ty == y) break; x = tx; y = ty; } } } //给生成湖泊用的函数 给格子排序高度 public static List<(Vector2Int pos, float height)> GetSortedTilesByHeight(float[,] heights) { int width = heights.GetLength(0); int height = heights.GetLength(1); // 使用 LINQ 将二维数组展平、转换、排序并生成列表,一行搞定。 return Enumerable.Range(0, width) .SelectMany(x => Enumerable.Range(0, height) .Select(y => (pos: new Vector2Int(x, y), height: heights[x, y]))) .OrderBy(tile => tile.height) .ToList(); } //给生成湖泊用的函数 ,确认一个点周围x范围内有没有水 public bool CheckGridRiverHead(int X,int Y,int r) { for (var x = X - r; x < X + r; x++) for (var y = Y - r; y < Y + r; y++) { if(x < 0 || x >= _width || y < 0 || y >= _height) return false; if (_heightMap[x, y] <= _landThreshold) return false; } return true; } //在连续大片海洋中生成岛屿 private void GenerateIsland() { for (var x = 1; x < _width - 1; x++) for (var y = 1; y < _height - 1; y++) { var t = GenerateTerrain(x, y); var canBeIsland = false; if (t == TerrainType.DeepSea) { canBeIsland = true; var landNearby = 0; for (var i = -2; i <= 2; i++) for (var j = -2; j <= 2; j++) if (x + i >= 0 && x + i < _width && y + j >= 0 && y + j < _height && GenerateTerrain(x + i, y + j) != TerrainType.DeepSea) landNearby++; if (landNearby > 9) canBeIsland = false; } if (canBeIsland && UnityEngine.Random.Range(0, 100) < 50) _heightMap[x, y] = _landThreshold + 1; } } //生成所有tirbes 以及对应的innergrids private void GenerateTribes() { var cant = new bool[_width, _height]; var count = _width * _height; //剩余多少格子能用 var cityNum = (int)(count / 12); Array.Clear(cant, 0, cant.Length); for (var x = 0; x < _width; x++) for (var y = 0; y < _height; y++) if (_heightMap[x, y] <= _landThreshold || x == 0 || x == _width - 1 || y == 0 || y == _height - 1) { cant[x, y] = true; count--; } for (int c = 0; count > 0 && c <= cityNum; c++) { var choose = (int)UnityEngine.Random.Range(1, count); //每次随机一个可用的格子(序号) //Debug.Log("this time " + count + " choose : " + choose); var tmp = 0; for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { if (cant[x, y]) continue; tmp++; if (tmp != choose) continue; _tribes.Add(new MapPosition(x,y)); for (var xx = -2; xx <= 2; xx++) for (var yy = -2; yy <= 2; yy++) { var nx = x + xx; var ny = y + yy; if (nx < 0 || nx >= _width || ny < 0 || ny >= _height || cant[nx, ny]) continue; cant[nx, ny] = true; // 把新城市方圆2距离的格子都ban了 count--; } break; } if (tmp == choose) break; } if (count <= 0) break; } foreach (var cent in _tribes) { for(int i = cent.X - 1; i<= cent.X + 1 ; i++) for(int j = cent.Y - 1; j<= cent.Y + 1 ; j++) if(i >= 0 && i < _width && j >= 0 && j < _height) _innerCityGrid.Add(new MapPosition(i,j)); } foreach (var cent in _tribes) { for(int i = cent.X - 2; i<= cent.X + 2 ; i++) for(int j = cent.Y - 2; j<= cent.Y + 2 ; j++) if(i >= 0 && i < _width && j >= 0 && j < _height) _outerCityGrid.Add(new MapPosition(i,j)); } //List LandCenters = new List(); //_map.cityCount = map.cityCenters.Count; } private void InitGridMapData(MapData mapData) { //标记innerCity和OnterCity for (int x = 0; x < _width; x++) { for (int y = 0; y < _height; y++) { Vector2 curV2 = new Vector2(x, y); // 生成文明层 var civId = GenerateCivilization(mapData, x, y); CivEnum civEnum = (CivEnum)(civId + 1); InnerOuterCity innerOuterCity = InnerOuterCity.Edge; if (_innerCityGrid.Contains(new MapPosition(x, y))) innerOuterCity = InnerOuterCity.InnerCity; else if (_outerCityGrid.Contains(new MapPosition(x, y))) innerOuterCity = InnerOuterCity.OuterCity; // 生成海陆层(陆地、浅海、深海) var terrain = GenerateTerrain(x, y, civEnum); // 生成地形层(是否有山) var feature = (terrain == TerrainType.Land) ? GenerateFeature(x, y, civEnum) : TerrainFeature.None; //如果是摇篮城市,terrain设置为road if (mapData.GridMap.GetGridDataByPos(x, y, out var gg) && mapData.GetCityDataByGid(gg.Id, out var cc)) feature = TerrainFeature.Road; // 生成植被层(是否有树木) var vegetation = (feature == TerrainFeature.None && terrain == TerrainType.Land) ? GenerateVegetation(x, y, civEnum) : Vegetation.None; // 生成资源层 var resource = GenerateResource(x, y, terrain, feature, vegetation, civEnum, innerOuterCity); //生成四个角的塔 if (HasTower(x, y)) { feature = TerrainFeature.None; resource = ResourceType.Tower; vegetation = Vegetation.None; } // 设置这个地块的所有层信息 //Debug.Log(map.grid[x,y]); if (mapData.GridMap.GetGridDataByPos(x, y, out GridData g)) g.SetGridData(terrain, feature, vegetation, resource, civId); } } } private void CivTerrainFeatureCountControl(MapData mapData) { foreach (var city in mapData.CityMap.CityList) { var grid = city.Grid(mapData); var player = city.Player(mapData); if (grid == null) continue; if(player == null) continue; dir8 = new List() { Vector2.up, Vector2.down, Vector2.left, Vector2.right, Vector2.up + Vector2.right, Vector2.up + Vector2.left, Vector2.down + Vector2.left, Vector2.down + Vector2.right }; //随机打乱dir8的顺序,使得每次强制生成保底的时候,没有明显规律 int n = dir8.Count; while (n > 0) { n--; int k = Random.Range(0,n + 1); (dir8[k], dir8[n]) = (dir8[n], dir8[k]); } dir4 = new List() { Vector2.up, Vector2.down, Vector2.left, Vector2.right, Vector2.up + Vector2.right }; //处理land保底 if (Table.Instance.PlayerDataAssets.GetLandformCount(TerrainType.Land,player.CivEnum, out var landCount)) { var cur = grid.Pos.V2(); int count = 0; foreach (var dir in dir8) { if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Terrain == TerrainType.Land) count++; } //如果land太少 ,要补充 if (count < landCount) { foreach (var dir in dir8) { if (count >= landCount) break; if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Terrain != TerrainType.Land) { //将该海洋格子改为陆地格子 tgrid.Terrain = TerrainType.Land; tgrid.Resource = ResourceType.None; //将该格子上下左右dir4方向的深海都变成浅海 foreach (var dirp in dir4) { if (!mapData.GridMap.GetGridDataByV2(cur + dir + dirp, out var ttgrid)) continue; if (ttgrid.Terrain == TerrainType.DeepSea) ttgrid.Terrain = TerrainType.ShallowSea; } count++; } } } } //处理mountain保底 if (Table.Instance.PlayerDataAssets.GetLandformCount(TerrainFeature.Mountain,player.CivEnum, out var mountainCount)) { var cur = grid.Pos.V2(); int count = 0; foreach (var dir in dir8) { if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Feature == TerrainFeature.Mountain) count++; } //Debug.Log($"原来只有{count}座山脉"); //如果mountain太少 ,要补充 if (count < mountainCount) { foreach (var dir in dir8) { if (count >= mountainCount) break; if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Resource == ResourceType.Tower) continue; if (tgrid.Terrain == TerrainType.Land && tgrid.Feature != TerrainFeature.Mountain) { //将该陆地格子改山脉格子 tgrid.Feature = TerrainFeature.Mountain; tgrid.Vegetation = Vegetation.None; //Debug.Log($"新增山脉位置:{cur+dir}"); count++; } } } //Debug.Log($"新增到{count}座山脉"); } //处理Tree保底 if (Table.Instance.PlayerDataAssets.GetLandformCount(Vegetation.Trees,player.CivEnum, out var treeCount)) { var cur = grid.Pos.V2(); int count = 0; foreach (var dir in dir8) { if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Vegetation == Vegetation.Trees) count++; } //Debug.Log($"原来只有{count}个森林"); //如果tree太少 ,要补充 if (count < treeCount) { foreach (var dir in dir8) { if (count >= treeCount) break; if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Resource == ResourceType.Tower) continue; if (tgrid.Terrain == TerrainType.Land && tgrid.Feature != TerrainFeature.Mountain && tgrid.Vegetation != Vegetation.Trees && tgrid.Resource == ResourceType.None) { //将该陆地格子改山森林格子 tgrid.Vegetation = Vegetation.Trees; //Debug.Log($"新增1个森林位于{cur+dir}"); count++; } } } //Debug.Log($"新增后有{count}个森林"); } //处理Resource保底 var resourceList = new List() {ResourceType.Fish, ResourceType.Animal, ResourceType.Fruit, ResourceType.Metal, ResourceType.Crop }; foreach (var resource in resourceList) { if (Table.Instance.PlayerDataAssets.GetLandformCount(resource,player.CivEnum, innerOuterCity:InnerOuterCity.InnerCity,out var recourceCount)) { var cur = grid.Pos.V2(); int count = 0; foreach (var dir in dir8) { if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Resource == resource) count++; } //Debug.Log($"原来只有{count}个{resource}"); //如果resource太少,要补充 if (count < recourceCount) { foreach (var dir in dir8) { if (count >= recourceCount) break; if (!mapData.GridMap.GetGridDataByV2(cur + dir, out var tgrid)) continue; if (tgrid.Resource == ResourceType.Tower) continue; switch (resource) { case ResourceType.Fish: if (tgrid.Terrain != TerrainType.Land && tgrid.Resource != ResourceType.Fish) { tgrid.Resource = ResourceType.Fish; count++; } break; case ResourceType.Fruit: if (tgrid.Terrain == TerrainType.Land && tgrid.Vegetation != Vegetation.Trees && tgrid.Feature != TerrainFeature.Mountain && tgrid.Resource != ResourceType.Fruit) { tgrid.Resource = ResourceType.Fruit; count++; } break; case ResourceType.Animal: if (tgrid.Vegetation == Vegetation.Trees && tgrid.Resource != ResourceType.Animal) { tgrid.Resource = ResourceType.Animal; count++; } break; case ResourceType.Metal: if (tgrid.Feature == TerrainFeature.Mountain && tgrid.Resource != ResourceType.Metal) { tgrid.Resource = ResourceType.Metal; count++; } break; case ResourceType.Crop: if (tgrid.Terrain == TerrainType.Land && tgrid.Vegetation != Vegetation.Trees && tgrid.Feature != TerrainFeature.Mountain && tgrid.Resource != ResourceType.Crop) { tgrid.Resource = ResourceType.Crop; count++; } break; default: break; } } } //Debug.Log($"新增后有{count}个{resource}"); } } } } private bool HasTower(int x, int y) { if (x == 0 && y == 0) return true; if (x == 0 && y == _height - 1) return true; if (x == _width - 1 && y == 0) return true; if (x == _width - 1 && y == _height - 1) return true; return false; } //生成文明摇篮城市(每个玩家的原始首都) private void GenerateCradleCity(MapData mapData) { //制作文明摇篮地点候选列表 var cityIndices = new System.Collections.Generic.List(); foreach (var c in _tribes) { var nearbyLand = 0; var cx = (int)c.PosId / 1000; var cy = (int)c.PosId % 1000; for (int x = cx - 1; x <= cx + 1; x++) for (int y = cy - 1; y <= cy + 1; y++) if (x >= 0 && x < _width && y >= 0 && y < _height && _heightMap[x, y] > _landThreshold) nearbyLand++; if (nearbyLand > 0) cityIndices.Add(new MapPosition(cx,cy)); } if (cityIndices.Count < mapData.MapConfig.PlayerCount) mapData.MapConfig.PlayerCount = (uint)cityIndices.Count; // 从制作列表随机排序并取前m个 PlayerCivOri = cityIndices .OrderBy(x => Guid.NewGuid()) // 使用 Guid 确保随机性 .Take((int)mapData.MapConfig.PlayerCount) .ToList(); //建立玩家档案,建立具体城市,建立初始单位 int rk = 0; foreach (var p in mapData.PlayerMap.PlayerDataList) { GridData g; mapData.GridMap.GetGridDataByPos(PlayerCivOri[rk].X, PlayerCivOri[rk].Y, out g); //建设一个新城市 CityData c = mapData.AddCityData(g.Id, p.Id); //设置该城市为首都 Main.CityLogic.SetCapital(mapData, c.Id); //设置该玩家的文明摇篮城市为该城市 p.CradleCityId = c.Id; //Main.CityLogic.SetCradle(mapData, c.Id); //TODO grid还没初始化好,这里不应该先建立unit的,应该在grid初始化结束后建单位 //建立文明的开国单位,并额外赋予初始行动点 if(mapData.AddUnitData(g.Id,c.Id,new UnitFullType(UnitType.Warrior,GiantType.None,0),out var newUnit)) newUnit.SetFullAPCPMP(); rk++; } } //返回x,y位置的海陆层信息 private TerrainType GenerateTerrain(int x, int y,CivEnum civ = CivEnum.Common,InnerOuterCity innerOuterCity = InnerOuterCity.All) { // 走柏林噪音判断 var heightValue = _heightMap[x, y]; if (heightValue > _landThreshold) return TerrainType.Land; if (x + 1 < _width && _heightMap[x + 1, y] > _landThreshold) return TerrainType.ShallowSea; if (x - 1 > 0 && _heightMap[x - 1, y] > _landThreshold) return TerrainType.ShallowSea; if (y + 1 < _height && _heightMap[x, y + 1] > _landThreshold) return TerrainType.ShallowSea; if (y - 1 > 0 && _heightMap[x, y - 1] > _landThreshold) return TerrainType.ShallowSea; return TerrainType.DeepSea; } //返回x,y位置的地形层信息 private TerrainFeature GenerateFeature(int x, int y,CivEnum civ = CivEnum.Common,InnerOuterCity innerOuterCity = InnerOuterCity.All) { if (_tribes.Contains(new MapPosition(x, y))) return TerrainFeature.None;//如果是城市中心那必没有山 var table = Table.Instance.PlayerDataAssets; return UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(TerrainFeature.Mountain, civ) ? TerrainFeature.Mountain : TerrainFeature.None; } //返回x,y位置的植被层信息 private Vegetation GenerateVegetation(int x, int y,CivEnum civ = CivEnum.Common,InnerOuterCity innerOuterCity = InnerOuterCity.All) { if (_tribes.Contains(new MapPosition(x,y))) return Vegetation.None;//如果是城市中心那必没有树 var table = Table.Instance.PlayerDataAssets; var a = UnityEngine.Random.Range(0f, 1f); var b = table.GetLandformRate(Vegetation.Trees, civ); //Debug.Log($"{x},{y},{civ},{innerOuterCity} : {a}/{b}, Tree"); return a < b ? Vegetation.Trees : Vegetation.None; } //返回x,y位置的资源层信息 private ResourceType GenerateResource(int x, int y, TerrainType terrain, TerrainFeature feature, Vegetation vegetation,CivEnum civ = CivEnum.Common,InnerOuterCity innerOuterCity = InnerOuterCity.All) { if (_tribes.Contains(new MapPosition(x,y))) return ResourceType.CityCenter; var table = Table.Instance.PlayerDataAssets; //Step #1 不再二环以内的,只能考虑遗迹和海星,且不能有其他资源 if (innerOuterCity == InnerOuterCity.Edge) { //先考虑遗迹 if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Treasure, civ, innerOuterCity)) { //如果遗迹附近有别的遗迹,不连着生成 if (_treasure.Any(P => Math.Abs(P.X - x) + Math.Abs(P.Y - y) <= 2)) return ResourceType.None; _treasure.Add(new MapPosition(x,y)); return ResourceType.Treasure; } //再考虑鲸鱼 if (terrain != TerrainType.Land) { if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Starfish, civ, innerOuterCity)) return ResourceType.Starfish; } return ResourceType.None; } //Step #2 如果是海洋 if (terrain != TerrainType.Land) { //先考虑渔业,再考虑鲸鱼,最后考虑Treasure if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Fish, civ, innerOuterCity)) return ResourceType.Fish; if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Starfish, civ, innerOuterCity)) return ResourceType.Starfish; if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Treasure, civ, innerOuterCity)) { //如果遗迹附近有别的遗迹,不连着生成 if (_treasure.Any(P => Math.Abs(P.X - x) + Math.Abs(P.Y - y) <= 2)) return ResourceType.None; _treasure.Add(new MapPosition(x,y)); return ResourceType.Treasure; } return ResourceType.None; } //Step #3 如果是陆地先处理山,再处理树,最后处理Fruit和Crop if (feature == TerrainFeature.Mountain) { var a = UnityEngine.Random.Range(0f, 1f); var b = table.GetLandformRate(ResourceType.Metal, civ, innerOuterCity); //Debug.Log($"{x},{y},{a}/{b},Metal"); //return UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Metal, civ, innerOuterCity) return a < b ? ResourceType.Metal : ResourceType.None; } if (vegetation == Vegetation.Trees) { var a = UnityEngine.Random.Range(0f, 1f); var b = table.GetLandformRate(ResourceType.Animal, civ, innerOuterCity); //Debug.Log($"{x},{y},{a}/{b},Animal"); return a < b ? ResourceType.Animal : ResourceType.None; } if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Fruit, civ, innerOuterCity)) return ResourceType.Fruit; if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Crop, civ, innerOuterCity)) return ResourceType.Crop; if (UnityEngine.Random.Range(0f, 1f) < table.GetLandformRate(ResourceType.Treasure, civ, innerOuterCity)) { //如果遗迹附近有别的遗迹,不连着生成 if (_treasure.Any(P => Math.Abs(P.X - x) + Math.Abs(P.Y - y) <= 2)) return ResourceType.None; _treasure.Add(new MapPosition(x,y)); return ResourceType.Treasure; } return ResourceType.None; } //返回x,y位置的文化层信息 private uint GenerateCivilization(MapData mapData,int x, int y) { // 简单的随机分配一个文明,或者使用更复杂的算法进行分布 var minDis = 2139062143; var civSeed = -1; var tt = 0; //Debug.Log(PlayerCivOri.Count); foreach (var p in PlayerCivOri) { if (Mathf.Abs(p.X - x) + Mathf.Abs(p.Y - y) < minDis) { minDis = (int)(Mathf.Abs(p.X - x) + Mathf.Abs(p.Y - y)); civSeed = (int)_mapData.PlayerMap.PlayerDataList[tt].PlayerCivId; } else if ((Mathf.Abs(p.X - x) + Mathf.Abs(p.Y - y) == minDis) && UnityEngine.Random.Range(0, 2) == 1) { minDis = (int)(Mathf.Abs(p.X - x) + Mathf.Abs(p.Y - y)); civSeed = (int)_mapData.PlayerMap.PlayerDataList[tt].PlayerCivId; } else if ((Mathf.Abs(p.X - x) + Mathf.Abs(p.Y - y) == minDis + 1) && UnityEngine.Random.Range(0, 3) == 1) { minDis = (int)(Mathf.Abs(p.X - x) + Mathf.Abs(p.Y - y)); civSeed = (int)_mapData.PlayerMap.PlayerDataList[tt].PlayerCivId; } tt++; } if (civSeed == -1) return (uint)UnityEngine.Random.Range(1, mapData.MapConfig.PlayerCount + 1); return (uint)civSeed; } //初始化所有玩家的视野信息 private void InitAllPlayerSight(MapData mapData) { foreach (var cityData in mapData.CityMap.CityList) { mapData.GetPlayerDataByCityId(cityData.Id, out var playerData); mapData.GetGridDataByCityId(cityData.Id, out var gridData); Main.PlayerLogic.UpdateSight_LogicView(mapData, playerData, mapData.GridMap.GetAroundGridIdList(2,gridData,true),false,0.01f); } } private void InitDebugInfo(MapData mapData) { if (DebugCenter.Instance.DebugSelfPlayerAllSight) { System.Collections.Generic.List tt = new System.Collections.Generic.List(); foreach (var gridData in mapData.GridMap.GridList) tt.Add(gridData.Id); Main.PlayerLogic.UpdateSight_LogicView(mapData,mapData.PlayerMap.SelfPlayerData,tt); } if (DebugCenter.Instance.DebugAIAllTech) { foreach (var playerData in mapData.PlayerMap.PlayerDataList) { if (playerData == mapData.PlayerMap.SelfPlayerData) continue; playerData.TechTree.LearnTech(TechType.Fishing, playerData); playerData.TechTree.LearnTech(TechType.Organization, playerData); playerData.TechTree.LearnTech(TechType.Farming, playerData); playerData.TechTree.LearnTech(TechType.Mining, playerData); playerData.TechTree.LearnTech(TechType.Forestry, playerData); playerData.TechTree.LearnTech(TechType.Hunting, playerData); playerData.TechTree.LearnTech(TechType.Smithery, playerData); playerData.TechTree.LearnTech(TechType.Mathematics, playerData); playerData.TechTree.LearnTech(TechType.FreeSpirit, playerData); playerData.TechTree.LearnTech(TechType.Chivalry, playerData); playerData.TechTree.LearnTech(TechType.Sailing, playerData); playerData.TechTree.LearnTech(TechType.Navigation, playerData); playerData.TechTree.LearnTech(TechType.Ramming, playerData); playerData.TechTree.LearnTech(TechType.Riding, playerData); playerData.TechTree.LearnTech(TechType.Archery, playerData); playerData.TechTree.LearnTech(TechType.Spiritualism, playerData); playerData.TechTree.LearnTech(TechType.Construction, playerData); playerData.TechTree.LearnTech(TechType.Meditation, playerData); playerData.TechTree.LearnTech(TechType.Aquatism, playerData); } } if (DebugCenter.Instance.DebugAIMoreMoney) { foreach (var playerData in mapData.PlayerMap.PlayerDataList) { if (playerData == mapData.PlayerMap.SelfPlayerData) continue; playerData.AddCoin(10); } } } //初始化所有玩家的特殊领地技能(目前主要是kaguya) private void InitPlayerSpecialSkill(MapData mapData) { //遍历每一个玩家,处理每一种可能得specialSkill foreach (var player in mapData.PlayerMap.PlayerDataList) { //首先通过Tech 赋予玩家技能 //处理kaguya专属skill if (player.TechTree.CheckIfHasTechAtom(TechAtom.KaguyaFrenchNapoleonicCode)) { //设置为永远亭领地 var cityList = new List(); mapData.GetCityDataListByPlayerId(player.Id,cityList); foreach (var city in cityList) { Main.PlayerLogic.SetCityTerritoryGridSp(mapData,city,GridSpType.KaguyaGrid); //获得首都4格内的遗迹视野 if(city.Id !=player.CradleCityId)continue; var gridList = mapData.GridMap.GetAroundGridData(4, 4, city.Grid(mapData)); var gidList = new List(); foreach(var grid in gridList) if(grid.Resource == ResourceType.Treasure) gidList.Add(grid.Id); Main.PlayerLogic.UpdateSight_LogicView(mapData, player, gidList); } } } } } }