Pythonic在游戏实体类中使用代码重用的方法

时间:2012-02-13 18:22:36

标签: python oop mixins

我开始为我正在编写的游戏定义我的实体类。但是,我想要重复使用大量代码。我想为不同的功能定义类,然后让类“拥有”这些类的一些功能。

例如:

class Collidable:
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape):
        self.shape = shape

class Movable:
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class Drawable:
    def draw(self):
        pass

    def __init__(self, image):
        self.image = image

class Controllable:
    def key_down(self, key):
        pass

    def __init__(self):
        pass

然后有一个Player类,它是可碰撞的,可移动的,可绘制的,可控制的,Invisible Barrier只有可碰撞的,Background只是可画的,等等。我听说过连接多个类的许多不同方法(例如通过组合,(多个)继承,接口等),但我不知道哪种方式最适合和/或pythonic适用于这种情况。

混合(多重继承的特殊情况)看起来像我正在寻找的(因为播放器应该是一个可碰撞的,可移动的,可绘制的和可控制的),但是在尝试这个时,我'我发现使用super将正确的参数传递给正确的init函数很困难。

修改

我正在使用python 3.2。

2 个答案:

答案 0 :(得分:4)

Mixins是要走的路,但你不想在它们上面调用__init__

class CollidableMixin(object):
    #...
    def init_collidable(self, shape):
        self.shape = shape

class MovableMixin(object):
    #...
    def init_movable(self, velocity, acceleration):
        self.velocity, self.acceleration = velocity, acceleration

class DrawableMixin(object):
    #...
    def init_drawable(self, image):
        self.image = image

我认为,Controllable不需要单独的类,因为它只定义了继承类应具有的接口。虽然你在Java这样的静态类型语言中做了很多,但你不需要在Python中使用它。相反,您只需定义一个key_down方法并完成它。这叫做鸭子打字。

在一个示例实现中,这将是这样的:

class Player(CollidableMixin, DrawableMixin, MovableMixin):
    def __init__(self):
        self.init_collidable(...)
        self.init_drawable(...)
        self.init_movable(...)

    def key_down(self, key):
        # ...

objects = []
objects.append(Player())
# ... add some more objects. Later we iterate through that collection,
# not knowing which of them is a player:
for o in objects:
    try:
        o.key_down(...)
    except AttributeError:
        pass

答案 1 :(得分:3)

这是使用super()实现继承的简单方法。为此,您将始终需要使用关键字参数创建Player(以及从您的***类继承的其他类)的实例。每个基类将从kwargs中删除它使用的任何关键字参数,并将其余参数传递给mro中的下一个__init__(),例如:

class Collidable(object):
    def handle_collision(other, incident_vector):
        pass

    def __init__(self, shape, **kwargs):
        self.shape = shape
        super(Collidable, self).__init__(**kwargs)

class Movable(object):
    def update_position(self):
        self.velocity += self.acceleration
        self.position += self.velocity

    def __init__(self, velocity, acceleration, **kwargs):
        self.velocity, self.acceleration = velocity, acceleration
        super(Movable, self).__init__(**kwargs)

class Drawable(object):
    def draw(self):
        pass

    def __init__(self, image, **kwargs):
        self.image = image
        super(Drawable, self).__init__(**kwargs)

class Controllable(object):
    def key_down(self, key):
        pass

    def __init__(self, **kwargs):
        super(Controllable, self).__init__(**kwargs)

然后你可以定义你的Player类:

class Player(Collidable, Movable, Drawable, Controllable):
    pass

并像这样使用它:

>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0

如果您需要Player类的其他实例变量,您可以定义与其他类相似的__init__(),例如:

class Player(Collidable, Movable, Drawable, Controllable):
    def __init__(name, **kwargs):
        self.name = name
        super(Player, self).__init__(**kwargs)