Пытаясь разработать компонент обнаружения столкновений для игры, я предложил следующее решение. Я определяю интерфейс ICollideable, который выглядит примерно так:
interface ICollideable
{
Sprite Sprite { get; }
int Damage { get; }
void HandleCollision(ICollideable collidedWith);
}
По сути, любые игровые объекты, которые хотят участвовать в обнаружении столкновений, должны реализовать этот интерфейс, а затем зарегистрироваться в детекторе, который ведет список ICollideables. Когда он обнаруживает столкновение, он вызывает метод HandleCollision для объекта и передает ссылку на объект, с которым столкнулся.
Мне это нравится, потому что это позволяет мне хранить все мои алгоритмы столкновений в одном месте и позволяет игровым объектам самим решать, как обрабатывать столкновения. Но из-за последнего я считаю, что мне нужно проверить базовый тип объекта. Например, я не хочу, чтобы игроки сталкивались друг с другом, поэтому в классе Player может быть что-то вроде:
void HandleCollision(ICollideable collidedWith)
{
if (!(collidedWith is Player)) { // do stuff }
}
и так далее, и мне интересно, говорит ли это, что у меня плохой дизайн и какие могут быть альтернативы.
Второй вопрос, далее по аналогии с первым. В целях оценки, если враг уничтожен снарядом, кто-то должен знать члена-владельца класса «Снаряд». Однако ни одно из моих других сопоставимых элементов не имеет и не нуждается в этом свойстве, поэтому я обнаружил, что хочу сделать это (в Enemy HandleCollision):
void HandleCollision(ICollideable collidedWith)
{
if (collidedWith is Projectile) {
Health -= collidedWith.Damage;
if (Health <= 0) {
Player whoDestroyedMe = (collidedWith as Projectile).FiredBy
// ...
}
}
}
Я понятия не имею, как справиться с этим с помощью лучшего дизайна. Любые идеи будут оценены.
РЕДАКТИРОВАТЬ: Я хотел сосредоточиться на втором вопросе, потому что моя интуиция говорит мне, как решить эту проблему, решит первый вопрос. Что касается первого вопроса, я подумал о способе абстрагировать это поведение. Я мог бы определить перечисление:
enum Team
{
Player,
Enemy,
Neither
}
и ICollideables реализует это свойство. Тогда детектор столкновений просто не регистрирует столкновения между объектами столкновения в одной и той же «Команде». Таким образом, Снаряды Игрока и Игрока будут в одной команде, Снаряды врага и Врага - в другой, а окружение (которое может повредить оба) не может быть ни в одном. Это не должно быть перечислением, может быть целым числом, строкой или чем-то другим, с той идеей, что объекты с одинаковым значением для этого свойства не сталкиваются друг с другом.
Мне нравится эта идея моделирования поведения с простым атрибутом. Например, если я хочу включить «разрешить дружественный огонь», все, что мне нужно сделать, это создать снаряды со значением команды, отличным от значения команды игрока. Однако у меня все же могут быть случаи, когда этого недостаточно. Например, у игрока могут быть щиты, которые временно непроницаемы для снарядов, но не защищают от прямого столкновения с врагом и т. Д.