Assignment 8 – Integrating the Visitor Pattern
I was really able to make a lot of progress with my project this week, due in large part to the versatility of the visitor pattern. I finally got the attack ability to work via a key press as I wanted to, the only lingering issue with that is the concurrency issue I mentioned last week. When I attack, it switches Godzilla’s sprite to one shooting a fireball and I would like for it to reset after a few moments. This was not my focus for this week however.
I implemented three different uses for the visitor pattern in a Visitors.py module, two of which are working properly. The two that are working are AttackSpriteVisitor and DisplayVisitor.
DisplayVisitor simply visits each object after it has been attacked and prints out its current health. I would like each objects life to be displayed on the canvas and visually reflect the changes but I’m not entirely sure about how to achieve that at the moment.
The AttackSpriteVisitor switches each enemy’s sprite to an attacking sprite as they automatically strike back each time they’re attacked by Godzilla. In the case of inanimate objects, that obviously don’t retaliate, it simply switches their sprite to one that reflects the damage done by Godzilla’s attack. I’m really excited that I got this working as intended because I was able to successfully wrap my head around and implement the visitor pattern using reflection, which I was previously struggling to understand. Here’s how this was implemented:
class AttackSpriteVisitor(Visitor): """visitor class: """ def __init__(self): super(AttackSpriteVisitor, self).__init__() def visit(self, node, *args, **kwargs): enemy = None for cls in node.__class__.__mro__: enemy_name = 'visit_' + cls.__name__ enemy = getattr(self, enemy_name, None) if enemy: break if not enemy: enemy = self.visit_Generic return enemy(node, *args, **kwargs) def visit_Mothra(self, node, *args, **kwargs): # print('visit_Mothra ' + node.__class__.__name__) node.setSprite(Tk.PhotoImage(file='../resources/MothraLaserLeft.gif')) def visit_Military(self, node, *args, **kwargs): # print('visit_Military ' + node.__class__.__name__) node.setSprite(Tk.PhotoImage(file='../resources/militaryAttack.gif')) def visit_Tank(self, node, *args, **kwargs): # print('visit_Tank ' + node.__class__.__name__) node.setSprite(Tk.PhotoImage(file='../resources/tankAttack.gif')) def visit_Building(self, node, *args, **kwargs): # print('visit_Building ' + node.__class__.__name__) node.setSprite(Tk.PhotoImage(file='../resources/buildingFire.gif')) def visit_Tree(self, node, *args, **kwargs): # print('visit_Tree ' + node.__class__.__name__) node.setSprite(Tk.PhotoImage(file='../resources/treesFire.gif')) def visit_Generic(self, node, *args, **kwargs): pass
Finally, the DeathVisitor is the visitor that isn’t yet fully implemented. What I want is to have DeathVisitor visit an object after its health reaches zero and remove it from the world. I can’t quite wrap my brain around how to achieve this though. I’m trying to have it reach into GameWorld.py and call the GameWorld’s removeWorldObject() method. I’m getting hung up on how to refer to the game world though (the self it requires here: def removeWorldObject(self, oldObject)). Since the GameWorld is created in the driver at runtime I don’t have a reference to it to work with. Here’s what I currently have (where it passes in need_world_reference as an argument to visit() is what I’m having trouble with):
class DeathVisitor(Visitor): """visitor class: removes an object from the GameWorld when its health is zero""" def __init__(self): super(DeathVisitor, self).__init__() def visit(self, visitable): GameWorld.removeWorldObject(need_world_reference, visitable)