问题描述
||
我偶尔会喜欢从其他项目中休息一下,尝试制作一个经典的基于文本的冒险游戏(这次是在Python中)作为一个有趣的项目,但是我在实现项目系统时总是遇到设计问题。
我希望游戏中的物品从一个基本的“ 0”类降级,其中包含每个物品具有的一些属性,例如损坏和重量。当我尝试向这些项目添加一些功能时,我的问题就开始了。当物品的损坏超过阈值时,应将其销毁。我的问题就在这里:我真的不知道该怎么做到。
由于
del self
不能工作于一百万种不同的原因,(编辑:我故意提供对'del'的使用,因为我知道这是错误的。我知道什么是垃圾回收,而我不是怎么回事。想要。)我应该怎么做(以及其他类似任务)?每个项目是否都应包含对其容器的某种引用(我猜是播放器)和“问”,以便将其自身删除?
首先想到的是一个大字典,其中包含游戏中的每个项目,每个对象都有对该列表的引用,并且两者都有并且知道它自己的唯一ID。我根本不喜欢这种解决方案,我也不认为这是正确的选择。有人有什么建议吗?
编辑:我看到很多人认为我担心垃圾回收。我要说的不是垃圾收集,而是从游戏中移除对象。我不确定应该启动删除操作的对象,等等。
解决方法
我希望您的对象提及其所有父母。然后,当应该销毁它时,它将通知其父母。如果您已经在使用事件系统,那么它应该可以与游戏的其余部分很好地集成在一起。
一种避免强迫父母在删除或添加引用时显式通知对象的好方法是使用某种代理。 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)
。
, 您正在混淆“销毁”概念的两种含义。物品应从“游戏性”的意义上销毁。让垃圾收集器担心何时将其作为对象销毁。
谁提到该物品?也许玩家将其存入库存,或者放置在游戏的房间中。无论哪种情况,您的“清单”或“房间”对象都知道该物料。告诉他们该物品已被销毁(从玩法上讲),让他们处理。也许他们现在将保留对“损坏的”项目的引用。也许他们会跟踪它,但不会向用户显示。也许他们会删除对其的所有引用,在这种情况下,内存中的对象将很快被删除。
面向对象编程的好处在于,您可以将这些过程从Item本身中抽象出来:将消息传递给需要了解的任何人,然后让他们以自己的方式实现销毁Item的含义。
, 一种选择是使用信号系统
首先,我们有一个可重用的类,可让您定义信号
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)
, 假设您在使用该项时调用了一个方法,则始终可以返回一个布尔值,指示其是否损坏。
, 怎么样:
from collections import defaultdict
_items = defaultdict(set)
_owner = {}
class CanHaveItems(object):
@property
def items(self):
return iter(_items[self])
def take(self,item):
item.change_owner(self)
def lose(self,item):
\"\"\" local cleanup \"\"\"
class _nobody(CanHaveItems):
def __repr__(self):
return \'_nobody\'
_nobody = _nobody()
class Destroyed(object):
def __repr__(self):
return \'This is an ex-item!\'
class Item(object):
def __new__(cls,*a,**k):
self = object.__new__(cls)
_owner[self] = _nobody
_items[_nobody].add(self)
self._damage = .0
return self
def destroy(self):
self.change_owner(_nobody)
self.__class__ = Destroyed
@property
def damage(self):
return self._damage
@damage.setter
def damage(self,value):
self._damage = value
if self._damage >= 1.:
self.destroy()
def change_owner(self,new_owner):
old_owner = _owner[self]
old_owner.lose(self)
_items[old_owner].discard(self)
_owner[self] = new_owner
_items[new_owner].add(self)
class Ball(Item):
def __init__(self,color):
self.color = color
def __repr__(self):
return \'Ball(%s)\' % self.color
class Player(CanHaveItems):
def __init__(self,name):
self.name = name
def __repr__(self):
return \'Player(%s)\' % self.name
ball = Ball(\'red\')
ball = Ball(\'blue\')
joe = Player(\'joe\')
jim = Player(\'jim\')
print list(joe.items),\':\',list(jim.items)
joe.take(ball)
print list(joe.items),list(jim.items)
jim.take(ball)
print list(joe.items),list(jim.items)
print ball,_owner[ball],list(jim.items)
ball.damage += 2
print ball,list(jim.items)
print _items,_owner
, 一开始:我没有任何python经验,所以以更一般的方式考虑一下
您的物品不应该知道或不在乎...您的物品应该有一个界面,说它是可破坏的。容器和其他关心可能被破坏的事物的对象可以利用该接口
该可销毁接口可能有一些选择,供消耗对象注册回调或事件,销毁该项目时触发