OO and game design questions
pavlovevidence at gmail.com
Mon Oct 18 11:54:33 CEST 2010
On Oct 18, 12:28 am, dex <josipmisko... at gmail.com> wrote:
> Every item/character/room is a separate object. Items/characters need
> to have references to room they are in, and room needs to have a list
> of references to items/characters that are contained within. I decided
> to use weak references. That way I can destroy object by deleting it,
> I don't have to destroy all references as well.
You're aware Python can collect reference cycles, correct? You don't
have to delete references; Python will get them eventually. If you
feel you're overengineering things perhaps getting rid of weak
references would be a substantial simplification.
> In each object's
> __init__() that object is added to game_object list, and in each
> __del__() they are removed from game_object list. This mechanism keeps
> them safe from garbage collector. How pythonic is this design?
I would say overriding __del__ is not particularly Pythonic at all.
Using __del__ has some undesirable side-effects (like potential for
memory leaks), and is unreliable (there are different reasons it might
not be called at all). I recommend that only experts deeply familiar
with these issues override it, and then only for objects whose sole
purpose is to own a resource. It's tricky to get right.
Instead, I'd recommend managing the lifetime of all objects (creating
and destroying) through game_object methods. To create an object,
don't call its constructor, call obj =
game_object.create(<object_type>,args) and game_object.destroy(obj).
(If you really want to be strict about it, you can override __init__
to raise an exception (thus disabling the normal way to create an
object), and create the objects in you create method by calling the
class's __new__ method directly.)
More generally, Python's dynamicism makes it hard for the language to
manage resources other than RAM automatically; this is something we
give up to get dynamicism's benefits. Therefore, the Pythonic
approach is to manage resources with constructs like with and
try...finally, although sometimes that's not possible so you have to
just release the resource by hand. In your case, it'd be hard to
manage the "resource", i.e., an entry in youg game_object list, with
try...finally because presumably the object lives for an indefinite
abount of time.
One thing I do in my games--you may or may not find this helpful--is
to distinguish between "lightweight" and "heavyweight" objects.
Lightweight objects do not need any sort of finalization and I use
them whenever possible. Heavyweight objects not only need to be
finalized but it must be explicit. I have a base class for
heavyweights (written in C) that checks if the finalization occurred
as a debugging aid, but it can't clean up automatically for various
> In turn-based games, the order of action execution in battle can give
> unfair advantage to players. For example, if player's arm is crippled
> before his action is executed, he would do less damage. To offset
> this, I first execute all players' actions and calculate effects in
> first pass, then apply the effects in second pass. The effect can be
> health decrease by 15HP, item pick-up, 30p experience gain, etc. This
> means the player deals the same amount of damage no matter what
> happens to him in that turn. The difficult part is keeping track of
> various effects. I had to make separate class for various types of
> effects (ChangeAttributeEffect, GetItemEffect, LooseItemEffect). Each
> class stores weak reference to target object and has apply() method
> that applies the effect to object. I'm not satisfied with this as it's
> limiting, error-prone and uses metaprogramming. Is there a design
> pattern that would remember changes to an object, and apply them
Your objects should have two sets of attributes (beginning of round,
end of round) and a method to copy the end-of-round attributes to the
beginning-of-round area at the end of the round.
More information about the Python-list