Pro-grammer
Pro-grammer

Reputation: 870

a single method call for many instances

I have a function update() in a Character class such that every time an instance of the class character is made, the update method needs to be called in the main loop for example:

troll = Character()
monster = Character()

while True:
   troll.update()
   monster.update()

This is fine, but is unclean if I were to have a lot of instances of the Character class.

I know this can be done using the @classmethod annotation. But I don't want to do this, are there other ways?

Any suggestions?

Upvotes: 0

Views: 148

Answers (4)

Bill Stidham
Bill Stidham

Reputation: 1480

I think what you are looking for is the composite pattern. You create a CompositeCharacter class that contains all Character instances. You can then call an update method in the CompositeCharacter object that will iteratively call the update method on all of it's children (your Character object collection).

You could define your composite class like this, or some variant of this. The point is that your instantiated CompositeCharacter object will have an internal list and provide methods to manipulate that list.

class CompositeCharacter():
    children = []

    def update(self):
        for c in self.children:
            c.update()

    def add(self, char):
        self.children.append(char)

At the beginning of your code, you instantiate the composite characters object into some variable reference... say compCharacters.

compCharacters = CompositeCharacter()

Or you could instantiate many CompositeCharacters based on some grouped character class

trollCharacters = CompositeCharacter()
monsterCharacters = CompositeCharacter()
humanCharacters = CompositeCharacter()

Then when you instantiate your individual Character()s you add them to the appropriate CompositeCharacter object.

troll = Character()
compCharacters.add(troll)    OR trollCharacters.add(troll)
monster = Character()
compCharacters.add(monster)  OR monsterCharacters.add(monster)

If you have added them to a general composite object (compCharacters) then you just call the update on that object

compCharacters.update()

Or, if you've used specialized groupings you could just call the update on whichever group you want to update.

trollCharacters.update()

OR

monsterCharacters.update()

OR

humanCharacters.update()

You could also keep all of your specialized composite objects in a parent composite object. Then you could call a global update if you wish or call a specialized one.

compCharacters = CompositeCharacter()

trollCharacters = CompositeCharacter()
compCharacters.add(trollCharacters)

monsterCharacters = CompositeCharacter()
compCharacters.add(monsterCharacters)

humanCharacters = CompositeCharacter()
compCharacters.add(humanCharacters)

Then to call the global update just call comp

compCharacters.update()

Upvotes: 1

Bartlomiej Lewandowski
Bartlomiej Lewandowski

Reputation: 11180

You cannot use a class method here, because a class method does not apply to an instance, but to some part of class that all sprites share.

Let's say your Character has an update method that moves the sprite. So it would look something like this:

def update(self):
    self.pos = (self.pos[0] + self.v[0], self.pos[1] + self.v[1])

If you where to make it a class method, the first argument would be a class, not an instance, so there is no way to change an instance from a class method, unless the class itself has a list of instances.

The approach you should take should depend on the size of the game.

For starters, just put them in a list, and iterate to call each instance update method.

Another way would be to have a list of characters in the class, as RyPeck suggested. I think storing the list in the main program is better, because there is no need for the class to know about the existence of any instance.

Upvotes: 1

RyPeck
RyPeck

Reputation: 8147

Taking advantage of storing data in classes.

class Character():
    instances = []

    def __init__(self):
        Character.instances.append(self)
        self.x = 0

    def class_update(self):
        for x in self.instances:
            x.instance_update()

    def instance_update(self):
        self.x += 1

A = Character()
B = Character()

A.class_update()
B.class_update()

C = Character()

C.class_update()

print Character.instances
print A, B, C
print A.x, B.x, C.x

Output -

[<__main__.Character instance at 0x10a8523f8>, <__main__.Character instance at 0x10a852440>, <__main__.Character instance at 0x10a852488>]
<__main__.Character instance at 0x10a8523f8> <__main__.Character instance at 0x10a852440> <__main__.Character instance at 0x10a852488>
3 3 1

I am unaware of the pitfalls of such an approach without knowing more about what it is you need to accomplish.

Upvotes: 2

jonrsharpe
jonrsharpe

Reputation: 122052

You could keep all of your Character objects in a dict:

characters = {}
characters["troll"] = Character()
characters["monster"] = Character()

Then updating all of your characters is easy:

for character in characters.values():
    character.update()

Upvotes: 1

Related Questions