2015-03-18 3 views
0

Постараюсь держать это короткие:Создание эффектов для плеера?

  • У меня есть PlayerEntity класса предоставленного игрового движка, который имеет атрибут move_type
  • move_type может быть установлен в единицу, в то время: MoveTypes.NONE, MoveTypes.FLY, MoveTypes.WALK
  • Я подклассы в PlayerEntity классе, и я хочу, чтобы мой подкласс, чтобы быть в состоянии делать такие вещи, как player.freeze(duration=5)
  • Я хотел бы также иметь специальные эффекты, такие как player.burn(duration=3)

Вот мой первый взять на него:

class Player(game.PlayerEntity): 
    def __init__(self): 
     super().__init__() 
     self._effects = [] 

    def add_effect(self, effect, duration=None): 
     self.effects.append(effect) 
     if duration is not None: 
      delayed(duration, self.remove_effect, effect) 
     self._apply_effects() 

    def remove_effect(self, effect): 
     if effect in self.effects: 
      self.effects.remove(effect) 
     self._apply_effects() 

    def _apply_effects(self): 
     if 'freeze' in self.effects: 
      self.move_type = MoveTypes.NONE 
     elif 'fly' in self.effects: 
      self.move_type = MoveTypes.FLY 
     else: 
      self.move_type = MoveTypes.WALK 
     if 'burn' in self.effects: 
      self.ignite() 
     else: 
      self.extinguish() 

    freeze = lambda self, duration: self.add_effect('freeze', duration) 
    fly = lambda self, duration: self.add_effect('fly', duration) 
    burn = lambda self, duration: self.add_effect('burn', duration) 

Однако, я хотел бы сделать его более гибким, например, имеют Effect класс.

Несколько вопросов У меня возникли проблемы с:

  1. Would Player имеют _effects список и вызвать self._effects[0].apply(self, duration), или будет Effect класса имеют player атрибут и просто вызвать его собственный apply(duration)?
  2. Как я могу взаимодействовать с несколькими эффектами? Player может летать только или быть замороженными, не оба сразу (из-за move_type). Однако burn полностью независимый эффект.
+0

В какой игровой движок вы используете/можете ссылаться на него? Для меня это больше похоже на субъективный вопрос, чем на объективную ответственность. Для 2) одна возможность может состоять в том, чтобы иметь несколько списков (движение [fly, frozen, slowed], attack [attackpeed_slowed, stunned]), а затем определять приоритет на них или делать их fifo/filo. Поэтому я предполагаю, что это больше вопрос о игровом дизайне или где-то «определено», что ожог является независимым, но fly/frozen not (кроме вашего «ума»/идеи для игры). – syntonym

+0

@syntonym Это на самом деле оболочка Python для движка игры C++: https://github.com/Source-Python-Dev-Team/Source.Python/ Причина, по которой ожог независим, обусловлен движком игры; Я могу называть 'player.ignite()' всякий раз, когда захочу. Тем не менее, замораживание и полет выполняются путем установки атрибута 'movetype' игрока, поэтому, если игрок летает (' player.movetype == MoveTypes.FLY'), и я хочу его заморозить, я изменю 'player.movetype = MoveTypes.NONE', и он больше не будет летать. –

+0

@syntonym Вы можете найти класс 'PlayerEntity' из' addons/source-python/packages/source-python/players/entity.py' –

ответ

2
  1. Я бы иметь Effect класс, а затем сохранить список объектов Effect в Player объекта. Вызвать метод в Player, чтобы добавить Effect объектов к этому списку. Перейдите по списку Effect s на каждом обороте/галочке, чтобы проверять стеки, обновлять оставшиеся сроки, удалять любые без оставшейся продолжительности и т. Д.

  2. Вы можете взаимодействовать с несколькими эффектами, создавая пользовательские объекты Effect. Например, если вы хотите, чтобы замороженное состояние позволяло перемещаться и просто увеличивало шанс для этого Player получить критический удар, создайте новый Effect, который определяет поведение, которое вы ищете.

+0

Спасибо за ответ! Я искал что-то похожее на ваш # 1, но пока не придумал рабочего решения. Что приходит на # 2, можете ли вы прочитать мой комментарий к оригинальному сообщению? Я имел в виду, что у меня должны быть разные эффекты 'freeze' и' fly', но класс 'PlayerEntity' игрового движка ограничивает его, поэтому только один может быть эффективным сразу. –

+0

Можете ли вы добавить новый эффект, например 'freeze_brittle', и вызвать ли он метод типа self.congeal()' так же, как 'burn' вызывает' self.ignite() '? Или вы ограничены жестким набором эффектов, определяемых двигателем? Сделайте 'self.effects' и' self._effects' обозначение двух разных списков эффектов или это опечатка? – TigerhawkT3

+0

Я ограничусь движением двигателя. И 'self.effects' был опечаткой :) –

1

Следующий код дает возможность определять новые эффекты при активации/деактивации и создает «категории». Если два эффекта находятся в одной категории, то один из них с более высоким приоритетом будет влиять на игрока. Эффекты в разных категориях независимы.

Существует «недостаток» в реализации, представьте себе, если происходит следующее:

  • откликнется применяется
  • откликнется удаляется не из-за тайм-аута
  • откликнется применяется еще раз до таймаут первой администрации
  • эффект a удален, поскольку была достигнута первая продолжительность администрирования

Это, вероятно, легко исправлено, если Effect превращен в класс/метакласс.

Эффект должен быть действительно класс/метакласс здесь, я только начал писать его таким образом и хотел его закончить. Почему метакласс? Один из способов решения описанной проблемы состоял бы в том, чтобы позволить Effect быть метаклассом, так что Freeze является классом, а одно администрирование будет экземпляром этого класса с задержкой, связанной с этим экземпляром.

from collections import namedtuple, defaultdict 

Effect = namedtuple("Effect", ["activate", "deactivate", "category", "priority", "name"]) 

class Player(game.PlayerEntity): 
    def __init__(self): 
     super().__init__() 
     # Instead of list a priority list could/should be used 
     self._effects = defaultdict(list) 

    def add_effect(self, effect, duration=None): 
     # Check if player allready suffers from effect 
     if effect not in self._effects[effect.category]: 

      # If the new effect has a higher priority than all others, activate it 
      max_priority_effect = max(self._effects, key = lambda effect: effect.priority): 
      if effect.priority > max_priority_effect 
       # Deactivate the old effect to savely change status 
       max_priority_effect.deactivate(self) 
       effect.activate(self) 

      self._effects[effect.category].append(effect) 

     if duration is not None: 
      delayed(duration, remove_effect, effect) 

    def remove_effect(self, effect): 
     if effect.name in self._effects[effect.category]: 
      priority_element = max(self._effects, key = lambda effect: effect.priority) 

      # Might not be optimal? 
      # If Effect is implemented as class do proper __eq__ 
      if effect.name == priority_element.name: 
       # If the effect is the currently active effect deactive it and activate 
       # the effect with the secondmost priority 
       self._effects[effect.category][effect.name].deactivate() 
       max(self._effects, key = lambda effect: effect.priority).activate() 
       # If Effect is implemented as class do proper max() handling 

      del self._effects[effect.category][effect.name] 

#Effects: 
freeze = Effect(
     activate = lambda player: player.move_type = MoveTypes.None, 
     deactivate = lambda player: player.move_type = MoveTypes.WALK, 
     category = "movement", 
     priority = 2, 
     name  = "freeze") 
fly = Effect(
     activate = lambda player: player.move_type = MoveTypes.FLY, 
     deactivate = lambda player: player.move_type = MoveTypes.WALK, 
     category = "movement", 
     priority = 1, 
     name  = "fly") 
burn = Effect(
     activate = lambda player: player.ignite(), 
     deactivate = lambda player: player.extinguish(), 
     category = "other", 
     priority = 0, 
     name  = "burn") 

EDIT: Похоже, я был неправ, и здесь не нужны метаклассы. Ниже приведена реализация с классом Effect. Непроверенные.

from collections import namedtuple, defaultdict 
from functools import total_ordering 

@total_ordering 
class Effect: 

    def __init__(self): 
     super().__init__(self) 
     self.deactivate = self.if_fresh(deactivate) 

    def if_fresh(self, f): 
     if self.fresh: 
      f() 
      self.fresh = False 

    def activate(self, player): 
     # Overwrite me! 
     pass 

    def deactivate(self, player): 
     # Overwrite me! 
     pass 

    def __eq__(self, other): 
     return(self is other) 

    def __lt__(self, other): 
     return(self.priority < other.priority) 

class Burn(Effect): 

    category = "other" 
    priority = "0" 

    def activate(self, player): 
     player.ignite() 

    def deactivate(self, player): 
     player.extinguish() 

[... other effects ... ] 


class Player(game.PlayerEntity): 
    def __init__(self): 
     super().__init__() 
     # Instead of list a priority list could/should be used 
     self._effects = defaultdict(list) 

    def add_effect(self, effect, duration=None): 
     # Check if player allready suffers from effect 
     if effect not in self._effects[effect.category]: 

      # If the new effect has a higher priority than all others, activate it 
      max_priority_effect = max(self._effects[effect.category]) 
      if effect > max_priority_effect: 
       # Deactivate the old effect to savely change status 
       max_priority_effect.deactivate(self) 
       effect.activate(self) 

      self._effects[effect.category].append(effect) 

     if duration is not None: 
      delayed(duration, remove_effect, effect) 

    def remove_effect(self, effect): 
     if effect in self._effects[effect.category]: 
      priority_element = max(self._effects) 

      if effect is priority_element: 
       # If the effect is the currently active effect deactive it and activate 
       # the effect with the secondmost priority 
       self._effects[effect.category][effect].deactivate() 
       max(self._effects.activate()) 

      del self._effects[effect.category][effect] 
+0

Это не ** точно **, что я искал, но он все еще довольно здорово. Я приму немного позже, если не придумаю что-нибудь еще! :) Просто не хочу спешить с принятием –

+0

Можете ли вы дать подробную информацию о том, что вы точно ожидали? Ну, я думаю, это не класс, но его легко переписать как один. – syntonym

+0

Не знаю, категории кажутся довольно странными, возможно, потому, что я никогда не думал о них раньше. Но я думаю, они работают отлично, и я не могу придумать ничего другого :) –