feat: add TicTacToe example project
Implement a complete Tic-Tac-Toe game using OECS to demonstrate ECS patterns, including: - Command pattern for placing marks - System groups for logical updates and rendering - CSV loading for initial board state - Reactivity logging for observing entity and component changes
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
using MessagePack;
|
||||
using OECS;
|
||||
|
||||
namespace TicTacToe;
|
||||
|
||||
/// <summary>
|
||||
/// Places the current player's mark on the cell at (Row, Col).
|
||||
/// Validates that the cell is empty and the game is still playing.
|
||||
/// </summary>
|
||||
[MessagePackObject]
|
||||
public struct PlaceMarkCommand : ICommand
|
||||
{
|
||||
[Key(0)] public int Row;
|
||||
[Key(1)] public int Col;
|
||||
|
||||
public void Execute(World world)
|
||||
{
|
||||
ref var state = ref world.GetSingleton<GameState>();
|
||||
|
||||
if (state.Status != GameStatus.Playing)
|
||||
return;
|
||||
|
||||
// Copy to locals so the lambda in ForEach can capture them
|
||||
// (this is a struct, so `this` cannot be captured directly).
|
||||
int row = Row;
|
||||
int col = Col;
|
||||
|
||||
// Find the cell entity at (Row, Col) that has no Mark.
|
||||
var query = world.Query().With<Cell>().Without<Mark>().Build();
|
||||
Entity? target = null;
|
||||
|
||||
world.ForEach(query, (Entity entity, ref Cell cell) =>
|
||||
{
|
||||
if (cell.Row == row && cell.Col == col)
|
||||
target = entity;
|
||||
});
|
||||
|
||||
if (target == null)
|
||||
return; // Cell already occupied or invalid position.
|
||||
|
||||
// Place the mark.
|
||||
world.AddComponent(target.Value, new Mark { Player = state.CurrentPlayer });
|
||||
world.MarkModified<Mark>(target.Value);
|
||||
|
||||
// Advance turn.
|
||||
state.MoveCount++;
|
||||
state.CurrentPlayer = state.CurrentPlayer == Player.X ? Player.O : Player.X;
|
||||
world.MarkModified<GameState>(World.SingletonEntity);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user