Должна ли сущность управлять своим движением?
В настоящее время я создаю простую пошаговую игру с комнатой, состоящей из двухмерного массива объектов плитки. Это может быть WallTile или FloorTile. У мозаичных объектов есть север, восток, юг и запад. FloorTiles имеет стек объектов, поэтому я могу легко нарисовать верхний объект.
Теперь мне интересно, мой Игрок является Сущностью, когда игрок движется, должен ли он обрабатывать эту логику или Игра, которая удерживает моего Игрока?
В первом случае это будет что-то вроде:
class Player : Entity {
public Tile CurrentLocation
public bool CanMoveTo(Direction) {
// Let's say that direction is East
return CurrentLocation.EastNeighbour == FloorTile
}
// This method does the actual move
public void MoveTo(Direction)
}
Во втором случае это будет так:
class Game {
public Player Player;
public Room Room;
public void Update() {
// Lets say we get direction from some input from somewhere
if Room.TileAt(player.Y, player.X) is FloorTile then MoveThere()
}
}
Я не совсем уверен, какой из двух вариантов самый лучший. Вначале я думаю о первом решении. Любая помощь или советы будут оценены.
Ответы
Нет правильных или неправильных способов делать что-либо. Только способы, которые работают для вас или не работают для вас.
В основной игровой архитектуре существует несколько конкурирующих философий.
A: Объектно-ориентированная архитектура
Каждая сущность должна быть представлена объектом. Эти объекты должны содержать всю свою собственную логику, инкапсулировать свое внутреннее состояние и взаимодействовать с другими объектами через четко определенные интерфейсы. Основной игровой движок просто вызывает методы «Обновить» и «Визуализировать» всех сущностей в цикле, а затем позволяет сущностям делать все остальное.
Когда у вас есть объекты, которые разделяют некоторые функции, вы обычно делаете это посредством наследования - извлекая общие функции в общий базовый класс. Например, вы можете захотеть иметь класс Player и класс Enemy, которые наследуются от класса Combatant, который содержит весь боевой код, и наследуется от Entity, который содержит базовый код для движения. И Enemy, вероятно, будет абстрактным классом, который содержит только логику, общую для всех врагов, с различными типами врагов и их уникальным поведением, реализованными в классах, унаследованных от Enemy.
В основном так, как вы должны делать ООП по книге.
Этот стиль часто встречается у разработчиков, пришедших из разработки приложений, потому что он там преобладает. И то, что работает для приложений, не обязательно полностью неверно для игр.
B: Сущностно-компонентная архитектура
Этот стиль предпочитает композицию наследованию . Сущность - это не один объект, это совокупность объектов, каждый из которых реализует разные функции этой сущности. Итак, у вас нет класса «Player», реализующего все, что может сделать игрок. У вас есть общая сущность с компонентами «Sprite», «Mover», «Shooter», «Hitpoints» и «PlayerInput».
Преимущество этого подхода в том, что компоненты очень легко смешивать и сопоставлять для создания новых видов игровых объектов. Это очень полезно для быстрых итераций в дизайне игры. Это любимый подход некоторых популярных игровых движков. Как, например, Unity.
C: Архитектура сущность-компонент-система
Сущность должна быть набором компонентов, как в архитектуре «Сущность-Компонент». Но в этой архитектуре эти компоненты должны быть просто тупыми держателями данных. Обычно в виде структур только с общедоступными переменными и без методов. Вся логика должна быть в системах. Каждая система отвечает за управление одним типом компонентов или набором компонентов. Например, у вас есть MovementSystem, которая обновляет компонент Position каждого объекта с помощью компонента Movement.
Но это всего лишь упрощение. Если вы хотите узнать больше, ознакомьтесь с вопросом «Что такое чистая ECS?» . Вы также можете посмотреть другие вопросы в нашем теге entity-component-system .
Подход ECS сейчас в моде. Основным аргументом в пользу этого является то, что он позволяет очень аккуратно оптимизировать производительность (особенно когда речь идет о локализации памяти и многопоточности) без ущерба для модульности и скорости итераций подхода Entity-Component. Но недостатком является то, что прочная и гибкая архитектура ECS требует довольно большого количества архитектурного кода, который выполняется «за кулисами» и который может быть трудно реализовать для начинающих.
Какой из них использовать?
Это то, что вам нужно выяснить самостоятельно. Но какой бы подход вы ни выбрали для своей игры, рекомендуется придерживаться его. По возможности избегайте смешивания и сопоставления архитектурных паттернов в вашей игре.
Это в основном зависит от количества данных, проходящих через вашу игровую сеть. Любой массовый многопользовательский режим должен всегда отслеживать, кто и где что делает (иначе последует массовый обман). Однако получение и отправка пакетов от сервера каждому клиенту (так называемый авторизационный сервер) редко бывает практичным для любого количества значимых пользователей. Итак, философия, похоже, заключается в том, насколько логично вы можете заставить игрока контролировать, не затрагивая других игроков. Другими словами, то, что затрагивает вас и только вас (кроме грабежей), может решать клиент. В то время как все, что затрагивает нескольких игроков, должно выполняться сервером. Или, если не обрабатываются, по крайней мере, разрешено до наступления каких-либо последствий.