Python 在面向对象游戏中管理项目
每隔一段时间,我喜欢从我的其他项目中休息一下,尝试制作一个经典的基于文本的冒险游戏(这次是Python)作为一个有趣的项目,但我在实现项目系统时总是遇到设计问题 我想让游戏中的物品从一个基本Python 在面向对象游戏中管理项目,python,oop,Python,Oop,每隔一段时间,我喜欢从我的其他项目中休息一下,尝试制作一个经典的基于文本的冒险游戏(这次是Python)作为一个有趣的项目,但我在实现项目系统时总是遇到设计问题 我想让游戏中的物品从一个基本物品类别下降,包含每个物品都具有的一些属性,例如伤害和重量。当我尝试向这些项目添加一些功能时,我的问题就开始了。当一件物品的伤害超过阈值时,它应该被销毁。这就是我的问题所在:我真的不知道如何做到这一点 由于del self由于无数不同的原因无法工作,(编辑:我故意提供使用“del”的方式,因为我知道这是错误的
物品类别下降,包含每个物品都具有的一些属性,例如伤害和重量。当我尝试向这些项目添加一些功能时,我的问题就开始了。当一件物品的伤害超过阈值时,它应该被销毁。这就是我的问题所在:我真的不知道如何做到这一点
由于del self
由于无数不同的原因无法工作,(编辑:我故意提供使用“del”的方式,因为我知道这是错误的。我知道什么是垃圾收集,以及它如何不是我想要的。)我应该怎么做(以及其他类似的任务)?每个项目是否都应该包含对其容器(我猜是玩家)的某种引用,并“请求”将其自身删除
首先想到的是一个包含游戏中每个项目的大字典,每个对象都会引用这个列表,并且都有并且知道它自己的唯一ID。我一点也不喜欢这个解决方案,我认为这根本不是正确的方法。有人有什么建议吗
编辑:我看到很多人认为我担心垃圾收集。我说的不是垃圾收集,而是从游戏中移除对象。我不确定哪些对象应该开始删除,等等。假设您在使用项时调用一个方法,您总是可以返回一个布尔值,指示它是否已损坏。您混淆了“销毁”概念的两种含义。物品应该在“游戏性”的意义上被销毁。让垃圾收集器担心何时将其作为对象销毁
谁有该项目的参考资料?也许玩家在他的库存中有,或者它在游戏中的一个房间里。无论哪种情况,您的库存或房间对象都知道该项目。告诉他们物品已经被销毁(从游戏性的角度)并让他们处理。也许他们现在会保留一个“坏”项目的引用。也许他们会跟踪它,但不会向用户显示它。也许他们会删除对它的所有引用,在这种情况下,内存中的对象很快就会被删除
面向对象编程的美妙之处在于,您可以将这些过程从项目本身抽象出来:将消息传递给需要知道的人,并让他们以自己的方式实现销毁项目的意义。首先:我没有任何python经验,所以请以更一般的方式考虑这一点
您的物品既不应该知道也不应该关心。。。你的物品应该有一个界面,说明它是可破坏的。容器和其他关心可能被破坏的东西的对象可以使用该接口
该可销毁接口可能有一些选项,用于使用对象注册回调或事件,当项目被销毁时触发该回调或事件如何:
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, ':', _owner[ball], ':', list(jim.items)
print _items, ':', _owner
我会让你的对象保留一个对其所有父对象的引用。然后,当它应该被销毁时,它会通知它的父母。如果您已经在使用一个事件系统,那么它应该与游戏的其余部分很好地集成
避免在删除或添加引用时强制父对象显式通知对象的一个好方法是使用某种代理。Python支持properties
,这将允许像self.wearm=wearm()
这样的代码将为新武器设置武器属性的任务实际移交给用户定义的函数
下面是一些使用属性的示例代码:
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.\uu getitem\uuuuuuuu(2)
,x[2]=5
调用x.\uuuu setitem\uuuuuuuu(2,5)
和del x[2]
调用x.\uuuu delitem\uuuuu2)
一个选项是使用信号系统
首先,我们有一个可重用的类,可以让您定义一个信号
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)
您的item类使用此信号创建其他类可以侦听的已销毁信号
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)
我并不困惑。我理解两者之间的区别。我使用“del”示例来说明什么不起作用,什么我不想要。我现在意识到这只会引起混乱。这是一种非常好的方法,为Signal类提供了额外的用例。