Pythonic在游戏实体类中实现代码重用的方法
我开始为我正在编写的游戏定义我的实体类。但是,我需要大量代码重用。我想为不同的功能定义类,然后让类“拥有”这些类中的一些功能 例如:Pythonic在游戏实体类中实现代码重用的方法,python,oop,mixins,Python,Oop,Mixins,我开始为我正在编写的游戏定义我的实体类。但是,我需要大量代码重用。我想为不同的功能定义类,然后让类“拥有”这些类中的一些功能 例如: class Collidable: def handle_collision(other, incident_vector): pass def __init__(self, shape): self.shape = shape class Movable: def update_position(sel
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
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)
class Player(Collidable, Movable, Drawable, Controllable):
def __init__(name, **kwargs):
self.name = name
super(Player, self).__init__(**kwargs)
然后有一个Player
类,它是可碰撞的、可移动的、可绘制的、可控制的,一个看不见的屏障
它是唯一可碰撞的,一个背景
它是唯一可绘制的,等等。我听说过许多连接多个类的不同方式,(比如通过组合、(多重)继承、接口等),但我不知道在这种情况下,哪一种方法最合适和/或最适合
Mix-ins(多重继承的特例)看起来就是我想要的(因为玩家应该是可碰撞的、可移动的、可绘制的和可控制的),但是在尝试这一点时,我发现使用super
将正确的参数传递给正确的init函数很困难
编辑:
我使用的是python 3.2。混合是一种方法,但您不想对它们调用
\uuuu init\uuuu
:
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
在我看来,controlable
不需要单独的类,因为它只定义了继承类应该具有的接口。虽然在Java等静态类型语言中经常这样做,但在Python中不需要这样做。相反,您只需定义一个key\u down
方法并使用它即可。这就是所谓的duck类型
在示例实现中,这将如下所示:
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
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0
混音是一种方式,但您不想对其调用
\uuuu init\uuuu
:
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
在我看来,controlable
不需要单独的类,因为它只定义了继承类应该具有的接口。虽然在Java等静态类型语言中经常这样做,但在Python中不需要这样做。相反,您只需定义一个key\u down
方法并使用它即可。这就是所谓的duck类型
在示例实现中,这将如下所示:
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
>>> p = Player(shape='circle', velocity=0.0, acceleration=1.0, image='player.png')
>>> p.shape
'circle'
>>> p.velocity
0.0
>>> p.acceleration
1.0
下面是使用
super()
实现继承的简单方法。为此,您将始终需要使用关键字参数创建Player
(以及从***类继承的其他类)的实例。每个基类将从kwargs
中删除它正在使用的任何关键字参数,并将其余的参数传递到mro中的下一个\uuuuuu init\uuuuu()
,例如:
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
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)
class Player(Collidable, Movable, Drawable, Controllable):
def __init__(name, **kwargs):
self.name = name
super(Player, self).__init__(**kwargs)
然后您可以定义您的Player
类:
class Player(Collidable, Movable, Drawable, Controllable):
pass
然后像这样使用它:
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
>>> 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
类的其他实例变量,您可以定义一个类似于其他类的\uuu init\uuuu()
,例如:
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
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)
class Player(Collidable, Movable, Drawable, Controllable):
def __init__(name, **kwargs):
self.name = name
super(Player, self).__init__(**kwargs)
下面是使用
super()
实现继承的简单方法。为此,您将始终需要使用关键字参数创建Player
(以及从***类继承的其他类)的实例。每个基类将从kwargs
中删除它正在使用的任何关键字参数,并将其余的参数传递到mro中的下一个\uuuuuu init\uuuuu()
,例如:
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
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)
class Player(Collidable, Movable, Drawable, Controllable):
def __init__(name, **kwargs):
self.name = name
super(Player, self).__init__(**kwargs)
然后您可以定义您的Player
类:
class Player(Collidable, Movable, Drawable, Controllable):
pass
然后像这样使用它:
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
>>> 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
类的其他实例变量,您可以定义一个类似于其他类的\uuu init\uuuu()
,例如:
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
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)
class Player(Collidable, Movable, Drawable, Controllable):
def __init__(name, **kwargs):
self.name = name
super(Player, self).__init__(**kwargs)
哇,我非常喜欢。也解决了我的游戏中的一些问题:)不过,我想知道这种方法有多标准。定义“init的私有版本”是否被认为是一种良好的实践?在我看来,代码仍然可以使用标准的init方法。而不是
self.init\u可碰撞(…)
,您得到的是可碰撞的。是不是更清晰,使用更标准的方法?干杯我为什么不给他们打电话?这是为了回答为正确的类提供正确的参数的问题吗?我可以通过使用**kwargs参数来解决这个问题吗?@Darthfett:对于新样式的类super(…)。\uuu init\uuu(…)
只有在所有方法都具有相同的签名时才有效。不能指定调用方法的顺序。你当然可以使用另一个答案中的方法,但这样做会失去一些安全性(通常不值得!)@Morlock:我认为这是老式类必须采用的方法,但对于新式类则不鼓励(尽管我不能告诉你为什么,抱歉)。哇,我非常喜欢。也解决了我的游戏中的一些问题:)不过,我想知道这种方法有多标准。定义“init的私有版本”是否被认为是一种良好的实践?在我看来,代码仍然可以使用标准的init方法。而不是self.init\u可碰撞(…)
,您得到的是可碰撞的。是不是更清晰,使用更标准的方法?干杯我为什么不给他们打电话?这是为了回答为正确的类提供正确的参数的问题吗?我可以通过使用**kwargs参数来解决这个问题吗?@Darthfett:对于新样式的类super(…)。\uuu init\uuu(…)
只有在所有方法都具有相同的签名时才有效。不能指定调用方法的顺序。您当然可以使用另一个答案中的方法,但这样做会失去一些安全性(通常不值得!)@Morlock:我认为旧样式的类必须这样做,但新样式的类不鼓励这样做(尽管我无法告诉您原因,抱歉)。我同意这是Python中最自然的实现方式—OOP系统的预期使用方式。只要Player
实例必须将自己的参数传递给父构造函数,这将变得很棘手。然后我们需要kwargs.update({…})
。如果几个参数的名称相同,它会变得更加丑陋…@NiklasB。是的