- 准备工作
- 前言
- 更大的地图
- ECS专题目录
- ECS更新计划
- 作者的话
如果大佬对ECS版的海克斯无限地图感兴趣,不妨参与进来,欢迎Star/Folk源码 0下载Unity编辑器(2019.1.12f1 or 更新的版本),if(已经下载了)continue; 1克隆:git clone https://github.com/cloudhu/HexMapMadeInUnity2019ECS.git --recurse
或下载Zip压缩包 2如果下载的是压缩包,需要先将压缩包解压。然后将HexMapMadeInUnity2019ECS添加到Unity Hub项目中; 3用Unity Hub打开的开源项目:HexMapMadeInUnity2019ECS,等待Unity进行编译工作; 4打开项目后,启动场景在Scenes目录下,打开AdvancedHexMap场景(优化重构的版本)。
首先对地图做了扩展,由原来的一个Mesh,增加到Mesh矩阵。由于我们需要物理组件MeshCollider,这个之前已经提到过了,ECS还没有物理引擎支持,所以目前被迫选择混合开发,这很尴尬,预计明年会有改善。这段时间用ECS开发,我越加觉得面向对象太好用了,简直就是人性化开发。而ECS更偏机器一些,所以反人类,很多东西需要特别去设计数据,否则操作起来特别麻烦,这是我的亲身感受。本来Hex Map就有OOP的实现,无疑是更容易理解的版本,更好做自定义。 总之,我越用ECS,越想弃坑,这也是这两天拖更的原因,陷入深切的自我怀疑,究竟该不该脱坑? 不管怎样,混合开发并非长久之计,如果真的想要开发自己的游戏,这样做实在太冒险了。为了一点性能优势,难道就牺牲整个项目吗?真是食之无味,弃之可惜,过渡阶段的ECS就是这样的鸡肋。 吐槽就到这里吧,也许我根本不应该选择用ECS来做无限地图的开发。
更大的地图前言中说了这么多,就是为了下面的OOP部分做铺垫,更大的地图,意味着不止一个Mesh(Unity中Mesh数组最大能存储65000个顶点),于是我开始改造OOP的结构,新建HexGrid脚本,用来管理地图块Chunk:
///
/// 地图网格,管理地图块
///
public class HexGrid : MonoBehaviour
{
///
/// 地图块的数量
///
public int chunkCountX = 4, chunkCountZ = 3;
///
/// 噪声采样纹理图
///
public Texture2D noiseSource;
///
/// 地图块预设
///
public HexGridChunk chunkPrefab;
///
/// 地图宽度(以六边形为基本单位)
///
private int cellCountX;
///
/// 地图长度(以六边形为基本单位)
///
private int cellCountZ;
///
/// 地图块数组
///
HexGridChunk[] chunks;
#region Mono
private void Awake()
{
cellCountX = chunkCountX * HexMetrics.chunkSizeX;
cellCountZ = chunkCountZ * HexMetrics.chunkSizeZ;
HexMetrics.noiseSource = noiseSource;
CreateChunks();
}
void OnEnable()
{
HexMetrics.noiseSource = noiseSource;
}
// Start is called before the first frame update
void Start()
{
MainWorld.Instance.SetupMap(cellCountX, cellCountZ,chunkCountX);
}
#endregion
///
/// 添加单元到地图块
///
/// 地图块编号
/// 地图块索引
/// 单元索引
/// 单元
public void AddCellToChunk(int chunkId,int chunkIndex,int cellIndex,Entity cell)
{
HexGridChunk chunk = chunks[chunkId];
chunk.AddCell(chunkIndex,cellIndex, cell);
}
///
/// 刷新地图块
///
/// 地图块编号
public void Refresh(int chunkId)
{
HexGridChunk chunk = chunks[chunkId];
chunk.Refresh();
}
///
/// 更新地图块
///
/// 地图块编号
/// 单元索引
/// 颜色
/// 海拔
/// 是否受影响
/// 刷子大小
public void UpdateChunk( int chunkId, int cellIndex, Color color, int elevation,bool affected=false,int brushSize=0)
{
if (chunkId==int.MinValue)
{
return;
}
HexGridChunk chunk = chunks[chunkId];
StartCoroutine(chunk.UpdateChunk(cellIndex,color,elevation,affected,brushSize));
}
///
/// 创建地图块
///
void CreateChunks()
{
chunks = new HexGridChunk[chunkCountX * chunkCountZ];
for (int z = 0, i = 0; z int.MinValue )
{
if (GetChunkIndex(NEIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(NEIndex, NEIndex, 0, false);
}
}
if (neighborsIndexs.EIndex > int.MinValue && GetChunkIndex(neighborsIndexs.EIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(neighborsIndexs.EIndex, neighborsIndexs.EIndex, 0, false);
}
if (neighborsIndexs.SEIndex > int.MinValue && GetChunkIndex(neighborsIndexs.SEIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(neighborsIndexs.SEIndex, neighborsIndexs.SEIndex, 0, false);
}
if (neighborsIndexs.SWIndex > int.MinValue && GetChunkIndex(neighborsIndexs.SWIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(neighborsIndexs.SWIndex, neighborsIndexs.SWIndex, 0, false);
}
if (neighborsIndexs.WIndex > int.MinValue && GetChunkIndex(neighborsIndexs.WIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(neighborsIndexs.WIndex, neighborsIndexs.WIndex, 0, false);
}
if (neighborsIndexs.NWIndex > int.MinValue && GetChunkIndex(neighborsIndexs.NWIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(neighborsIndexs.NWIndex, neighborsIndexs.NWIndex, 0, false);
}
UpdateData data = new UpdateData
{
CellIndex = cellIndex,
NewColor = color,
Elevation = elevation,
NEIndex=NEIndex,
EIndex= neighborsIndexs.EIndex,
SEIndex= neighborsIndexs.SEIndex,
SWIndex= neighborsIndexs.SWIndex,
WIndex= neighborsIndexs.WIndex,
NWIndex= neighborsIndexs.NWIndex
};
for (int i = 0; i int.MinValue && GetChunkIndex(cell.EIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(cell.EIndex, cellIndex, 0, true);
Debug.Log(cellIndex + "影响E:" + cell.EIndex);
}
if (cell.SEIndex > int.MinValue && GetChunkIndex(cell.SEIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(cell.SEIndex, cellIndex, 0, true);
Debug.Log(cellIndex + "影响SE:" + cell.SEIndex);
}
if (cell.SWIndex > int.MinValue && GetChunkIndex(cell.SWIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(cell.SWIndex, cellIndex, 0, true);
Debug.Log(cellIndex + "影响SW:" + cell.SWIndex);
}
if (cell.WIndex > int.MinValue && GetChunkIndex(cell.WIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(cell.WIndex, cellIndex,0, true);
Debug.Log(cellIndex + "影响W:" + cell.WIndex);
}
if (cell.NWIndex > int.MinValue && GetChunkIndex(cell.NWIndex) == int.MinValue)
{
MainWorld.Instance.AffectedChunk(cell.NWIndex, cellIndex, 0, true);
Debug.Log(cellIndex + "影响NW:" + cell.NWIndex);
}
}
}
}
}
///
/// 获取块内索引
///
/// 单元索引
///
private int GetChunkIndex(int cellIndex)
{
if (cellIndex!=int.MinValue)
{
for (int i = 0; i int.MinValue) updateList.Add(updata.NEIndex);
if (updata.EIndex > int.MinValue) updateList.Add(updata.EIndex);
if (updata.SEIndex > int.MinValue) updateList.Add(updata.SEIndex);
if (updata.SWIndex > int.MinValue) updateList.Add(updata.SWIndex);
if (updata.WIndex > int.MinValue) updateList.Add(updata.WIndex);
if (updata.NWIndex > int.MinValue) updateList.Add(updata.NWIndex);
//1.判断并更新自身单元颜色以及相邻单元颜色
Color color = updata.NewColor;
//更新相邻单元的颜色
if (updateList.Contains(neighborsIndex.NEIndex))
{
neighbors.NE = color;
neighbors.NEElevation = updata.Elevation;
}
if (updateList.Contains(neighborsIndex.EIndex))
{
neighbors.E = color;
neighbors.EElevation = updata.Elevation;
}
if (updateList.Contains(neighborsIndex.SEIndex)) {
neighbors.SE = color;
neighbors.SEElevation = updata.Elevation;
}
if (updateList.Contains(neighborsIndex.SWIndex))
{
neighbors.SW = color;
neighbors.SWElevation = updata.Elevation;
}
if (updateList.Contains(neighborsIndex.WIndex) )
{
neighbors.W = color;
neighbors.WElevation = updata.Elevation;
}
if (updateList.Contains(neighborsIndex.NWIndex) )
{
neighbors.NW = color;
neighbors.NWElevation = updata.Elevation;
}
if (updateList.Contains(cellData.Index))//更新自身单元的颜色
{
cellData.Color = color;
cellData.Position.y= updata.Elevation * HexMetrics.elevationStep;
cellData.Elevation = updata.Elevation;
}
updateList.Dispose();
//2.remove UpdateData after Update,therefor NewDataTag need to be added to active CellSystem
CommandBuffer.RemoveComponent(index, entity);
CommandBuffer.AddComponent(index, entity);
}
}
但是这些改进都是非常局限的,因为IComponentData无法储存数组,所以这里没有无限扩充更新的数量,仅限本单元和相邻的六个单元,也就是最多7个单元,如下图所示: 这就是刷子难题,无法像原版OOP实现那样可以使用更大的刷子,而且这个刷子还有Bug,例如在地图块边界的地方时,会造成桥的连接突起。总之ECS的数据很不好处理,也许是我没有设计好的缘故! 就是这样吧,bug越来越多,希望有大佬来帮忙解决!
如果喜欢可以点赞支持一下,谢谢鼓励!如果有什么疑问可以给我留言,有错漏的地方请批评指证! 技术难题?加入开发者联盟:566189328(QQ付费群)提供有限技术探讨,以及,心灵鸡汤Orz! 当然,不需要技术探讨也欢迎加入进来,在这里劈柴、遛狗、聊天、撸猫!( ̄┰ ̄*)