Как вы даете нескольким классам дополнительную функциональность без наследования в AS3?

Я пишу игру на ActionScript, где у меня есть несколько классов, которые должны быть "подходящими" для выстрелов.

Наиболее универсальный класс, от которого наследуются все остальные игровые сущности, - CombatObject; Классы CombatShip, CombatAsteroid и различные другие наследуются от него. Классы CombatAi и CombatPlayer оба наследуются от CombatShip.

Теперь я хочу сделать CombatAi, CombatPlayer и CombatAsteroid доступными для выстрелов, но я не хочу, чтобы они унаследовали их (позже могут появиться CombatShips, которые не должны быть применимыми).

Моя идея теперь заключалась в том, чтобы эти три реализовали интерфейс IHitable, чтобы, когда они сталкиваются с выстрелом, я мог спросить if(hitObject is IHitable) и если это правда, уничтожить выстрел и нанести урон.

Теперь вопрос в том, будет ли лучше иметь каждый из этих классов

  1. Реализуйте весь код, необходимый для получения урона (например, проверку щитов, расчет процента урона и т. Д.).
  2. Пусть все они владеют экземпляром класса DamageManager и реализовать функцию getDamageManager():DamageManager, который возвращает класс, который обрабатывает все функции, связанные с повреждением
  3. Одним из недостатков (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, вы можете вызвать статический метод, который будет обрабатывать оценку ущерба и возвращать ваш измененный объект.

Другие вопросы по тегам