1112 lines
47 KiB
C#
1112 lines
47 KiB
C#
/*
|
||
* @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<MapPosition> _tribes;
|
||
//用来避免treasure连着生成
|
||
private List<MapPosition> _treasure;
|
||
private List<MapPosition> _innerCityGrid;
|
||
private List<MapPosition> _outerCityGrid;
|
||
public List<MapPosition> PlayerCivOri;
|
||
|
||
public Dictionary<uint, GeoItem> GeoDict;
|
||
public HashSet<uint> UsedGeoId;
|
||
|
||
List<Vector2> dir4 = new List<Vector2>() { Vector2.up, Vector2.right, Vector2.down, Vector2.left };
|
||
List<Vector2> dir8 = new List<Vector2>() { 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;
|
||
GeoDict = new Dictionary<uint, GeoItem>();
|
||
UsedGeoId = new HashSet<uint>();
|
||
foreach(var t in Table.Instance.GeoDataAssets.GeoItemList)
|
||
GeoDict.Add(t.Id,t);
|
||
}
|
||
|
||
public bool GetGeoId(CivEnum civ, GeoBigClass bigType, HashSet<GeoSmallClass> smallTypeSet,out uint id)
|
||
{
|
||
var selected = new List<uint>();
|
||
foreach (var t in GeoDict)
|
||
{
|
||
if (civ != CivEnum.Common && t.Value.CivEnum != civ) continue;
|
||
if(t.Value.GeoBigClass != bigType) continue;
|
||
if(!smallTypeSet.Contains(t.Value.GeoSmallClass )) continue;
|
||
if(UsedGeoId.Contains(t.Key)) continue;
|
||
selected.Add(t.Key);
|
||
}
|
||
|
||
if (selected.Count == 0)
|
||
{
|
||
foreach (var t in GeoDict)
|
||
{
|
||
if (civ != CivEnum.Common && t.Value.CivEnum != civ) continue;
|
||
if(t.Value.GeoBigClass != bigType) continue;
|
||
//水体的话,只能从sea里选择
|
||
if (bigType == GeoBigClass.Water && t.Value.GeoSmallClass != GeoSmallClass.Sea) continue;
|
||
//这一轮 放下smallType的限制
|
||
//if(!smallTypeSet.Contains(t.Value.GeoSmallClass )) continue;
|
||
if(UsedGeoId.Contains(t.Key)) continue;
|
||
selected.Add(t.Key);
|
||
}
|
||
|
||
//如果第二轮还是找不到
|
||
if (selected.Count == 0)
|
||
{
|
||
id = 0;
|
||
return false;
|
||
}
|
||
|
||
}
|
||
id = selected[Random.Range(0, selected.Count)];
|
||
return true;
|
||
}
|
||
|
||
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<MapPosition>();
|
||
_treasure = new List<MapPosition>();
|
||
_innerCityGrid = new List<MapPosition>();
|
||
_outerCityGrid = new List<MapPosition>();
|
||
|
||
//用柏林噪音生成地图高度
|
||
GenerateHeightMap();
|
||
//平滑地图
|
||
SmoothHeightMap();
|
||
//归一化处理地图,均匀分布0~1范围
|
||
NormalizeHeightMap();
|
||
//在连续的大片海洋上生成岛屿
|
||
GenerateIsland();
|
||
//在连续的陆地上生成湖泊
|
||
GenerateLakes();
|
||
//生成所有tribe
|
||
GenerateTribes();
|
||
//创建文明摇篮城市(每个玩家的原始首都)
|
||
GenerateCradleCity(mapData);
|
||
//初始化所有Grid信息
|
||
InitGridMapData(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<Vector2Int> LandCenters = new List<Vector2Int>();
|
||
//_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);
|
||
|
||
}
|
||
}
|
||
//Step #2 生成Geo信息
|
||
for (int x = 0; x < _width; x++)
|
||
{
|
||
for (int y = 0; y < _height; y++)
|
||
{
|
||
if (!mapData.GridMap.GetGridDataByPos(x, y, out GridData grid)) continue;
|
||
Vector2 curV2 = new Vector2(x, y);
|
||
//生成Geo信息,如果是深海,先跳过
|
||
if (grid.Terrain == TerrainType.DeepSea) continue;
|
||
GeoBigClass big = GeoBigClass.Plain;
|
||
HashSet<GeoSmallClass> smallset = new HashSet<GeoSmallClass>() { };
|
||
|
||
bool firstAdd = false;
|
||
if (grid.Terrain != TerrainType.Land)
|
||
{
|
||
firstAdd = true;
|
||
big = GeoBigClass.Water;
|
||
if (CheckGeoLake(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Lake);
|
||
if (CheckGeoRiver(mapData,grid))
|
||
smallset.Add(GeoSmallClass.River);
|
||
if (CheckGeoFjord(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Fjord);
|
||
if(smallset.Count == 0)
|
||
smallset.Add(GeoSmallClass.Sea);
|
||
|
||
}
|
||
|
||
if (grid.Feature == TerrainFeature.Mountain)
|
||
{
|
||
firstAdd = true;
|
||
big = GeoBigClass.Mountain;
|
||
smallset.Add(GeoSmallClass.Hill);
|
||
smallset.Add(GeoSmallClass.Mountain);
|
||
smallset.Add(GeoSmallClass.Volcano);
|
||
}
|
||
|
||
if (grid.Vegetation == Vegetation.Trees)
|
||
{
|
||
firstAdd = true;
|
||
big = GeoBigClass.Forest;
|
||
if (CheckGeoMangrove(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Mangrove);
|
||
if (CheckGeoOasis(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Oasis);
|
||
if (CheckGeoSavanna(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Savanna);
|
||
if (CheckGeoJungle(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Jungle);
|
||
if (smallset.Count == 0)
|
||
{
|
||
smallset.Add(GeoSmallClass.Deciduous);
|
||
smallset.Add(GeoSmallClass.Evergreen);
|
||
smallset.Add(GeoSmallClass.Taiga);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
grid.GeoIdList = new List<uint>();
|
||
//第一次生成
|
||
if (firstAdd && GetGeoId(grid.CivEnum, big, smallset, out var id))
|
||
{
|
||
grid.GeoIdList.Add(id);
|
||
UsedGeoId.Add(id);
|
||
}
|
||
|
||
if (grid.Terrain == TerrainType.Land && grid.Feature != TerrainFeature.Mountain)
|
||
{
|
||
smallset.Clear();
|
||
big = GeoBigClass.Plain;
|
||
if (CheckGeoWetland(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Wetland);
|
||
if (CheckGeoMarsh(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Marsh);
|
||
if (CheckGeoFloodplain(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Floodplain);
|
||
if(CheckGeoPlain(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Plain);
|
||
if (smallset.Count == 0)
|
||
{
|
||
smallset.Add(GeoSmallClass.Grassland);
|
||
smallset.Add(GeoSmallClass.Permafrost);
|
||
smallset.Add(GeoSmallClass.Tundra);
|
||
smallset.Add(GeoSmallClass.Plain);
|
||
}
|
||
|
||
if (CheckGeoDesert(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Desert);
|
||
|
||
//第二次生成
|
||
if (GetGeoId(grid.CivEnum, big, smallset, out id))
|
||
{
|
||
grid.GeoIdList.Add(id);
|
||
UsedGeoId.Add(id);
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
//Step #3 整体处理Geo中的大洋部分
|
||
uint OceanCount = 0;
|
||
Dictionary<Vector2,uint> OceanMark = new Dictionary<Vector2,uint>();
|
||
for (int x = 0; x < _width; x++)
|
||
for (int y = 0; y < _height; y++)
|
||
if (mapData.GridMap.GetGridDataByPos(x, y, out var _grid)
|
||
&& _grid.Terrain != TerrainType.DeepSea)
|
||
OceanMark.Add(new Vector2(x,y),9999);
|
||
|
||
for (int x = 0; x < _width; x++)
|
||
for (int y = 0; y < _height; y++)
|
||
{
|
||
if (!OceanMark.TryGetValue(new Vector2(x, y), out var tmark))
|
||
{
|
||
Queue<Vector2> queue = new Queue<Vector2>();
|
||
OceanMark.Add(new Vector2(x, y),OceanCount);
|
||
queue.Enqueue(new Vector2(x, y));
|
||
var tmptest = 0;
|
||
while (queue.Count > 0 && tmptest < 10000)
|
||
{
|
||
tmptest++;
|
||
var now = queue.Dequeue();
|
||
foreach(var dir in dir8)
|
||
if (mapData.GridMap.GetGridDataByV2(now + dir,out var _g)
|
||
&& !OceanMark.TryGetValue(now + dir, out var _))
|
||
{
|
||
OceanMark.Add(now + dir,OceanCount);
|
||
queue.Enqueue(now + dir);
|
||
}
|
||
}
|
||
OceanCount++;
|
||
}
|
||
}
|
||
|
||
|
||
//OceanMarkSort 按照海域大小,记录了每一片成片相连的海域
|
||
List<Vector2> oceanMarkSort = new List<Vector2>();
|
||
for (int i = 0; i < OceanCount; i++)
|
||
{
|
||
int count = 0;
|
||
for (int x = 0; x < _width; x++)
|
||
for (int y = 0; y < _height; y++)
|
||
if (OceanMark.TryGetValue(new Vector2(x, y), out var tmark) && tmark == i)
|
||
count++;
|
||
oceanMarkSort.Add(new Vector2(count,i));
|
||
}
|
||
oceanMarkSort.Sort((a, b) => a.x.CompareTo(b.x));
|
||
|
||
int oceanId = 1;
|
||
var smallsea = new HashSet<GeoSmallClass>() { GeoSmallClass.Sea };
|
||
//遍历每一片海域,赋予geoId
|
||
for (int t = oceanMarkSort.Count - 1; t >= 0; t--)
|
||
{
|
||
//tmpId 就是本轮要设置的大洋/大海 , 前6大海域走大洋体系
|
||
uint geoId = (uint)oceanId;
|
||
if (oceanId > 6) //剩下的,走大海体系,从所有sea里面挑选就行
|
||
GetGeoId(CivEnum.Common, GeoBigClass.Water, smallsea, out geoId);
|
||
|
||
|
||
for (int x = 0; x < _width; x++)
|
||
for (int y = 0; y < _height; y++)
|
||
{
|
||
if (!mapData.GridMap.GetGridDataByPos(x, y, out GridData g)) continue;
|
||
if (OceanMark.TryGetValue(new Vector2(x, y), out var tmark) &&
|
||
tmark == (uint)oceanMarkSort[t].y)
|
||
{
|
||
g.GeoIdList = new List<uint>();
|
||
g.GeoIdList.Add(geoId);
|
||
}
|
||
}
|
||
oceanId++;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
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<MapPosition>();
|
||
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<uint> tt = new System.Collections.Generic.List<uint>();
|
||
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.TechTree.LearnTech(TechType.Organization);
|
||
playerData.TechTree.LearnTech(TechType.Farming);
|
||
playerData.TechTree.LearnTech(TechType.Mining);
|
||
playerData.TechTree.LearnTech(TechType.Forestry);
|
||
playerData.TechTree.LearnTech(TechType.Hunting);
|
||
playerData.TechTree.LearnTech(TechType.Smithery);
|
||
playerData.TechTree.LearnTech(TechType.Mathematics);
|
||
playerData.TechTree.LearnTech(TechType.FreeSpirit);
|
||
playerData.TechTree.LearnTech(TechType.Chivalry);
|
||
playerData.TechTree.LearnTech(TechType.Sailing);
|
||
playerData.TechTree.LearnTech(TechType.Navigation);
|
||
playerData.TechTree.LearnTech(TechType.Ramming);
|
||
playerData.TechTree.LearnTech(TechType.Riding);
|
||
playerData.TechTree.LearnTech(TechType.Archery);
|
||
playerData.TechTree.LearnTech(TechType.Spiritualism);
|
||
playerData.TechTree.LearnTech(TechType.Construction);
|
||
playerData.TechTree.LearnTech(TechType.Meditation);
|
||
playerData.TechTree.LearnTech(TechType.Aquatism);
|
||
}
|
||
}
|
||
|
||
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<CityData>();
|
||
mapData.GetCityDataListByPlayerId(player.Id,cityList);
|
||
foreach(var city in cityList)
|
||
Main.PlayerLogic.SetCityTerritoryGridSp(mapData,city,GridSpType.KaguyaGrid);
|
||
}
|
||
}
|
||
}
|
||
|
||
public bool GetForestGeoId(MapData mapData,GridData grid,out uint retId)
|
||
{
|
||
var big = GeoBigClass.Forest;
|
||
var smallset = new HashSet<GeoSmallClass>();
|
||
retId = 0;
|
||
if (grid.Vegetation != Vegetation.Trees) return false;
|
||
|
||
if (CheckGeoMangrove(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Mangrove);
|
||
if (CheckGeoOasis(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Oasis);
|
||
if (CheckGeoSavanna(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Savanna);
|
||
if (CheckGeoJungle(mapData,grid))
|
||
smallset.Add(GeoSmallClass.Jungle);
|
||
if (smallset.Count == 0)
|
||
{
|
||
smallset.Add(GeoSmallClass.Deciduous);
|
||
smallset.Add(GeoSmallClass.Evergreen);
|
||
smallset.Add(GeoSmallClass.Taiga);
|
||
}
|
||
|
||
return GetGeoId(grid.CivEnum, big, smallset, out retId);
|
||
}
|
||
|
||
|
||
private bool CheckGeoLake(MapData map, GridData grid)
|
||
{
|
||
//dir4必须都是land
|
||
if (grid.Terrain != TerrainType.ShallowSea) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir4)
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
|| tgrid.Terrain != TerrainType.Land) return false;
|
||
return true;
|
||
|
||
}
|
||
|
||
private bool CheckGeoRiver(MapData map, GridData grid)
|
||
{
|
||
//dir4必须有相对两块是land
|
||
if (grid.Terrain != TerrainType.ShallowSea) return false;
|
||
var cur = grid.Pos.V2();
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir4[0], out var tgrid0))return false;
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir4[1], out var tgrid1))return false;
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir4[2], out var tgrid2))return false;
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir4[3], out var tgrid3))return false;
|
||
if (tgrid0.Terrain == TerrainType.Land && tgrid2.Terrain == TerrainType.Land) return true;
|
||
if (tgrid1.Terrain == TerrainType.Land && tgrid3.Terrain == TerrainType.Land) return true;
|
||
return false;
|
||
}
|
||
|
||
private bool CheckGeoFjord(MapData map, GridData grid)
|
||
{
|
||
//dir8必须有1格山
|
||
if (grid.Terrain != TerrainType.ShallowSea) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir8)
|
||
if (map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
&& tgrid.Feature == TerrainFeature.Mountain) return true;
|
||
return false;
|
||
}
|
||
|
||
private bool CheckGeoWetland(MapData map, GridData grid)
|
||
{
|
||
//dir4必须有1格水
|
||
if (grid.Terrain != TerrainType.Land) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir4)
|
||
if (map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
&& tgrid.Terrain != TerrainType.Land) return true;
|
||
return false;
|
||
}
|
||
|
||
private bool CheckGeoMarsh(MapData map, GridData grid)
|
||
{
|
||
//dir4必须有1格水
|
||
if (grid.Terrain != TerrainType.Land) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir4)
|
||
if (map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
&& tgrid.Terrain != TerrainType.Land) return true;
|
||
return false;
|
||
}
|
||
|
||
private bool CheckGeoOasis(MapData map, GridData grid)
|
||
{
|
||
//dir8不能有水
|
||
if (grid.Vegetation != Vegetation.Trees) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir8)
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
|| tgrid.Terrain != TerrainType.Land) return false;
|
||
return true;
|
||
}
|
||
private bool CheckGeoMangrove(MapData map, GridData grid)
|
||
{
|
||
//dir4必须有2格水
|
||
if (grid.Vegetation != Vegetation.Trees) return false;
|
||
var cur = grid.Pos.V2();
|
||
int water = 0;
|
||
foreach (var dir in dir4)
|
||
if (map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
&& tgrid.Terrain != TerrainType.Land) water ++;
|
||
return water > 1;
|
||
}
|
||
|
||
private bool CheckGeoFloodplain(MapData map, GridData grid)
|
||
{
|
||
//dir4必须有2格水
|
||
if (grid.Terrain != TerrainType.Land) return false;
|
||
var cur = grid.Pos.V2();
|
||
int water = 0;
|
||
foreach (var dir in dir4)
|
||
if (map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
&& tgrid.Terrain != TerrainType.Land) water ++;
|
||
return water > 1;
|
||
}
|
||
|
||
private bool CheckGeoDesert(MapData map, GridData grid)
|
||
{
|
||
//dir8必须无水,自身无田
|
||
if (grid.Terrain != TerrainType.Land) return false;
|
||
if (grid.Resource == ResourceType.Crop) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir8)
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
|| tgrid.Terrain != TerrainType.Land)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
private bool CheckGeoSavanna(MapData map, GridData grid)
|
||
{
|
||
//dir8必须无林
|
||
if (grid.Vegetation != Vegetation.Trees) return false;
|
||
var cur = grid.Pos.V2();
|
||
foreach (var dir in dir8)
|
||
if (!map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
|| tgrid.Vegetation != Vegetation.Trees)
|
||
return false;
|
||
return true;
|
||
}
|
||
|
||
private bool CheckGeoJungle(MapData map, GridData grid)
|
||
{
|
||
//dir8必须>=3林
|
||
if (grid.Vegetation != Vegetation.Trees) return false;
|
||
var cur = grid.Pos.V2();
|
||
var tree = 0;
|
||
foreach (var dir in dir8)
|
||
if (map.GridMap.GetGridDataByV2(cur + dir, out var tgrid)
|
||
&& tgrid.Vegetation == Vegetation.Trees)
|
||
tree++;
|
||
return tree > 2;
|
||
}
|
||
|
||
private bool CheckGeoPlain(MapData map, GridData grid)
|
||
{
|
||
//必须是crop
|
||
if (grid.Terrain != TerrainType.Land) return false;
|
||
if (grid.Resource != ResourceType.Crop) return false;
|
||
return true;
|
||
}
|
||
|
||
}
|
||
} |