[Fix] ECS

This commit is contained in:
2026-06-07 01:12:10 +07:00
parent 285c11597a
commit 5a58c9031a
16 changed files with 225 additions and 36 deletions
+92 -11
View File
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Minesweeper.Core;
using Minesweeper.ECS.Components;
using Unity.Collections;
@@ -7,6 +8,10 @@ namespace Minesweeper.ECS
{
public sealed class BoardEcsSyncService : IBoardEcsSyncService
{
private readonly Dictionary<int, Entity> cellsByIndex = new Dictionary<int, Entity>();
private int syncedWidth;
private int syncedHeight;
public void ClearBoard()
{
if (!TryGetEntityManager(out var entityManager))
@@ -15,6 +20,9 @@ namespace Minesweeper.ECS
}
ClearCells(entityManager);
cellsByIndex.Clear();
syncedWidth = 0;
syncedHeight = 0;
}
public void SyncBoard(IBoardService boardService)
@@ -24,14 +32,27 @@ namespace Minesweeper.ECS
return;
}
ClearCells(entityManager);
if (syncedWidth != boardService.Width || syncedHeight != boardService.Height || cellsByIndex.Count != boardService.Width * boardService.Height)
{
ClearCells(entityManager);
cellsByIndex.Clear();
syncedWidth = boardService.Width;
syncedHeight = boardService.Height;
}
else
{
ClearChangedTags(entityManager);
}
var boardEntity = GetOrCreateSingleton<BoardConfigComponent>(entityManager);
entityManager.SetComponentData(boardEntity, new BoardConfigComponent
{
Width = boardService.Width,
Height = boardService.Height,
MinesCount = boardService.MinesCount
MinesCount = boardService.MinesCount,
OpenedSafeCellsCount = boardService.OpenedSafeCellsCount,
FlaggedCellsCount = boardService.FlaggedCellsCount,
IsGenerated = ToByte(boardService.IsGenerated)
});
var archetype = entityManager.CreateArchetype(typeof(CellComponent));
@@ -39,16 +60,45 @@ namespace Minesweeper.ECS
for (var i = 0; i < cells.Count; i++)
{
var cell = cells[i];
var entity = entityManager.CreateEntity(archetype);
entityManager.SetComponentData(entity, new CellComponent
var index = ToIndex(cell.X, cell.Y, boardService.Width);
if (!cellsByIndex.TryGetValue(index, out var entity) || !entityManager.Exists(entity))
{
X = cell.X,
Y = cell.Y,
IsMine = ToByte(cell.IsMine),
IsOpened = ToByte(cell.IsOpened),
IsFlagged = ToByte(cell.IsFlagged),
NeighborMines = cell.NeighborMines
});
entity = entityManager.CreateEntity(archetype);
cellsByIndex[index] = entity;
}
SetCell(entityManager, entity, cell, boardService.Width, false);
}
}
public void SyncCells(IReadOnlyList<BoardCellData> cells, IBoardService boardService)
{
if (cells == null || cells.Count == 0 || !TryGetEntityManager(out var entityManager))
{
return;
}
var boardEntity = GetOrCreateSingleton<BoardConfigComponent>(entityManager);
entityManager.SetComponentData(boardEntity, new BoardConfigComponent
{
Width = boardService.Width,
Height = boardService.Height,
MinesCount = boardService.MinesCount,
OpenedSafeCellsCount = boardService.OpenedSafeCellsCount,
FlaggedCellsCount = boardService.FlaggedCellsCount,
IsGenerated = ToByte(boardService.IsGenerated)
});
ClearChangedTags(entityManager);
for (var i = 0; i < cells.Count; i++)
{
var cell = cells[i];
var index = ToIndex(cell.X, cell.Y, boardService.Width);
if (cellsByIndex.TryGetValue(index, out var entity) && entityManager.Exists(entity))
{
SetCell(entityManager, entity, cell, boardService.Width, true);
}
}
}
@@ -87,6 +137,37 @@ namespace Minesweeper.ECS
query.Dispose();
}
private static void ClearChangedTags(EntityManager entityManager)
{
var query = entityManager.CreateEntityQuery(typeof(CellChangedTag));
entityManager.RemoveComponent<CellChangedTag>(query);
query.Dispose();
}
private static void SetCell(EntityManager entityManager, Entity entity, BoardCellData cell, int width, bool markChanged)
{
entityManager.SetComponentData(entity, new CellComponent
{
X = cell.X,
Y = cell.Y,
Index = ToIndex(cell.X, cell.Y, width),
IsMine = ToByte(cell.IsMine),
IsOpened = ToByte(cell.IsOpened),
IsFlagged = ToByte(cell.IsFlagged),
NeighborMines = cell.NeighborMines
});
if (markChanged && !entityManager.HasComponent<CellChangedTag>(entity))
{
entityManager.AddComponent<CellChangedTag>(entity);
}
}
private static int ToIndex(int x, int y, int width)
{
return y * width + x;
}
private static Entity GetOrCreateSingleton<T>(EntityManager entityManager) where T : unmanaged, IComponentData
{
var query = entityManager.CreateEntityQuery(typeof(T));
@@ -7,5 +7,8 @@ namespace Minesweeper.ECS.Components
public int Width;
public int Height;
public int MinesCount;
public int OpenedSafeCellsCount;
public int FlaggedCellsCount;
public byte IsGenerated;
}
}
@@ -0,0 +1,8 @@
using Unity.Entities;
namespace Minesweeper.ECS.Components
{
public struct CellChangedTag : IComponentData
{
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5702c8f40c71e7444a70e7aa73d8a9db
@@ -6,9 +6,11 @@ namespace Minesweeper.ECS.Components
{
public int X;
public int Y;
public int Index;
public byte IsMine;
public byte IsOpened;
public byte IsFlagged;
public int NeighborMines;
}
}
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Minesweeper.Core;
namespace Minesweeper.ECS
@@ -6,6 +7,7 @@ namespace Minesweeper.ECS
{
void ClearBoard();
void SyncBoard(IBoardService boardService);
void SyncCells(IReadOnlyList<BoardCellData> cells, IBoardService boardService);
void SyncGameState(GameState state, bool hasFirstClick);
}
}