Skip to main content
 首页 » 编程设计

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

2025年05月04日14bjzhanghao

我开始为我正在编写的游戏定义实体类。但是,我希望大量代码重用。我想为不同的功能定义类,然后拥有“具有”其中一些类功能的类。

例如:

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 类,它是 Collidable、Movable、Drawable、Controllable,一个 Invisible Barrier,它只是 Collidable,一个 Background,它是只是 Drawable 等。我听说过许多连接多个类的不同方法(例如通过组合、(多个)继承、接口(interface)等),但我不知道哪种方法最合适和/或 pythonic这种情况。

Mix-ins(多重继承的特例)看起来是我正在寻找的东西(因为 Player 应该是 Collidable、Movable、Drawable 和 Controllable),但在尝试这个过程中,我我发现很难使用 super 将正确的参数传递给正确的 init 函数。

编辑:

我正在使用 python 3.2。

请您参考如下方法:

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 创建一个单独的类,因为它只是定义了一个继承类应该具有的接口(interface)。虽然您在 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