2011-06-13 13 views
5

De vez en cuando me gusta tomar un descanso de mis otros proyectos para tratar de hacer un clásico juego de aventura basado en texto (en Python, esta vez) como un proyecto divertido, pero Siempre tengo problemas de diseño implementando el sistema de elementos.Administrar elementos en un juego orientado a objetos

Me gustaría que los elementos en el juego desciendan de una clase base Item, que contiene algunos atributos que tiene cada elemento, como el daño y el peso. Mis problemas comienzan cuando intento agregar alguna funcionalidad a estos elementos. Cuando el daño de un elemento supera un umbral, debe destruirse. Y ahí radica mi problema: realmente no sé cómo lograr eso.

Dado que del self no funcionará por un millón de razones diferentes, (Editar: intencionalmente proporciono el uso de 'del' como algo que sé que está mal. Sé lo que es la recolección de basura, y cómo no es lo que quiero.) ¿cómo debo hacer esto (y otras tareas similares)? ¿Debería cada elemento contener algún tipo de referencia a su contenedor (El jugador, supongo) y 'preguntarse' por sí mismo para ser eliminado?

Lo primero que viene a la mente es un gran diccionario que contiene todos los elementos del juego, y cada objeto tendría una referencia a esta lista, y ambos tienen y saben que es una identificación única. No me gusta esta solución en absoluto y no creo que sea la manera correcta de hacerlo. ¿Alguien tiene alguna sugerencia?

EDIT: Estoy viendo a mucha gente pensando que me preocupa la recolección de basura. De lo que estoy hablando no es de recolección de basura, sino de eliminar el objeto del juego. No estoy seguro de qué objetos deben iniciar la eliminación, etc.

Respuesta

0

Suponiendo que llama a un método cuando se utiliza el elemento, siempre puede devolver un valor booleano que indique si está roto.

1

Usted está combinando dos significados de la idea "destruir". El objeto debería ser destruido en un sentido de "juego". Deje que el recolector de basura se preocupe por cuándo destruirlo como un objeto.

¿Quién tiene alguna referencia al artículo? Tal vez el jugador lo tiene en su inventario, o está en una habitación del juego. En cualquier caso, su inventario u objetos de la sala conocen el artículo. Dígales que el artículo ha sido destruido (en un sentido de juego) y déjelos manejar eso. Tal vez ahora mantendrán una referencia a un artículo "roto". Tal vez lo mantendrán al tanto, pero no lo mostrarán al usuario. Quizás eliminarán todas las referencias a él, en cuyo caso el objeto en la memoria pronto será eliminado.

La belleza de la programación orientada a objetos es que puede abstraer estos procesos del Item mismo: pasar los mensajes a quien los necesite y permitirles implementar a su manera lo que significa que el Objeto sea destruido .

+0

No estoy confundido. Entiendo la diferencia entre los dos. Estaba usando el ejemplo 'del' para mostrar lo que _no funciona_ y lo que no quería. Ahora me doy cuenta de que solo causa confusión. –

-1

en un principio: no tengo ninguna experiencia pitón, por lo que pienso acerca de esto de una manera más general

su artículo no deberían ni sabe ni le importa ... su artículo debe tener una interfaz que dice que es algo destruible.contenedores y otros objetos que se preocupan por las cosas que se pueden destruir, pueden hacer uso de esa interfaz

esa interfaz destructible podrían tener alguna opción para consumir objetos para registrar una devolución de llamada o evento, provocada cuando el artículo se destruye

0

¿Qué tal:

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 
2

Me gustaría tener su objeto mantener una referencia a todos sus padres. Luego, cuando debería ser destruido, notificaría a sus padres. Si ya estás usando un sistema de eventos, esto debería integrarse muy bien con el resto del juego.

Una buena manera de evitar forzar a su padre a notificar explícitamente al objeto cada vez que se suelte o agregue la referencia es utilizar algún tipo de proxy. Python admite properties que permitirá que código como self.weapon = Weapon() transfiera realmente el deber de establecer el atributo de arma a la nueva arma a una función definida por el usuario.

Aquí hay un código de ejemplo usando propiedades:

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() 

Ahora bien, si usted está haciendo algún tipo de sistema de inventario, donde un jugador puede tener más de 1 arma y cualquiera de ellos puede ser destruida en cualquier momento , entonces vas a tener que escribir tu propia clase de colección.
Por algo por el estilo, sólo tener en cuenta que x[2] llamadas x.__getitem__(2), x[2] = 5 llamadas x.__setitem__(2, 5) y del x[2] llamadas x.__delitem__(2)

1

Una opción sería utilizar un sistema de señales

En primer lugar, tenemos una clase reutilizable que le permite define una señal

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) 

Su clase de elemento utiliza esta señal para crear una señal destruida que otras clases pueden escuchar.

class Item(object): 
    def __init__(self): 
     self.destroyed = Signal() 

    def destroy(self): 
     self.destroyed.fire(self) 

Y inventario escucha las señales de los artículos y actualiza su estado interno en consecuencia

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) 
+0

Este es un enfoque fantástico, con casos de uso adicionales para la clase Signal. – Jared

Cuestiones relacionadas