Re: OO and game design questions
In article i9lfbu$1a...@localhost.localdomain, Martin Gregorie mar...@address-in-sig.invalid wrote: On Tue, 19 Oct 2010 19:49:20 -0400, Dave Angel wrote: Thanks, that is what I was trying to say. In the same sense that emptying a list makes it quite small, if it's a general purpose object, you just want to remove all the attributes. I think a 'place' (to generalise it) is quite a small object in any case. All it needs to contain is a few lists: - a list of exits, which in some implementations might be simply references to other places, but might usefully be objects with two sides, each having an appearance and a link to the place where that side appears. - a list of fixed objects which only serve to describe the place. - a list of mobile objects that actors can pick up and move - a list of actors who happen to be there. plus a describePlace() method and add(), remove() and getItem() methods for each list. It may be possible to use a single list for all types of object, in which case the object itself would be very small indeed. Maybe you want a rule-based approach: http://eblong.com/zarf/essays/rule-based-if/ -- Aahz (a...@pythoncraft.com) * http://www.pythoncraft.com/ Look, it's your affair if you want to play with five people, but don't go calling it doubles. --John Cleese anticipates Usenet -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
Jonathan Hartley wrote: One common way to store delayed actions is as a lambda (an anonymous function.) Although note that you don't have to use 'lambda' in particular -- functions defined with 'def' can be used the same way. -- Greg -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 20, 12:11 pm, dex josipmisko...@gmail.com wrote: On Oct 20, 12:25 pm, Jonathan Hartley tart...@tartley.com wrote: On Oct 18, 8:28 am, dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. One common way to store delayed actions is as a lambda (an anonymous function.) A lambda defines a new function: , and you can call this function later. The created function has no name, (but you can assign it to a variable to give it a name if you like) and can be called later: So in the game, you could have a collection 'effects', each one will be a lambda: effects = [] At the start of the round, as each entity makes its moves, they add lambdas to this collection. effects.append( lambda: decrease_hp(monster_a, 4) ) effects.append( lambda: lose_item(monster_a, item_b) ) Instead of appending it directly like this, I imagine the lambdas could be returned by the monster's 'act' or 'update' method: class Monster(): def act(self): # blah and finally return lambda: decrease_hp(monster_a, 4) Then for the start of a round, first you ask each monster what action it is going to perform: for monster in room.monsters: effects.append( monster.act() ) Then for the end of the round, call all the lambdas for effect in effects: effect() Mr. Roy Smith already proposed using closures. I already did a similar thing in my code, but instead of decrease_hp() I have AttributeEffect class which is able to modify any attribute (in old RPGs some monsters could drain your intelligence, in my game laser gun hit will decrease HP as well as armor integrity). The first version looks like this (missing few checks): class AttributeEffect(object): '''Effect changes object's attribute by delta''' def __init__(self, obj, attrib, delta): self.obj = obj # reference to object the effect applies to self.attrib = attrib # name of attribute that effect applies to self.delta = delta # change of value for object.attribute def apply(self): value = getattr(self.obj, self.attrib) # todo: try, except value += self.delta setattr(self.obj(), self.attrib, value) Yesterday I learned that Python 3.0 introduces nonlocal keyword which would simplify defining effect functions and passing them along. Nice improvement. Very cool, that looks like it would work. The thing I like about the lambda idea though, is that you don't have to write any classes like AttributeEffect, (and presumably other such classes, like LoseItemEffect, etc.) Instead of *modelling* the different kind of effects that could happen, you just write code that *performs* the desired effect. (e.g. monster.hp -= damage) To my eyes, lambda's are therefore more flexible and require less code. But I could be wrong, and obviously you should do what you think is best for your circumstances. Very best of luck with it. Out of interest, is there anywhere you blog about the game development, or are likely to make
Re: OO and game design questions
On Oct 20, 12:11 pm, dex josipmisko...@gmail.com wrote: On Oct 20, 12:25 pm, Jonathan Hartley tart...@tartley.com wrote: On Oct 18, 8:28 am, dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. One common way to store delayed actions is as a lambda (an anonymous function.) A lambda defines a new function: , and you can call this function later. The created function has no name, (but you can assign it to a variable to give it a name if you like) and can be called later: So in the game, you could have a collection 'effects', each one will be a lambda: effects = [] At the start of the round, as each entity makes its moves, they add lambdas to this collection. effects.append( lambda: decrease_hp(monster_a, 4) ) effects.append( lambda: lose_item(monster_a, item_b) ) Instead of appending it directly like this, I imagine the lambdas could be returned by the monster's 'act' or 'update' method: class Monster(): def act(self): # blah and finally return lambda: decrease_hp(monster_a, 4) Then for the start of a round, first you ask each monster what action it is going to perform: for monster in room.monsters: effects.append( monster.act() ) Then for the end of the round, call all the lambdas for effect in effects: effect() Mr. Roy Smith already proposed using closures. I already did a similar thing in my code, but instead of decrease_hp() I have AttributeEffect class which is able to modify any attribute (in old RPGs some monsters could drain your intelligence, in my game laser gun hit will decrease HP as well as armor integrity). The first version looks like this (missing few checks): class AttributeEffect(object): '''Effect changes object's attribute by delta''' def __init__(self, obj, attrib, delta): self.obj = obj # reference to object the effect applies to self.attrib = attrib # name of attribute that effect applies to self.delta = delta # change of value for object.attribute def apply(self): value = getattr(self.obj, self.attrib) # todo: try, except value += self.delta setattr(self.obj(), self.attrib, value) Yesterday I learned that Python 3.0 introduces nonlocal keyword which would simplify defining effect functions and passing them along. Nice improvement. Very cool, that looks like it would work. The thing I like about the lambda idea though, is that you don't have to write any classes like AttributeEffect, (and presumably other such classes, like LoseItemEffect, etc.) Instead of *modelling* the different kind of effects that could happen, you just write code that *performs* the desired effect. (e.g. monster.hp -= damage) To my eyes, lambda's are therefore more flexible and require less code. But I could be wrong, and obviously you should do what you think is best for your circumstances. Very best of luck with it. Out of interest, is there anywhere you blog about the game development, or are likely to make
Re: OO and game design questions
On Oct 20, 12:11 pm, dex josipmisko...@gmail.com wrote: On Oct 20, 12:25 pm, Jonathan Hartley tart...@tartley.com wrote: On Oct 18, 8:28 am, dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. One common way to store delayed actions is as a lambda (an anonymous function.) A lambda defines a new function: , and you can call this function later. The created function has no name, (but you can assign it to a variable to give it a name if you like) and can be called later: So in the game, you could have a collection 'effects', each one will be a lambda: effects = [] At the start of the round, as each entity makes its moves, they add lambdas to this collection. effects.append( lambda: decrease_hp(monster_a, 4) ) effects.append( lambda: lose_item(monster_a, item_b) ) Instead of appending it directly like this, I imagine the lambdas could be returned by the monster's 'act' or 'update' method: class Monster(): def act(self): # blah and finally return lambda: decrease_hp(monster_a, 4) Then for the start of a round, first you ask each monster what action it is going to perform: for monster in room.monsters: effects.append( monster.act() ) Then for the end of the round, call all the lambdas for effect in effects: effect() Mr. Roy Smith already proposed using closures. I already did a similar thing in my code, but instead of decrease_hp() I have AttributeEffect class which is able to modify any attribute (in old RPGs some monsters could drain your intelligence, in my game laser gun hit will decrease HP as well as armor integrity). The first version looks like this (missing few checks): class AttributeEffect(object): '''Effect changes object's attribute by delta''' def __init__(self, obj, attrib, delta): self.obj = obj # reference to object the effect applies to self.attrib = attrib # name of attribute that effect applies to self.delta = delta # change of value for object.attribute def apply(self): value = getattr(self.obj, self.attrib) # todo: try, except value += self.delta setattr(self.obj(), self.attrib, value) Yesterday I learned that Python 3.0 introduces nonlocal keyword which would simplify defining effect functions and passing them along. Nice improvement. Very cool, that looks like it would work. The thing I like about the lambda idea though, is that you don't have to write any classes like AttributeEffect, (and presumably other such classes, like LoseItemEffect, etc.) Instead of *modelling* the different kind of effects that could happen, you just write code that *performs* the desired effect. (e.g. monster.hp -= damage) To my eyes, lambda's are therefore more flexible and require less code. But I could be wrong, and obviously you should do what you think is best for your circumstances. Very best of luck with it. Out of interest, is there anywhere you blog about the game development, or are likely to make
Re: OO and game design questions
On Oct 19, 8:08 pm, Carl Banks pavlovevide...@gmail.com wrote: On Oct 19, 1:19 am, dex josipmisko...@gmail.com wrote: I'm not sure if it's a good idea to let an item disappear from your inventory by a weak reference disappearing. It seems a little shaky to not know where your objects are being referenced, but that's yout decision. OK, imagine a MUD, where players can dig out new rooms. Room A has a door that holds reference to newly created room B. By using a door, player is transported to room B. At later time someone destroys room B. Using strong references, I have to remove room B from list of rooms, and also remove door to room B, as it holds reference to room B. To do that, I have to keep list of doors that lead to room B. Using weak references, I don't have to worry about removing all doors to room B. They all now have a dead reference, which better models actual situation. If part of mine collapses, or if a module on space station is destroyed, the passage to that location does not magically vanish - it's just obstructed. Can you please tell me if there's something wrong with my reasoning? Well, you're talking about particulars here whereas I am speaking in general. If something is questionable or even bad in general it doesn't mean there are no particular cases for it. Generally speaking: in a game there's presumably some conservation of objects. If you drop an item, does it disappear, or does it become an object of the room? Weak referencing won't help you in the latter case because you have to take care of references at both ends anyway. That's what I mean by shaky: it lets you forget about half of the transaction, which might not be the best thing. YMMV Carl Banks I see your point. I'll think this through and try to build more robust system. Thanks for your insight. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 19, 6:54 pm, Dennis Lee Bieber wlfr...@ix.netcom.com wrote: On Tue, 19 Oct 2010 01:19:48 -0700 (PDT), dex josipmisko...@gmail.com declaimed the following in gmane.comp.python.general: OK, imagine a MUD, where players can dig out new rooms. Room A has a door that holds reference to newly created room B. By using a door, player is transported to room B. At later time someone destroys room B. Out of curiosity, have you looked at any of the older Python efforts? http://py-universe.sourceforge.net/http://www.strout.net/info/coding/python/poo/index.html(some dead links) -- Wulfraed Dennis Lee Bieber AF6VN wlfr...@ix.netcom.com HTTP://wlfraed.home.netcom.com/ I will check out your links. I did some research on several MUD projects (evennia, PyMUD) and gained very little from them. I used MUD only as example, my game idea is combination of Rogue and Elite, with Darklands GUI. It's definitely overambitious, but I'm taking it slowly and learning things on the way. Thanks for input. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 18, 8:28 am, dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. One common way to store delayed actions is as a lambda (an anonymous function.) A lambda defines a new function: , and you can call this function later. The created function has no name, (but you can assign it to a variable to give it a name if you like) and can be called later: So in the game, you could have a collection 'effects', each one will be a lambda: effects = [] At the start of the round, as each entity makes its moves, they add lambdas to this collection. effects.append( lambda: decrease_hp(monster_a, 4) ) effects.append( lambda: lose_item(monster_a, item_b) ) Instead of appending it directly like this, I imagine the lambdas could be returned by the monster's 'act' or 'update' method: class Monster(): def act(self): # blah and finally return lambda: decrease_hp(monster_a, 4) Then for the start of a round, first you ask each monster what action it is going to perform: for monster in room.monsters: effects.append( monster.act() ) Then for the end of the round, call all the lambdas for effect in effects: effect() -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 20, 11:25 am, Jonathan Hartley tart...@tartley.com wrote: On Oct 18, 8:28 am, dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. One common way to store delayed actions is as a lambda (an anonymous function.) A lambda defines a new function: , and you can call this function later. The created function has no name, (but you can assign it to a variable to give it a name if you like) and can be called later: So in the game, you could have a collection 'effects', each one will be a lambda: effects = [] At the start of the round, as each entity makes its moves, they add lambdas to this collection. effects.append( lambda: decrease_hp(monster_a, 4) ) effects.append( lambda: lose_item(monster_a, item_b) ) Instead of appending it directly like this, I imagine the lambdas could be returned by the monster's 'act' or 'update' method: class Monster(): def act(self): # blah and finally return lambda: decrease_hp(monster_a, 4) Then for the start of a round, first you ask each monster what action it is going to perform: for monster in room.monsters: effects.append( monster.act() ) Then for the end of the round, call all the lambdas for effect in effects: effect() Also, I second other people's suggestions that you almost never need to be using __del__ nor weak references in Python, unless you are writing a project that is specifically related to complex resource allocation issues. In an rpg game like this, just store references to the objects that you need (which you have to do anyway, to use them), and forget about allocation issues. Don't be afraid to post follow-up questions, (or even to mail me off list.) I make hobbyist OpenGL games in Python myself, and although I'm no expert, I'd love to chat more about this for our mutual benefit. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 20, 12:25 pm, Jonathan Hartley tart...@tartley.com wrote: On Oct 18, 8:28 am, dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. One common way to store delayed actions is as a lambda (an anonymous function.) A lambda defines a new function: , and you can call this function later. The created function has no name, (but you can assign it to a variable to give it a name if you like) and can be called later: So in the game, you could have a collection 'effects', each one will be a lambda: effects = [] At the start of the round, as each entity makes its moves, they add lambdas to this collection. effects.append( lambda: decrease_hp(monster_a, 4) ) effects.append( lambda: lose_item(monster_a, item_b) ) Instead of appending it directly like this, I imagine the lambdas could be returned by the monster's 'act' or 'update' method: class Monster(): def act(self): # blah and finally return lambda: decrease_hp(monster_a, 4) Then for the start of a round, first you ask each monster what action it is going to perform: for monster in room.monsters: effects.append( monster.act() ) Then for the end of the round, call all the lambdas for effect in effects: effect() Mr. Roy Smith already proposed using closures. I already did a similar thing in my code, but instead of decrease_hp() I have AttributeEffect class which is able to modify any attribute (in old RPGs some monsters could drain your intelligence, in my game laser gun hit will decrease HP as well as armor integrity). The first version looks like this (missing few checks): class AttributeEffect(object): '''Effect changes object's attribute by delta''' def __init__(self, obj, attrib, delta): self.obj = obj # reference to object the effect applies to self.attrib = attrib # name of attribute that effect applies to self.delta = delta # change of value for object.attribute def apply(self): value = getattr(self.obj, self.attrib) # todo: try, except value += self.delta setattr(self.obj(), self.attrib, value) Yesterday I learned that Python 3.0 introduces nonlocal keyword which would simplify defining effect functions and passing them along. Nice improvement. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
I'm not sure if it's a good idea to let an item disappear from your inventory by a weak reference disappearing. It seems a little shaky to not know where your objects are being referenced, but that's yout decision. OK, imagine a MUD, where players can dig out new rooms. Room A has a door that holds reference to newly created room B. By using a door, player is transported to room B. At later time someone destroys room B. Using strong references, I have to remove room B from list of rooms, and also remove door to room B, as it holds reference to room B. To do that, I have to keep list of doors that lead to room B. Using weak references, I don't have to worry about removing all doors to room B. They all now have a dead reference, which better models actual situation. If part of mine collapses, or if a module on space station is destroyed, the passage to that location does not magically vanish - it's just obstructed. Can you please tell me if there's something wrong with my reasoning? -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On 2:59 PM, dex wrote: I'm not sure if it's a good idea to let an item disappear from your inventory by a weak reference disappearing. It seems a little shaky to not know where your objects are being referenced, but that's yout decision. OK, imagine a MUD, where players can dig out new rooms. Room A has a door that holds reference to newly created room B. By using a door, player is transported to room B. At later time someone destroys room B. Using strong references, I have to remove room B from list of rooms, and also remove door to room B, as it holds reference to room B. To do that, I have to keep list of doors that lead to room B. Using weak references, I don't have to worry about removing all doors to room B. They all now have a dead reference, which better models actual situation. If part of mine collapses, or if a module on space station is destroyed, the passage to that location does not magically vanish - it's just obstructed. Can you please tell me if there's something wrong with my reasoning? Simply replace room B with a destroyed room object. That can be quite small, and you only need one, regardless of how many rooms are thus eliminated. DaveA -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
dex josipmisko...@gmail.com wrote: I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing Such is often the case in real life code :-) In turn-based games, the order of action execution in battle can give unfair advantage to players. [...] Is there a design pattern that would remember changes to an object, and apply them later? This sounds like a database transaction. Perhaps what you want is for each object to include a delayedActions list. Each time something happens to an object, you push a closure onto the list. At the end of the turn, you run for obj in global_object_list: obj.apply_delayed_actions() Sorry for the wall of text. No problem. The newsgroup ducks, swivels around on its Content-Type header, hides behind an NNTP outcropping on the server, and just barely avoids being hit by the oncoming wall. You roll 2d10 and make your saving throw against Magical Text Wall, preventing any residual effects of the attack. Whew, that was close! In another article, Dave Angel suggested: Simply replace room B with a destroyed room object. That can be quite small, and you only need one, regardless of how many rooms are thus eliminated. I worked with an OODB system which did exactly this. Each object class had a Class::Deleted singleton. Whenever an object was deleted, references to it were replaced by references to the Deleted object. For the most part, this worked, but resulted in a 4-byte memory leak for each reference (there was still a C++ pointer to Class::Deleted). This memory leak was a known problem, but deemed to be small enough that we could live with it. In the particular application domain we were working in, object deletions were rare. I don't know if that's the case in your MUD. I would assume that the physical structure of the world (rooms, corridors, doors) for the most part get created and rarely deleted, but that may not be true of other objects in the game? -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Tue, Oct 19, 2010 at 5:37 AM, Dave Angel da...@ieee.org wrote: On 2:59 PM, dex wrote: Using strong references, I have to remove room B from list of rooms, and also remove door to room B, as it holds reference to room B. To do that, I have to keep list of doors that lead to room B. Using weak references, I don't have to worry about removing all doors to room B. They all now have a dead reference, which better models actual situation. If part of mine collapses, or if a module on space station is destroyed, the passage to that location does not magically vanish - it's just obstructed. Can you please tell me if there's something wrong with my reasoning? Simply replace room B with a destroyed room object. That can be quite small, and you only need one, regardless of how many rooms are thus eliminated. How does this avoid the problem of having to keep a list of doors that lead to room B? You can't just replace one object with another. You would have to replace every reference to B with a reference to the new object. This is no simpler than deleting the references or replacing them with None. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 19, 1:19 am, dex josipmisko...@gmail.com wrote: I'm not sure if it's a good idea to let an item disappear from your inventory by a weak reference disappearing. It seems a little shaky to not know where your objects are being referenced, but that's yout decision. OK, imagine a MUD, where players can dig out new rooms. Room A has a door that holds reference to newly created room B. By using a door, player is transported to room B. At later time someone destroys room B. Using strong references, I have to remove room B from list of rooms, and also remove door to room B, as it holds reference to room B. To do that, I have to keep list of doors that lead to room B. Using weak references, I don't have to worry about removing all doors to room B. They all now have a dead reference, which better models actual situation. If part of mine collapses, or if a module on space station is destroyed, the passage to that location does not magically vanish - it's just obstructed. Can you please tell me if there's something wrong with my reasoning? Well, you're talking about particulars here whereas I am speaking in general. If something is questionable or even bad in general it doesn't mean there are no particular cases for it. Generally speaking: in a game there's presumably some conservation of objects. If you drop an item, does it disappear, or does it become an object of the room? Weak referencing won't help you in the latter case because you have to take care of references at both ends anyway. That's what I mean by shaky: it lets you forget about half of the transaction, which might not be the best thing. YMMV Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On 10/19/2010 1:46 PM, Ian Kelly wrote: On Tue, Oct 19, 2010 at 5:37 AM, Dave Angel da...@ieee.org mailto:da...@ieee.org wrote: On 2:59 PM, dex wrote: Using strong references, I have to remove room B from list of rooms, and also remove door to room B, as it holds reference to room B. To do that, I have to keep list of doors that lead to room B. Using weak references, I don't have to worry about removing all doors to room B. They all now have a dead reference, which better models actual situation. If part of mine collapses, or if a module on space station is destroyed, the passage to that location does not magically vanish - it's just obstructed. Can you please tell me if there's something wrong with my reasoning? Simply replace room B with a destroyed room object. That can be quite small, and you only need one, regardless of how many rooms are thus eliminated. How does this avoid the problem of having to keep a list of doors that lead to room B? You can't just replace one object with another. You would have to replace every reference to B with a reference to the new object. This is no simpler than deleting the references or replacing them with None. One should rather *change* (not replace) the room into a 'destroyed room' or 'collapsed passage' or whatever, that cannot be entered. The keeps the room around but allows it to be repaired, rebuilt, cleared, or whatever. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On 2:59 PM, Terry Reedy wrote: On 10/19/2010 1:46 PM, Ian Kelly wrote: On Tue, Oct 19, 2010 at 5:37 AM, Dave Angel da...@ieee.org mailto:da...@ieee.org wrote: snip Simply replace room B with a destroyed room object. That can be quite small, and you only need one, regardless of how many rooms are thus eliminated. How does this avoid the problem of having to keep a list of doors that lead to room B? You can't just replace one object with another. You would have to replace every reference to B with a reference to the new object. This is no simpler than deleting the references or replacing them with None. One should rather *change* (not replace) the room into a 'destroyed room' or 'collapsed passage' or whatever, that cannot be entered. The keeps the room around but allows it to be repaired, rebuilt, cleared, or whatever. Thanks, that is what I was trying to say. In the same sense that emptying a list makes it quite small, if it's a general purpose object, you just want to remove all the attributes. DaveA -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Tue, 19 Oct 2010 19:49:20 -0400, Dave Angel wrote: Thanks, that is what I was trying to say. In the same sense that emptying a list makes it quite small, if it's a general purpose object, you just want to remove all the attributes. I think a 'place' (to generalise it) is quite a small object in any case. All it needs to contain is a few lists: - a list of exits, which in some implementations might be simply references to other places, but might usefully be objects with two sides, each having an appearance and a link to the place where that side appears. - a list of fixed objects which only serve to describe the place. - a list of mobile objects that actors can pick up and move - a list of actors who happen to be there. plus a describePlace() method and add(), remove() and getItem() methods for each list. It may be possible to use a single list for all types of object, in which case the object itself would be very small indeed. -- martin@ | Martin Gregorie gregorie. | Essex, UK org | -- http://mail.python.org/mailman/listinfo/python-list
OO and game design questions
I'm building a turn based RPG game as a hobby. The design is becoming increasingly complicated and confusing, and I think I may have tendency to over-engineer simple things. Can anybody please check my problems-solutions and point me to more elegant solution? 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. 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? 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 later? Sorry for the wall of text. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 18, 12:28 am, dex josipmisko...@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 reasons. 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 later? 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. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
dex wrote: 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? You don't have to manage memory with python, I don't know if you wrote C++ in the past (looks like) but consider that python is taking care of everything and you'll be fine. So do not override __del__ (anyway it is not called as you may expect it). Keep a game_object list only if you need the game to know wich objects are in the game, not to keep references. JM -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
You're aware Python can collect reference cycles, correct? You don't have to delete references; Python will get them eventually. I'm not sure I understand this part? If I don't delete all strong references, the object will not be deleted. It will persist and occupy memory as long as there's at least one reference to it (it could be part of inventory, or target of some action). 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.) This makes sense, I will make these modifications. 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. Perhaps I could utilize properties. Make getters return start-of-round attributes and setters set end-of-round attributes. Things would get a bit messy if two or more players modify the same attribute or chest content. I need to think about this some more. Thanks for your thoughts. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Mon, Oct 18, 2010 at 9:50 AM, dex josipmisko...@gmail.com wrote: You're aware Python can collect reference cycles, correct? You don't have to delete references; Python will get them eventually. I'm not sure I understand this part? If I don't delete all strong references, the object will not be deleted. It will persist and occupy memory as long as there's at least one reference to it (it could be part of inventory, or target of some action). No it won't. Python has a garbage collector. The object will persist as long as it is reachable through code. If it becomes unreachable, the garbage collector will delete it even if there is a reference cycle. -- http://mail.python.org/mailman/listinfo/python-list
Re: OO and game design questions
On Oct 18, 6:50 am, dex josipmisko...@gmail.com wrote: You're aware Python can collect reference cycles, correct? You don't have to delete references; Python will get them eventually. I'm not sure I understand this part? If I don't delete all strong references, the object will not be deleted. It will persist and occupy memory as long as there's at least one reference to it (it could be part of inventory, or target of some action). I was assuming the weak referencing was used to avoid reference cycling. I'm not sure if it's a good idea to let an item disappear from your inventory by a weak reference disappearing. It seems a little shaky to not know where your objects are being referenced, but that's yout decision. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list