Python 为玩家创造效果?

Python 为玩家创造效果?,python,python-3.x,class-hierarchy,Python,Python 3.x,Class Hierarchy,我会尽量简短地说: 我有一个由游戏引擎提供的PlayerEntity类,它有一个move\u type属性 move\u type可以一次设置为一个:MoveTypes.NONE,MoveTypes.FLY,MoveTypes.WALK 我已经对PlayerEntity类进行了子类化,我希望我的子类能够执行类似player.freeze(duration=5) 我还希望有一些自定义效果,如player.burn(持续时间=3) 这是我的第一个想法: class Player(game.Pla

我会尽量简短地说:

  • 我有一个由游戏引擎提供的
    PlayerEntity
    类,它有一个
    move\u type
    属性
  • move\u type
    可以一次设置为一个:
    MoveTypes.NONE,MoveTypes.FLY,MoveTypes.WALK
  • 我已经对
    PlayerEntity
    类进行了子类化,我希望我的子类能够执行类似
    player.freeze(duration=5)
  • 我还希望有一些自定义效果,如
    player.burn(持续时间=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)
但是,我想让它更灵活,例如有一个
效果

我遇到的几个问题:

  • Player
    是否具有
    \u效果
    列表并调用
    self.\u效果[0]。应用(self,duration)
    ,或者
    Effect
    类是否具有
    Player
    属性并只调用它自己的
    应用(duration)
  • 我将如何与多重效果交互<代码>玩家只能飞行或被冻结,不能同时飞行和冻结(由于
    移动类型
    )。然而,
    burn
    是完全独立的效果
  • 我会有一个
    Effect
    类,然后将
    Effect
    对象列表存储在
    Player
    对象中。在
    Player
    中调用一个方法,将
    Effect
    对象添加到此列表中。在每个回合/勾选中,浏览
    效果的列表,以检查堆栈、更新剩余持续时间、删除任何没有剩余持续时间的,等等

  • 通过创建自定义
    效果
    对象,可以与多种效果交互。例如,如果您想要一个允许移动的冻结状态,并且只增加该
    玩家
    受到暴击的机会,请创建一个新的
    效果
    ,定义您正在寻找的行为

  • 我会有一个
    Effect
    类,然后将
    Effect
    对象列表存储在
    Player
    对象中。在
    Player
    中调用一个方法,将
    Effect
    对象添加到此列表中。在每个回合/勾选中,浏览
    效果的列表,以检查堆栈、更新剩余持续时间、删除任何没有剩余持续时间的,等等

  • 通过创建自定义
    效果
    对象,可以与多种效果交互。例如,如果您想要一个允许移动的冻结状态,并且只增加该
    玩家
    受到暴击的机会,请创建一个新的
    效果
    ,定义您正在寻找的行为

  • 我会有一个
    Effect
    类,然后将
    Effect
    对象列表存储在
    Player
    对象中。在
    Player
    中调用一个方法,将
    Effect
    对象添加到此列表中。在每个回合/勾选中,浏览
    效果的列表,以检查堆栈、更新剩余持续时间、删除任何没有剩余持续时间的,等等

  • 通过创建自定义
    效果
    对象,可以与多种效果交互。例如,如果您想要一个允许移动的冻结状态,并且只增加该
    玩家
    受到暴击的机会,请创建一个新的
    效果
    ,定义您正在寻找的行为

  • 我会有一个
    Effect
    类,然后将
    Effect
    对象列表存储在
    Player
    对象中。在
    Player
    中调用一个方法,将
    Effect
    对象添加到此列表中。在每个回合/勾选中,浏览
    效果的列表,以检查堆栈、更新剩余持续时间、删除任何没有剩余持续时间的,等等

  • 通过创建自定义
    效果
    对象,可以与多种效果交互。例如,如果您想要一个允许移动的冻结状态,并且只增加该
    玩家
    受到暴击的机会,请创建一个新的
    效果
    ,定义您正在寻找的行为


  • 以下代码提供了使用激活/停用定义新效果的可能性,并创建“类别”。如果两个效果属于同一类别,则优先级较高的效果将影响玩家。不同类别的影响是独立的

    实现中存在一个“缺陷”,想象一下如果发生以下情况:

    • 应用效果a
    • 由于超时,效果a被删除而不是
    • 在第一次给药超时之前,再次应用效果a
    • 由于达到第一次给药持续时间,效果a被删除
    如果将
    Effect
    转换为类/元类,这可能很容易解决

    这里的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")
    
    编辑: 看来我错了,这里不需要元类。下面是一个
    效果
    为类的实现。未经测试

    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]
    
    从集合导入namedtuple,defaultdict
    从functools导入总排序
    @总订单
    阶级效应:
    定义初始化(自):
    超级()。\uuuu初始化\uuuuu(自)
    self.deactivate=self.if_fresh(停用)
    def如果_新鲜(自身,f):
    如果self.fresh:
    f()
    self.fresh=False
    def激活(自我,玩家):
    #覆盖我!
    通过
    def停用(自身、玩家):
    #覆盖我!
    通过
    定义(自身、其他):
    返回(自我是他者)
    定义(自身、其他):
    返回(自优先级<其他优先级)
    等级烧伤(效果):
    类别=“其他”