所以我正在制作一款游戏,所有对象都派生自一个 GameObject 类,看起来像这样;
class GameObject(pygame.sprite.DirtySprite):
actions = dict()
def __init__(self):
pygame.sprite.DirtySprite.__init__(self)
self.rect = None
self.state = None
def update(self):
if callable(self.__class__.actions[self.state]):
#If this key has a function for its element...
self.__class__.actions[self.state](self)
现在,我遇到了另一个与继承有关的问题。观察下面的类,以及从它派生的两个类;
class Bullet(gameobject.GameObject):
FRAME = pygame.Rect(23, 5, 5, 5)
STATES = config.Enum('IDLE', 'FIRED', 'MOVING', 'RESET')
def __init__(self):
gameobject.GameObject.__init__(self)
self.image = config.SPRITES.subsurface(self.__class__.FRAME)
self.rect = self.__class__.START_POS.copy()
self.state = self.__class__.STATES.IDLE
actions = {
STATES.IDLE : None ,
STATES.FIRED : start_moving,
STATES.MOVING : move ,
STATES.RESET : reset ,
}
class ShipBullet(bullet.Bullet):
SPEED = -8
START_POS = pygame.Rect('something')
def __init__(self):
super(self.__class__, self).__init__()
self.add(ingame.PLAYER)
class EnemyBullet(bullet.Bullet):
SPEED = 2
START_POS = pygame.Rect('something else')
def __init__(self):
super(self.__class__, self).__init__()
self.add(ingame.ENEMIES)
除了 None
之外,Bullet.actions
的每个元素(请注意,是静态成员)都是 Bullet
中的一个函数。 Bullet
并不是要自己创建;如果这是 C++,它将是一个抽象类。所以发生的事情是,Bullet
的子类在每一帧搜索 Bullet.actions
以决定下一步做什么,这取决于它们的状态(它们是否移动,它们是否刚刚射击, ETC。)。然而,由于 Bullet.actions
的元素是 Bullet
的 own 方法,它的子类正在执行这些方法而不是它们自己的扩展版本(它调用父方法)。由于内存使用原因,我不想复制这个回调指令。所以,我问这个; 我怎样才能让子类的实例查看充满回调方法的父类字典,如果存在则执行它们自己的版本,如果不存在则执行它们父类的版本?
最佳答案
一个可能的解决方案是存储函数的名称而不是直接引用并使用 getattr
检索正确的引用:
actions = {
STATES.IDLE : None ,
STATES.FIRED : 'start_moving',
STATES.MOVING : 'move' ,
STATES.RESET : 'reset' ,
}
[...]
def update(self):
method_name = self.__class__.actions[self.state]
if method_name and callable(getattr(self, method_name)):
getattr(self, method_name)(self)
为了加速,您可以在初始化对象时预先计算此表:
class Bullet(gameobject.GameObject):
FRAME = pygame.Rect(23, 5, 5, 5)
STATES = config.Enum('IDLE', 'FIRED', 'MOVING', 'RESET')
action_names = {
STATES.IDLE : None ,
STATES.FIRED : 'start_moving',
STATES.MOVING : 'move' ,
STATES.RESET : 'reset' ,
}
def __init__(self):
gameobject.GameObject.__init__(self)
self.image = config.SPRITES.subsurface(self.__class__.FRAME)
self.rect = self.__class__.START_POS.copy()
self.state = self.__class__.STATES.IDLE
# Update actions table using getattr, so we get the correct
# method for subclasses.
self.actions = {}
for state, method_name in self.action_names.items():
if method_name and callable(getattr(self, method_name)):
self.actions[state] = getattr(self, method_name)
else:
self.actions[state] = lambda self: None
def update(self):
self.actions[self.state]()
请注意,由于 __init__
中的代码使用了 getattr
,它可以放在 Bullet.__init__
中并且仅由其他类扩展。由于您已经调用了 super 构造函数,因此无需更改扩展类甚至注释它们。
关于Python:回调问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13505649/