Как работать со ссылочными типами в DOTS
Вопрос по поводу работы в Unity с использованием DOTS. Пример:
У меня есть игровой объект - скажем космический корабль. Моя задача состоит в том чтобы заставить его курсировать между двумя планетами, на которые он мог бы приземляться и с которых он мог бы взлетать.
По сути я реализовал для планеты следующее:
public class Planet : IPlanet
{
public SpaceshipsDock SpaceshipsDock { get; set; }
private void Start()
{
SpaceshipsDock = new SpaceshipsDock();
}
private void Update()
{
}
}
где SpaceshipsDock:
public class SpaceshipsDock
{
public int Tier { get; private set; }
public int DockSize { get; set; }
public List<ISpaceship> Spaceships { get; private set; } = new List<ISpaceship>();
public Queue<ISpaceship> LandingQueue { get; private set; } = new Queue<ISpaceship>();
public SpaceshipsDock()
{
DockSize = 1;
Tier = 1;
}
public void AcceptLandingRequest(ISpaceship spaceship) {
if (Spaceships.Count < DockSize) {
Spaceships.Add(spaceship);
spaceship.Land();
return;
}
LandingQueue.Enqueue(spaceship);
}
public void SendToFlight(ISpaceship spaceship) {
Spaceships.Remove(spaceship);
spaceship.Fly();
if (LandingQueue.Count > 0)
{
var pendingShip = LandingQueue.Dequeue();
Spaceships.Add(pendingShip);
pendingShip.Land();
}
}
public void TierUp() {
DockSize += ++Tier * BalanceSettings.DockCapacityMultiplier;
}
}
Однако если планета - игровой объект, и я хочу использовать DOTS, то я должен сделать её struct. Но я не могу сделать этого не погрешив против здравого смысла, т.к. в этой структуре будут жить ссылочные типы, и что ещё хуже - концепция DOTS как я её понимаю состоит в том что сущности могут содержать компоненты, которые содержат в себе данные для обработки системы. И при этом компоненты не должны содержать никакой логики. Просто данные и желательно только типы значения. Если представить что SpaceshipDock это компонент, то возникает вопрос - а как мне избежать логики в нём?
Я могу конечно вынести методы из него в какой ни будь SpaceshipDockService, передавать в него данные, таким образом обойти это ограничение. Это уже выглядит глупо, но ещё глупее то, что не List не Queue в структуре жить не могут.
Мне кажется мой подход в корне неверен. Возможно ООП вообще не следует применять с DOTS, но я не понимаю как лучше это организовать.
А теперь для полноты картины корабль:
public interface ISpaceship
{
SpaceshipFlightPlan FlightPlan { get; }
public void Land();
public void Fly();
}
public enum FlightPlanState {
InProcess,
Finished,
Suspended
}
public class SpaceshipFlightPlan
{
public bool IsLooped { get; set; }
public FlightPlanState PlanState { get; private set; }
public Queue<WayPoint> FlightWaypoints { get; private set; } = new Queue<WayPoint>();
private Queue<WayPoint> FlightWaypointsSaved { get; set; } = new Queue<WayPoint>();
public WayPoint CurrentTargetWaypoint { get; private set; }
public WayPoint HomeWaypoint { get; set; }
public void AddWaypoint(WayPoint wayPoint) {
FlightWaypoints.Enqueue(wayPoint);
FlightWaypointsSaved.Enqueue(wayPoint);
}
public void RemoveWaypoint(WayPoint wayPoint) {
FlightWaypoints = new Queue<WayPoint>(FlightWaypoints.Where(i => i != wayPoint));
FlightWaypointsSaved = new Queue<WayPoint>(FlightWaypoints);
}
public void ClearWaypoints() {
FlightWaypoints.Clear();
FlightWaypointsSaved.Clear();
}
public void OnWayPointReached() {
if(PlanState != FlightPlanState.Finished)
CurrentTargetWaypoint = GetNextWaypoint();
}
public void OnSuspendFlight() {
PlanState = FlightPlanState.Suspended;
CurrentTargetWaypoint = HomeWaypoint;
}
private WayPoint GetNextWaypoint() {
if (!IsLooped) {
if(FlightWaypoints.Count > 0)
return FlightWaypoints.Dequeue();
FlightWaypoints = new Queue<WayPoint>(FlightWaypointsSaved);
return HomeWaypoint;
}
PlanState = FlightPlanState.Finished;
return HomeWaypoint;
}
}
И опять эти данные не могут считаться структурой в полной мере. Я надеялся сделать так:
Есть две планеты. Я задаю кораблю FlightPlan, допустим слетать туда и обратно. После того как я вызываю у планеты метод SendToFlight вызывается нереализованный, но представим что реализованный метод Fly у корабля, который просто должен выставить PlanState - InProcess.
Далее, некая система, которая отвечает за полёты кораблей, FlightSystem, видит при следующем обходе кораблей что этот должен взлететь. Она спавнит его модель рядом с планетой и начинает фрейм за фреймом двигать в сторону CurrentTargetWaypoint, проверяя оставшуюся до пункта назначения дистанцию.
По достижении пункта назначения, когда дистанция становится меньше некоторой минимальной, корабль (опустим для простоты что он может попасть в очередь на посадку), садится на планету. Его модель диспавнится, он появляется в доке. Происходит процесс его разгрузки, после чего он снова взлетает, и летит обратно.
И вот у меня получается смешение подходов. С одной стороны, когда я буду двигать корабль туда сюда, я просто буду менять его LocalToWorld компонент. Но потом у меня остаётся логика взлёта-посадки, и тут вообще не ясно как не сделать глупую реализацию. Ведь на сколько я понимаю механизм работы DOTS - созданный мною объект нивелирует преимущество перед MonoBehaviour, т.к. не возможно сказать какого размера он будет, и жить он будет в куче.
Может кто-то поделится наработками? Что я делаю не так? Может у кого есть проект в котором можно подглядеть? Заранее спасибо!