Следующий код дает возможность определять новые эффекты при активации/деактивации и создает «категории». Если два эффекта находятся в одной категории, то один из них с более высоким приоритетом будет влиять на игрока. Эффекты в разных категориях независимы.
Существует «недостаток» в реализации, представьте себе, если происходит следующее:
- откликнется применяется
- откликнется удаляется не из-за тайм-аута
- откликнется применяется еще раз до таймаут первой администрации
- эффект 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]
В какой игровой движок вы используете/можете ссылаться на него? Для меня это больше похоже на субъективный вопрос, чем на объективную ответственность. Для 2) одна возможность может состоять в том, чтобы иметь несколько списков (движение [fly, frozen, slowed], attack [attackpeed_slowed, stunned]), а затем определять приоритет на них или делать их fifo/filo. Поэтому я предполагаю, что это больше вопрос о игровом дизайне или где-то «определено», что ожог является независимым, но fly/frozen not (кроме вашего «ума»/идеи для игры). – syntonym
@syntonym Это на самом деле оболочка Python для движка игры C++: https://github.com/Source-Python-Dev-Team/Source.Python/ Причина, по которой ожог независим, обусловлен движком игры; Я могу называть 'player.ignite()' всякий раз, когда захочу. Тем не менее, замораживание и полет выполняются путем установки атрибута 'movetype' игрока, поэтому, если игрок летает (' player.movetype == MoveTypes.FLY'), и я хочу его заморозить, я изменю 'player.movetype = MoveTypes.NONE', и он больше не будет летать. –
@syntonym Вы можете найти класс 'PlayerEntity' из' addons/source-python/packages/source-python/players/entity.py' –