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)
I was able to somewhat successfully incorporate the state pattern into my project this week. As of now it’s simply being used to change the image of the user controlled character, Godzilla. I created two states for Godzilla depending on whether he’s engage with an enemy or not. When he engages an enemy by calling his performAttack() method on them it will switch his state to the EngagedState which will cause his sprite to change to one where he’s shooting a fireball. I say that I was somewhat successful because I’ve encountered two stumbling blocks related to how I want the performAttack() method and state pattern to function.
The first issue, and really the only part of my use of the state pattern that isn’t working, is making the sprite change back to the not engaged sprite after an attack has been performed. I basically want the fire breathing sprite to be displayed for a few seconds when I perform an attack and then for it to change back to the notEngaged sprite (not breathing fire). I’ve tried, in numerous places throughout the chain of commands, to reset the state to notEngaged. It works, in that it does reset the state, but it does so instantaneously such that you never even see the fire breathing sprite displayed. I’ve tried using the sleep function imported from time, thinking that I could make it pause for a few seconds before resetting the sprite but so far that’s only had the effect of pausing the canvas from being displayed and then when it is the sprite has already been reset to notEngaged. My attack behaviors are implemented using the strategy pattern and are the final step in the chain of actions when I call performAttack(), thus they seem like a logical spot reset the the sprite to me. Here’s what I was trying to no avail (the two commented out lines):
class AttackFireBreath(AttackBehavior): """breath fire attack behavior""" def attack(self, victim): victim.health -= 20 self.notifyObservers() print "I'm breathing fire at you!" # time.sleep(3.0): # self.setState(self.notEngagedState)
The second issue is that I want the performAttack() method to be called with the press of a key. I was able to get this functionality working properly as far as binding the proper keys and having a keyPressHandler send instructions to the GameWorld to call the performAttack() method. What I’m getting stuck on is how to make it perform that attack on an actual enemy on the screen. My train of thought is that when the performAttack() method is called I somehow need to cycle through each object in the gameWorlds object list, test if any of them are within some defined attackRange, perform attack if they are, else pass. Testing the distance between them is what I haven’t successfully implemented yet; I’m attempting to do it using the provided getLocation() method (in GameWorld.py) and the distance() method imported into GameWorld.py from Locations.py. Here’s screenshot of the hybrid code/pseudocode I currently have for this (in GameWorld.py):
I’ve managed to refactor my Godzilla simulator taking advantage of the sample code and structure provided to us in our last lab. I’d be lying if I said I understood everything going on in the code that was provided, but I’ve got a decent grasp on the way things are structured both in the code and in the directory hierarchy provided. My biggest improvement is using the provided GameUnit class and having all of my other classes, both animates and inanimates, subclassing it. I was also able to finally get crude graphics implemented so that I can start to get some visual feedback on the things that are happening. Right now I just have various animate and inanimate objects being displayed on the canvas, but most actions are still being outputted as text. My enemy animates are currently using the random movement code provided while my main character Godzilla can be moved around the screen using the arrow keys. I plan on also mapping his attack ability to a key press but I’m not completely sure how to achieve that at the moment.
I’ve starting planning out how to utilize the state pattern and I’ve hashed out a bit of code in a separate project to test it out. So far, so good but there are still some details I need to work out. I didn’t go overboard with this refactoring, as far as behaviors and interactions are concerned, because I already know I’m going to change a number of things with my use of the state pattern. I wasn’t far enough along with some of those ideas to implement them in time for this assignment though, so I opted to do some things in the refactoring that I know will change. The main thing is the way I’m currently making use of the strategy pattern to set/change behaviors will likely be completely overhauled when the state pattern is implemented. I’m also not currently making use of the decorator pattern and struggling a bit to make good use of it in my program. I was considering using it to maybe change the images dynamically (say change Godzilla to Godzilla with fireball when attacking, for example), but I’m not sure if it makes more sense or not to have images change using the state pattern (if Godzilla switched to an attackState).
Another thing that I’d like to have happen is for my destructible objects (both animate and inanimate) to appear randomly throughout the game world rather than having to create and place them in the driver. I really have no clue how this is achieved though, or if it’s reasonable for this project.
Overall I feel like I’m making some positive progress and maintaining a grasp on the program even though it keeps growing in complexity.
I feel like I’m understanding the syntax of Python (and that of Java) a lot better than I was just a few weeks ago. To me this has always been the biggest hurdle because I have no coding experience other than CIS 210 last term. I feel very comfortable with the concepts discussed in the book/class and I understand the design patterns just fine, but actually implementing things into code has always been a major hurdle for me, one that I finally feel I’m progressing past (to a small but noticeable extent).
Unfortunately, I feel that my code has become a bit of a mess and there’s a lot of things that I now understand better and would like to go back and address. I am finding that as I understand the technical aspects better, the way I envision my project keeps shifting (evolving hopefully) but in a way this is problematic because rather than moving forward I want to go back and fix things which is difficult due to time constraints.
I’m still struggling a bit with implementing the strategy pattern in a meaningful manner. I’ve got various “behavior” interfaces implemented for things such as attacking, moving, and having characters declare themselves (make a vocal announcement for the time being). I also created a HealthBehavior interface which allows any class that implements it to have access to methods that set their initial health and decrease health (if attacked). I didn’t feel that it was properly utilizing the strategy pattern though as the behavior types contained in it weren’t as generic as they should be. I set the HealthBehavior interface up a bit differently than the interfaces we created for our soldiers classes in lab. My confusion about the strategy pattern stems from the examples in lab where there was so little actually happening in the interfaces that it didn’t seem very useful to use them as well as the fact that much of what was in them seemed duplicated in the actually classes and subclasses that implemented them. So I initially tried to make HealthBehavior a bit more useful by reusing more code, but since I didn’t feel it was correct use of the strategy pattern I ended up scrapping it and moving to a more simplified health system. Here’s a snippet of the HealthBehavior interface code I initially had. Maybe you could provide some feedback on if it was a valid use of the strategy pattern or not?
class HealthBehavior(object): """interface for health behaviors""" def __init__(self): super(HealthBehavior, self).__init__() self.health = None def setHealth(self): pass def decreaseHealth(self): pass class GodzillaHealth(HealthBehavior): """Godzilla's health behavior""" def __init__(self): super(GodzillaHealth, self).__init__() def setHealth(self): self.health = 1000 def decreaseHealth(self): while self.health >= 10: ####DELETE THIS LINE print "Godzilla's health is " + str(self.health) self.health -= 10 if self.health == 0: print "Godzilla is dead!" class MothraHealth(HealthBehavior): """Mothra's health behavior""" def __init__(self): super(MothraHealth, self).__init__() def setHealth(self): self.health = 100 def decreaseHealth(self): while self.health >= 10: ####DELETE THIS LINE print "Mothra's health is " + str(self.health) self.health -= 10 if self.health == 0: print "Mothra is dead!"
And how it was actually implemented in a concrete class using self.healthBehavior.setHealth():
class Godzilla(Monster): """a subclass of Monster""" def __init__(self): super(Godzilla, self).__init__() self.attackBehavior = AttackFireBreath() self.moveBehavior = MoveWalk() self.declareBehavior = DeclareRoar() self.healthBehavior = GodzillaHealth() self.healthBehavior.setHealth()
There’s a few lines that needed to be deleted, as marked by comments, but I they were just there to test the decreaseHealth method. As I though about it, it seems to make more sense not to use the strategy pattern for health as it’s not really something that has a bunch of different versions or changes particularly (other than decreasing in value when attacked). I ended up switching it to the following which simply initializes each object with a value for self.health and uses the various attack interfaces to decrease the health of enemies.
class AttackBehavior(Observable, Observer): """interface for attack behaviors""" def attack(self, victim): pass class AttackFireBreath(AttackBehavior): """breath fire attack behavior""" def attack(self, victim): victim.health -= 20 self.notifyObservers() print "I'm breathing fire at you!" class Godzilla(Monster): """a subclass of Monster""" def __init__(self): super(Godzilla, self).__init__() self.attackBehavior = AttackFireBreath() self.moveBehavior = MoveWalk() self.declareBehavior = DeclareRoar() self.health = 1000
I’m currently working on using the observer pattern to make it so Godzilla can attack a unit and it will use the decreaseHealth method to lower their health. I’m admittedly struggling a bit to get this to incorporate the observer pattern. I have an attack system working as shown above but I want it to happen automatically when Godzilla observes an enemy or destroyable inanimate object within range. I’m just not certain how to implement this at the moment. The main use I’m currently making of the observer pattern is having every object watch when Godzilla moves and having Godzilla watch when every object moves. One object moves and the other responds by readying them self to move. I’m really eager to get graphics implemented so that I can visually see how these things are interacting – I’m hoping to work on that over the next few days. I’ve already found some sprites that I’ll likely use for the final version. I want to have it be a top down isometric viewpoint of Godzilla rampaging through city and an ocean locations and encountering different animate and inanimate objects which he can destroy. I initially started off with the intentions of having it be a scripted world where you just observe what’s happening but I’m now toying with the idea of giving the user control of Godzilla’s moving directions and attack ability.
Here’s a simple driver making use of the observer pattern (Godzilla & Mothra observing each other moving, Godzilla attacking Mothra) and the strategy pattern (Godzilla’s firebreath attack gets changed to a punch attack and back to firebreath, Mothra’s health decreasing, both objects move behaviors).
def main(): godzilla = Godzilla() mothra = Mothra() mothra.display() godzilla.addObserver(mothra) mothra.addObserver(godzilla) godzilla.planMove() godzilla.act() mothra.act() godzilla.performAttack(mothra) mothra.display() godzilla.performAttack(mothra) mothra.display() godzilla.setAttackBehavior(AttackPunch()) godzilla.performAttack(mothra) mothra.display() godzilla.display() mothra.performAttack(godzilla) godzilla.display() godzilla.declareBehavior.declare() godzilla.act() godzilla.setAttackBehavior(AttackFireBreath()) godzilla.performAttack(mothra) mothra.display() godzilla.performAttack(mothra) mothra.display() godzilla.performAttack(mothra) mothra.declareBehavior.declare() mothra.display() main()
And the output:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python /Users/jasonjkeller/PycharmProjects/GodzillaSim/GodzillaSimDriver.py I'm Mothra!!! My health is 100. Godzilla is planning to move. I'm walking around! Mothra is planning to move. I'm flying around! Godzilla is planning to move. I'm breathing fire at you! I'm Mothra!!! My health is 80. I'm breathing fire at you! I'm Mothra!!! My health is 60. I'm punching you! I'm Mothra!!! My health is 55. I'm Godzilla!!! My health is 1000. I'm shooting a laser beam at you! I'm Godzilla!!! My health is 985. ROOOAAAAAR!!! I'm walking around! Mothra is planning to move. I'm breathing fire at you! I'm Mothra!!! My health is 35. I'm breathing fire at you! I'm Mothra!!! My health is 15. I'm breathing fire at you! BZZZzzz!!! Mothra is dead. Process finished with exit code 0
For my CIS 211 project I wish to create a simulation based on Godzilla. My goal is to have a few different locations in which Godzilla engages various animate and inanimate objects in combat and wanton destruction.
For my Animates category I will have Godzilla as the main focus of the simulation. He will roam around destroying different types of inanimate objects (such as Buildings, Trees and Boats) with his fire breath and punching abilities. He will also engage with several different types of animates (Civilians, Military, Battleships, Mothra) by chasing after them and breathing fire or punching at them.
Mothra will be a monster enemy that will randomly appear and fight with Godzilla. Mothra’s Actions will include the ability to fly around, shoot laser beams at Godzilla, and be killed in battle by Godzilla. Mothra will be able to appear at any location throughout the game.
Battleships (as opposed to inanimate Boats) will be found only at the Ocean location. Their Actions will include the ability to move through the Ocean and fire Guns at Godzilla. They will also be destroyable by Godzilla’s fire breathing and punching actions.
Finally I wish to have several subclasses of People as animate objects. The first subclass is Civilians whose Actions consist of running away from Godzilla, screaming for their lives, and being killed by Godzilla. The second subclass of People is Military. They will have all of the same Actions as Civilians but they will also have the added ability to engage Godzilla by firing their guns at him. All subclasses of People will only be able to appear in the City location.
My Inanimates will consist of Buildings, Boats, Trees, and Guns. Buildings, Trees and Boats will be scattered throughout the locations of the simulation and will be destroyable by the fire breathing and punching actions of Godzilla. Guns will be equipped on the Military subclass of People and they will be able to be fired at Godzilla when engaged with him.
My Locations will consist of a City and an Ocean. The City (likely modeled after Tokyo) will be filled with Buildings, Trees, and People. The Ocean will consist of Battleships and Boats.
I’m optimistic that this project will be both attainable and highly enjoyable but I’m also keenly aware that there are a myriad of implementation issues that haven’t even begun to creep into my consciousness yet. More than anything I’m excited to attempt to build a simulation like this from the ground up as I fully expect it to be a rewarding learning experience.
I feel that I have a better grasp on basic Java programming having gone through the process of porting SimUDuck to Python. Java seems a lot “wordier” to me in it’s use of syntax. Having such a limited background in programming – my only real exposure being three months of Python in CIS 210 – I feel that Java is a bit more confusing due to the wordier and more restrictive syntax but overall it’s not terribly different than Python. My brain certainly got twisted around numerous times jumping back and forth between the two languages but I’m confident that over time each of them will become more ingrained through the conversion process.
Here’s a brief checklist on how to implement the strategy pattern:
1. Determine what aspects of your program vary versus which aspects are static.
2. Encapsulate the aspects that vary by creating interfaces/classes for each of them.
3. Program to the encapsulated interfaces/classes rather than implementing those aspects locally.
4. Strive to utilize composition over inheritance as much as possible to keep your code as flexible and maintainable as possible.