Piszę grę w której chciałbym oddzielić logikę od renderingu - obecnie mam 2 projekty: Logic oraz Rendering.
W projekcie Logic mam coś w stylu:
public interface IItemHelper
{
IsInRange(Player player, Item item)
}
public class Player
{
private IItemHelper itemHelper;
public bool TryPickUp(Item item)
{
if (!itemHelper.IsInRange(this, item))
return false;
//pozostałe sprawdzanie
}
}
W projekcie Rendering mam adaptery opakowujące elementy w stylu:
public class Sprite<T>
{
public T LogicElement { get; private set; }
public Vector2 Position { get; set; }
public Sprite(T logicElement)
{
LogicElement = logicElement;
}
//pozostał właściwości potrzebne do rysowania
}
public class ItemAdapter : Sprite<Item>
{
public ItemAdapter(Item tem) : base(item) {}
//medtody związane z renderingiem przedmiotu
}
public class PlayerAdapter : Sprite<Player>
{
public PlayerAdapter(Player player) : base(player) {}
//medtody związane z renderingiem gracza
}
Implementacja IItemHelper
znajduje się także w projekcie Rendering:
public class ItemHelper : IItemHelper
{
public IsInRange(Player player, Item item)
{
var playerAdapter = GetAsAdapter(player);
var itemAdapter = GetAsAdapter(item);
return Math.Distance(playerAdapter.Position, itemAdapter.Position) < 2
}
}
Problem dotyczy właśnie GetAsAdapter
- nie za bardzo wiem w którą stronę z tym iść. Pierwsze rozwiązanie:
- Mamy listę Sprite'ów i ją przeszukujemy dopasowując po LogicElement -
spriteList.First(s => s.LogicElement == element)
- mało eleganckie rozwiązanie i pewnie w dalszej perspektywie mało wydajne. - Elementy logiki trzymają swój Adapter, np.
//Logic
public class Element
{
object Adapter {get; set;}
}
public class Player : Element { }
//Rendering
public class Sprite<T>
{
public T LogicElement { get; private set; }
public Sprite(T logicElement)
{
LogicElement.Adapter = this;
}
}
Jednak to rozwiązanie również wydaje mi się jeszcze brzydsze, lecz zapewne wydajniejsze.
Macie może pomysły jak mógłbym rozwiązać ten problem? A może zupełnie inaczej powinienem do tego podejść?