Это Pythonic, чтобы класс отслеживал его экземпляры? - PullRequest
3 голосов
/ 30 марта 2012

Возьмите следующий фрагмент кода

class Missile:
    instances = []

    def __init__(self):
        Missile.instances.append(self)

Теперь возьмите код:

class Hero():
    ...
    def fire(self):
        Missile()

Когда герой стреляет, нужно создать ракету и добавить ее в основной список. Таким образом, объект героя должен ссылаться на список, когда он срабатывает. Вот несколько решений, хотя я уверен, что есть и другие:

  • Сделать список глобальным,
  • Используйте переменную класса (как указано выше) или
  • Пусть объект героя содержит ссылку на список.

Я не опубликовал это на gamedev, потому что мой вопрос на самом деле более общий: считается ли предыдущий код в порядке? Учитывая ситуацию, подобную этой, есть ли более Pythonic решение?

Ответы [ 5 ]

5 голосов
/ 30 марта 2012

Вопросы:

  • Имеет ли Герой дальнейший контроль над ракетой после запуска?
    • Да -> вести список с экземпляром героя
    • Нет -> держи его где-нибудь еще
  • Нужно ли классу ракет знать о уже созданных ракетах, чтобы создать новую ракету или иным образом обрабатывать ракеты?
    • Да -> вести список с классом ракеты
    • Нет -> держи его где-нибудь еще
  • Вы ответили "Нет" на оба вышеуказанных вопроса?
    • Да -> сохранить список как часть игры

В сохранении списка как части класса нет ничего непонятного, если ваши причины имеют для этого смысл.

2 голосов
/ 30 марта 2012

Независимо от того, чтобы быть Pythonic, я бы сказал, что для хорошей ОО-практики класс Hero должен поддерживать список ракет.

(Если я что-то упустил, и один Missile должен был бы знать о других?)

Нечто подобное может подойти:

class Hero():
    def __init__(self):
        self.missiles = []

    def fire(self):
        self.missiles.append(Missile())

Если вам нужен «глобальный» список ракет, а не по одному для каждого Hero, то я бы предложил вместо этого создать статическую переменную-член:

class Hero():
    missiles = []

    def fire(self):
        Hero.missiles.append(Missile())
2 голосов
/ 30 марта 2012

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

Возможно, в вашем случае более разумно, чтобы список принадлежал объекту героя, хотя

1 голос
/ 06 сентября 2012

Позволение персонажу отслеживать снаряды, которые он выпустил, может работать нормально, но это также означает, что всякий раз, когда вы удаляете этого персонажа, его снаряды также исчезают. Если я правильно помню, это то, что произошло на Тиберийском Солнце, когда вы уничтожили парящую MLRS - если у нее были ракеты в полете, когда она взорвалась, они бы исчезли.

Разрешение функции обновления символов возвращать созданные им снаряды, поэтому цикл обновления может помещать их в список снарядов, также может работать очень хорошо. Обработка нескольких снарядов за обновление может быть такой же простой, как и всегда возвращение списка - он может быть пустым или содержать один или несколько снарядов.

Вот что я хотел бы предложить: хранить снаряды и персонажей (героев, союзников, врагов и т. Д.) В объекте World и передавать ссылку на этот объект каждому персонажу, с которым нужно взаимодействовать (путем запуска снарядов). в мир, или проверяя ближайших врагов). Для каждой ракеты, которую запускает ваш герой, он вызывает функцию addProjectile своего мира. Если герою необходимо выполнить другие действия, которые влияют на остальную часть игры, объект World может предоставить для этого функциональность без необходимости загромождать основной цикл обновления специальными случаями.

Конечно, вы не ограничены только одним подходом. Вы можете объединить их, когда вам нужно. Если у вас есть самонаводящиеся снаряды, вы можете дать им ссылку на свою цель, чтобы они могли обновлять свою скорость при каждом вызове обновления. Если у вас есть снаряды, которые не могут повредить тот, который их выпустил, вы можете дать им ссылку на их «владельца». Если персонаж может иметь только 2 снаряда одновременно (как в некоторых старых играх), вы можете попросить персонажей следить за их активными снарядами, чтобы они знали, когда прекратить стрельбу. Вы можете даже позволить снарядам следить за своими «друзьями», если они стреляют во взрыве, чтобы они могли координировать свое движение, чтобы сформировать причудливые стекающиеся образцы. ;)

1 голос
/ 30 марта 2012

Ваш код в порядке, и первые два предложенных вами решения приемлемы (хотя на самом деле не совсем понятно, какое третье: какой список является "списком"?).

В зависимости от ваших потребностей,и если есть много классов, нуждающихся в такой системе отслеживания (например, пули, ракеты, мины ...), вы можете переместить эту логику отслеживания в метакласс (классы, используемые для создания экземпляров классов).

По сути, вы создаете подкласс type класса и создаете свой собственный "конструктор класса", затем вы используете синтаксис:

__metaclass__ = my_metaclass_that_generate_classes_tracking_their_instantiation

в вашем отслеживаемом классе.


РЕДАКТИРОВАТЬ: просто прочитайте ваш комментарий к первоначальному вопросу.Если у вас есть больше сущностей, запускающих ракеты одного и того же класса, то самым чистым образцом для подражания - IMO - было бы наличие каждой сущности (Hero, BadGuy, Allied ...) для сохранения списка ракетных объектов.Он моделирует мир, который вы описываете, и облегчит обслуживание кода ...

HTH!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...