在面向对象游戏中管理物品
我时不时会停下手头的其他项目,尝试用Python做一个经典的文字冒险游戏,作为一个有趣的项目,但我在设计物品系统时总是遇到问题。
我希望游戏里的物品都能从一个基础的 Item
类派生出来,这个类包含每个物品都有的一些属性,比如伤害和重量。我的问题在于,当我想给这些物品添加一些功能时就开始了。当一个物品的伤害超过某个阈值时,它应该被销毁。这就是我遇到的问题:我不知道该怎么实现这个功能。
因为 del self
由于各种原因是行不通的,(编辑:我故意提到使用 'del' 是错误的。我知道什么是垃圾回收,也知道这不是我想要的。) 那我该怎么做呢(还有其他类似的任务)?每个物品是否应该包含一个指向它容器的引用(我想是玩家)并“请求”自己被删除呢?
我首先想到的是一个大字典,里面包含游戏中的每个物品,每个物品对象都有一个对这个列表的引用,并且都有自己独特的ID。我一点都不喜欢这个方案,我觉得这根本不是正确的做法。有没有人有其他建议?
编辑:我看到很多人以为我在担心垃圾回收。其实我说的不是垃圾回收,而是真正从游戏中移除这个物体。我不确定应该由哪些物体来发起移除等问题。
6 个回答
一种选择是使用信号系统
首先,我们有一个可以重复使用的类,它让你可以定义一个信号
class Signal(object):
def __init__(self):
self._handlers = []
def connect(self, handler):
self._handlers.append(handler)
def fire(self, *args):
for handler in self._handlers:
handler(*args)
你的物品类使用这个信号来创建一个“被销毁”的信号,其他类可以监听这个信号。
class Item(object):
def __init__(self):
self.destroyed = Signal()
def destroy(self):
self.destroyed.fire(self)
而库存则监听来自物品的信号,并相应地更新它的内部状态
class Inventory(object):
def __init__(self):
self._items = []
def add(self, item):
item.destroyed.connect(self.on_destroyed)
self._items.add(item)
def on_destroyed(self, item):
self._items.remove(item)
你把“销毁”这个概念搞混了。这里说的销毁是指在“游戏玩法”上,物品应该被销毁。至于什么时候作为一个对象被真正删除,那就让垃圾回收器来处理吧。
谁在引用这个物品呢?可能是玩家把它放在了自己的背包里,或者它在游戏中的某个房间里。不管是哪种情况,你的背包或者房间对象都知道这个物品的存在。你只需要告诉它们这个物品已经被“销毁”(在游戏玩法上),然后让它们来处理这个事情。也许它们会保留一个“损坏”物品的引用,或者可能会跟踪这个物品,但不再向用户展示。也有可能它们会删除对这个物品的所有引用,这样内存中的对象很快就会被删除。
面向对象编程的美妙之处在于,你可以把这些过程抽象出来,不用让物品自己处理:把消息传递给需要知道的人,让他们以自己的方式来实现物品被销毁的含义。
我建议让你的对象保存所有父对象的引用。这样,当它需要被销毁时,就可以通知它的父对象。如果你已经在使用事件系统,这样的做法会和游戏的其他部分很好地结合在一起。
为了避免让父对象每次添加或删除引用时都必须明确通知子对象,可以使用某种代理。Python支持properties
,这可以让像self.weapon = Weapon()
这样的代码,实际上把设置武器属性的任务交给一个用户定义的函数来处理。
下面是一个使用属性的示例代码:
class Weapon(object):
def __init__(self, name):
self.name = name
self.parent = None
def destroy(self):
if self.parent:
self.parent.weaponDestroyed()
def WeaponRef():
def getWeapon(self):
return self._weapon
def setWeapon(self, newWeapon):
if newWeapon == None: #ensure that this is a valid weapon
delWeapon(self)
return
if hasattr(self, "weapon"): #remove old weapon's reference to us
self._weapon.parent = None
self._weapon = newWeapon
newWeapon.parent = self
def delWeapon(self):
if hasattr(self, "weapon"):
self._weapon.parent = None
del self._weapon
return property(getWeapon, setWeapon, delWeapon)
class Parent(object):
weapon = WeaponRef()
def __init__(self, name, weapon=None):
self.name = name
self.weapon = weapon
def weaponDestroyed(self):
print "%s deleting reference to %s" %(self.name, self.weapon.name)
del self.weapon
w1 = Weapon("weapon 1")
w2 = Weapon("weapon 2")
w3 = Weapon("weapon 3")
p1 = Parent("parent 1", w1)
p2 = Parent("parent 2")
w1.destroy()
p2.weapon = w2
w2.destroy()
p2.weapon = w3
w3.destroy()
如果你在做一个物品管理系统,玩家可以拥有多个武器,并且任何一个武器都可以随时被销毁,那么你需要自己写一个集合类。
在这种情况下,记住x[2]
会调用x.__getitem__(2)
,x[2] = 5
会调用x.__setitem__(2, 5)
,而del x[2]
会调用x.__delitem__(2)
。