Back to HAXEING!
Monday, November 29, 2010 11:58:45 AM
Rule 18: Limber Up
So guys, on my last post I described and illustrated the AnimalWorld project which is my "learning" project for Haxe. I recommend reading my last post again, or for the first time if it's your case, so you can get into the mood again. Ah, don't forget your mug of favorite beverage . Read past the funny image when you are done. Rule 18 is very important or else you might pull something. Unfortunately I haven't done anything more related to my bigger project, the "Joker Engine".
Lately I've been inspired a lot by zombies.
Back already!? I hope you enjoyed the reading but, most of all, I hope that you are also anxious for some haxe lines of code. Oh boy, I got some good stuff for you now! Let's start with the class diagram of the implementation:
View the image in a different tab or save it to see full size.
DOWNLOAD SOURCE HERE
It all starts in with com.billbsb.haxedorhaxe.animalworld.Main which is the entry point of the program defined in the compile.hxml. This Main class is the "Client" that uses the AnimalWorld classes and adjust some properties. I like to stress where it all begins because I get frustrated when I get my hands on a new project and I don't even know where or how everything starts. I hope it's clear for you.
Design Patterns FTW
My idea was to make the AnimalWorld a very flexible, low coupled, highly cohesive and extensible program and for that I implemented it using several Design Patterns(DP) in combination. I think I achieve all that although there is still many places for refactoring as you will see. In the current version I implemented the following DPs:
- Abstract Factory
- Strategy - The PatternCraft series by John Lindquist is A MUST WATCH SERIES!
The first DP you'll see is the classical combo Singleton+Abstract Factory for the Continents. My intention was to be able to switch the simulating Continent and all it's inhabitants in a very practical way and what's more practical than 1 line of code? The com.billbsb.haxedorhaxe.animalworld.IWorldFactory defines all the functionality/responsibilities that a World Continent Factory has like creating Carnivores, Herbivores and Plants. You just need to pass an IWorldFactory instance to the com.billbsb.haxedorhaxe.animalworld.AnimalWorld, which by the way is the actual "main" class, and the simulation will run with the proper set of "living beings".
At the same time comes the Singleton pattern for my implementing IWorldFactory, the com.billbsb.haxedorhaxe.animalworld.africa.AfricanWorldFactory. It makes a lot of sense to have 1 and only 1 instance of the factory and I also wanted to try private constructors!
As I said before, the AnimalWorld class is the "heart"/ of the application. It's where all the living things are created and the "main loop" is run. The main loop is one of the most interesting parts of the application because it's where the living things can act based on whatever you want. There are so many possibilities on how this can be achieved that I had to make it very decoupled and easy to change the logics. Did the word "Strategy" also poped up in your head?! That's where and why I implemented the Strategy Pattern. I provide the com.billbsb.haxedorhaxe.animalworld.strategy.RandomLoopStrategy implementation which I quite like because every time I run the AnimalWorld I get a completely different output. Sometimes life flourish and some other times the plants take over.
In summary the AnimalWorld class must have an instance of a com.billbsb.haxedorhaxe.animalworld.IWorldFactory and a com.billbsb.haxedorhaxe.animalworld.strategy.IMainLoopStrategy both injected in the class constructor.
Interactions, Visitors and Scenes: ACTION!
All right, so far we got the AnimalWorld up and running but what about the interactions and how do they work? For this I applied the Visitor Pattern. The idea is to add interactive capabilities to our objects at compile time. In this case we are interested in the capability to interact with something. For instance, if you want a Class to be able to interact with an IAnimal, or it's sub-classes, this class must implement the com.billbsb.haxedorhaxe.animalworld.visitor.IAnimalVisitor interface. The IAnimal class can interact with other IAnimals and IPlants so it implements the IAnimalVisitor and com.billbsb.haxedorhaxe.animalworld.visitor.IPlantVisitor. The IAnimal and IPlant are aware of this interactions and provide the proper "acceptVisitor" method. So it's in the "visit" method that the interaction logic takes place. The interaction logic is something like: "if it's a Male Lion interacting with a Female Zebra this will happen!".
And for every interaction that happens an com.billbsb.haxedorhaxe.animalworld.scene.IScene that illustrates what just happened is created and played a little bit later. This whole Scene thing came to my mind when I was thinking about the visual/graphical/rendering part of the application. I decided to make the AnimalWorld a Scene-based animation, opposed to a real time animation just to make it simpler. I couldn't recognize any pattern for this behavior though and but I had no time to implement the visual part yet so all the scenes are just text output. I tried to make it a bit funny No?
I know, it's a little bit confusing, it's double dispatched, there's parent-child logic, it has scenes ... but it works elegantly. It can be thought like a dialog:
Zebra says: - Hello Plant, I can interact with Plants. Can you accept my interaction?
Plant says: - Hello Zebra. Yes! I will accept you interaction. Please visit me.
Zebra says: - All right, I'm visiting you right now.
Play the Scene of the hungry Zebra eating the Plant.
I think the Visitor pattern is very useful and an elegant solution but it's also very abstract, hard to explain and visualize. I use it with caution.
That's it guys. My first Haxe project that is yet to be completely finished. Right now it's ready for expansion, ready for YOU to get your hands on! There's a README file in the project's packaged file which contains a lot of instructions for building, running, testing and some FlashDevelop tricks. I also didn't mentioned all used classes but make sure to check the package com.billbsb.haxedorhaxe.animalworld.base and the classes com.billbsb.haxedorhaxe.animalworld.WorldUtils and com.billbsb.haxedorhaxe.animalworld.ErrorMessages. Also make sure to check the test folder which contains the Unit Tests which are also not complete but cover most part of the code.
I hope I was clear enough and helpful. Please share your thoughts, critics, ideas and code with me. Ah, also if you liked the post, help me spread my blog.
DOWNLOAD SOURCE HERE
Tchau! Tot ziens!