管理面向对象游戏中的项目

时间:2011-06-13 01:02:59

标签: python oop

每隔一段时间我就想从其他项目中休息一下,尝试将经典冒险基于文本的游戏(在Python中,这次)作为一个有趣的项目,但我总是有设计问题实现项目系统。

我希望游戏中的项目从一个基础Item类下降,包含每个项目具有的一些属性,例如损坏和重量。当我尝试为这些项添加一些功能时,我的问题开始了。当物品的伤害超过阈值时,它应该被摧毁。我的问题就在于:我真的不知道如何实现这一目标。

由于del self因百万种原因不起作用,(编辑:我故意提供'del'作为我知道错误的东西。我知道什么是垃圾收集,以及它不是我想要的。)我应该怎么做(以及其他类似的任务)?每个项目是否应该包含对它的容器的某种引用(我猜这个玩家)并且“要求”自己被删除?

首先想到的是一个包含游戏中每个项目的大字典,每个对象都会引用此列表,并且都拥有并知道它自己的唯一ID。我根本不喜欢这个解决方案,我认为这不是正确的方法。有人有什么建议吗?

编辑:我看到很多人都认为我担心垃圾收集。我所说的不是垃圾收集,而是从游戏玩法中删除对象。我不确定哪些对象应该启动删除等。

6 个答案:

答案 0 :(得分:2)

我希望你的对象能够引用它的所有父母。然后,当它被销毁时,它会通知其父母。如果您已经在使用事件系统,那么这应该与游戏的其余部分很好地集成。

避免强制父级在删除或添加引用时显式通知对象的一种好方法是使用某种代理。 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()

现在,如果您正在进行某种库存系统,玩家可以拥有多于1种武器,并且其中任何一种都可以随时销毁,那么您将不得不编写自己的集合类。
对于类似的内容,请注意x[2]来电x.__getitem__(2)x[2] = 5来电x.__setitem__(2, 5)del x[2]来电x.__delitem__(2)

答案 1 :(得分:1)

你正在混淆“摧毁”这个想法的两个含义。物品应该以“游戏玩法”的意义被摧毁。让垃圾收集器担心何时将其作为对象销毁。

谁有参考物品?也许玩家在他的库存中有它,或者它在游戏中的一个房间里。在任何一种情况下,您的库存或房间对象都知道该项目。告诉他们物品已被摧毁(在游戏玩法意义上)并让他们处理。也许他们现在会提到一个“破碎”的物品。也许他们会跟踪它,但不会将其显示给用户。也许他们会删除对它的所有引用,在这种情况下,内存中的对象很快就会被删除。

面向对象编程的美妙之处在于,您可以将这些过程从Item本身抽象出来:将消息传递给任何需要知道的人,并让他们以自己的方式实现对Item的销毁意味着什么。

答案 2 :(得分:1)

一种选择是使用信号系统

首先,我们有一个可重用的类,可以让你定义一个信号

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)

答案 3 :(得分:0)

假设您在使用该项时调用方法,您可以始终返回一个布尔值,指示它是否已损坏。

答案 4 :(得分:0)

怎么样:

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

答案 5 :(得分:-1)

起初:我没有任何python经验,所以以更一般的方式考虑这个

你的物品既不知道也不在乎......你的物品应该有一个界面,说明它是可以破坏的东西。关注可以销毁的东西的容器和其他对象可以使用该接口

可破坏的接口可以有一些选项来消耗对象来注册回调或事件,当项目被销毁时触发