Как вы даете нескольким классам дополнительную функциональность без наследования в AS3?
Я пишу игру на ActionScript, где у меня есть несколько классов, которые должны быть "подходящими" для выстрелов.
Наиболее универсальный класс, от которого наследуются все остальные игровые сущности, - CombatObject; Классы CombatShip, CombatAsteroid и различные другие наследуются от него. Классы CombatAi и CombatPlayer оба наследуются от CombatShip.
Теперь я хочу сделать CombatAi, CombatPlayer и CombatAsteroid доступными для выстрелов, но я не хочу, чтобы они унаследовали их (позже могут появиться CombatShips, которые не должны быть применимыми).
Моя идея теперь заключалась в том, чтобы эти три реализовали интерфейс IHitable, чтобы, когда они сталкиваются с выстрелом, я мог спросить if(hitObject is IHitable)
и если это правда, уничтожить выстрел и нанести урон.
Теперь вопрос в том, будет ли лучше иметь каждый из этих классов
- Реализуйте весь код, необходимый для получения урона (например, проверку щитов, расчет процента урона и т. Д.).
- Пусть все они владеют экземпляром класса
DamageManager
и реализовать функциюgetDamageManager():DamageManager
, который возвращает класс, который обрабатывает все функции, связанные с повреждением - Одним из недостатков (2.) будет то, что каждый CombatShip, CombatAsteroid и т. Д. Должен будет иметь экземпляр DamageManager. Может быть, было бы еще лучше, если бы DamageManager был синглтоном и имел бы ссылку на корабль и данный ему выстрел и позволял ему справляться с остальными?
3 ответа
Mixins - хорошая идея, но ее поддержка в AS3, ну, в общем, имитируется.
Вариант 2 будет работать, но раскрытие экземпляра DamageManager нарушает инкапсуляцию. Вы можете решить эту проблему, добавив метод Hit в ваш интерфейс IHitable. Этот метод будет вызываться вашей игрой, когда что-то попадает в этот объект. Реализация этого метода зависит от объекта. Вы можете реализовать его по-разному для каждого объекта (вариант 1), но вы также можете создать общий класс DamageManager и использовать его для расчета ущерба.
class DamageManager {
public function calculateDamage(...){
// implement your damage logic...
}
}
interface IHitable {
function hit(by:GameObject);
}
И для примера в CombatPlayer
class CombatPlayer implements IHitable
{
private var _damage:DamageManager;
public function CombatPlayer(){
_damage = new DamageManager();
}
public function hit(by:GameObject):void {
_damage.calculateDamage(...);
}
}
Я оставил реализацию DamageManager открытой, так как не знаю, как реализованы ваши объекты, и как вы хотите рассчитать ущерб.
Я думаю, что в идеале DamageManager не должен изменять непосредственно ваш объект. Вы можете передать объект Stat (который содержит информацию о здоровье и щите объекта) вместе с другим объектом, описывающим свойства "нападающего", и DamageManager вернет другой объект Stat, который вы можете использовать для обновления статистики "нападающего".
Надеюсь, что это имеет смысл!
Вариант 1 приведет к большому количеству повторяющегося кода, и это плохо по очевидным причинам.
Вариант 3 будет означать, что весь ваш код столкновения переходит в один класс. С точки зрения инкапсуляции это плохо, потому что в итоге вы получите класс бегемота, который обрабатывает все.
Это оставляет вариант 2 как лучший вариант. Вариант 2 лучше, чем вариант 3, потому что вы можете расширить класс DamageManager для различных типов кораблей и астероидов.
Тем не менее, я также хотел бы представить вариант 4: mixins
Миксины - это функция уровня языка, которая позволяет добавлять общие функции к нескольким классам без наследования. Хотя язык ActionScript 3 не поддерживает миксины, AS3 достаточно гибок, чтобы его можно было смоделировать. Внедрение Mixin или Trait в AS3?
Что касается реализации isHitable getter, в интерфейсе IHitable, это может обеспечить большую гибкость, если вы захотите внести изменения в определенные классы позже в игре, потому что с экземпляром IHitable "is IHitable" всегда будет возвращать true.
В зависимости от типа расчетов и полученных изменений, DamageManager не обязательно должен быть Singleton, вы можете вызвать статический метод, который будет обрабатывать оценку ущерба и возвращать ваш измененный объект.