Tile Animation
My helper libraries are changing enough to become incompatible with previous versions, so here are newer builds for today's tile animation demonstration:
gameobjects, build 3
mu, build 9
gcsio, build 11
The map viewer with tile animation is available here.
I've converted a few implementation-only classes into interface/class pairs mostly.I also updated gcsio to load the VERGE 3 tile animation and obstruction tile data in VERGE3_VSP.
To achieve simple tile animation, I updated the createVERGE3GameMap() method from GameMapFactoryImpl. If I hadn't been returning a GameMapImpl in the interface for the factory, the map viewer from yesterday wouldn't have been incompatible with the current build — that's what I get for straying from the holy path of interfaces!
The timing is not precise, and is achieved simply by pausing a little bit after repainting the viewport — the focus was on achieving animation. The new code to set up the tile animations is of course in GameMapFactoryImpl.
Yesterday a was creating a new GameTile for every single cell on the game map's grid. This is an unnecessary amount of object creation, since we only need one unique GameTile for each unique tile graphic. I didn't notice until I set about creating GameAnimatedTileImpl, when it became evident that creating duplicate animated tiles could eat up a whole lot of memory needlessly — there would be duplicated lists of the bitmaps for each animation.
So first I create a set of GameTile objects that are the animated tiles. I do this first since I need to be able to lookup an animated tile when populating the layers in my GameMap.
Then I actually go through all the layers, lazily creating unique GameTile instances as I come across new tile indexes, or instead using one of the animated GameTile objects if the tile index falls within the tile index range of the start and finish tiles for any of the VERGE 3 tile animation "strands."Note that this approach doesn't give you 100% accurate tile animations for a couple reasons. First of course is that I don't pay attention to VERGE 3's tile animation rules for forward, backward, ping pong, or random progressions. I just do forward animation.
The second inaccuracy is more subtle. VERGE 3 tile animations specify a start and finish tile index. When creating my game map object, I am generating animations in the form of GameTile objects for any tile index I cross that falls between these two indices. But if you have a water animation that is three frames long, for example, you have three possible variations when displaying the tile due to the way the VERGE 3 engine updates the tile indices during animation.
The second and third tiles in the tile animation are basically "ahead" by one and two frames, respectively. In this way you are able to leverage the utility of a single animation strand in terms of slightly varied output that looks more natural. Scatter tiles from within the same strand across a region and you've got a little more convincing, or at least more interesting, display. You've all seen at least one movie with a large computer generated formation of soliders whose movements are all uncannily synchronous. The more immersive ones do this without setting off your brain's highly attuned wtf-sensors.
At any rate, since my MuAnimation classes have no comprehension of offsets within some larger entity, such as a tile set, I would have to create three separate MuAnimation objects for each version of the water animation if I wanted to model the VERGE 3 animation fully. MuBitmap objects would be added in the appropriately offset order for each variation. Then, as I am populating each layer in my GameMap, I would insert the appropriate animated GameTile instance for each variation, dependent upon which tile index between the start and finish indices was encountered.
It might seem a little overly complex at first, but I think there are benefits to this approach. At a later date I will be able to do a little bit of this upfront tapdancing for other tile animation flavors, such as those from maps in Sphere or ika, and I won't have to modify my game object code that manages these animations.
It is the triumph of interfaces! Be they explicit Java interface definitions or abstract classes. The important thing is there is an agreement on how objects talk to each other to perform various operations, such as an animation. That is, what methods are available, and what do they do? If you then write code which adheres to these agreements, you're programming more conceptually than concretely. At that stage, it won't matter how much you screw with your concrete implementations, so long as they're obeying your agreements. Interfaces and abstract classes are the mechanism by which Java and many other languages help to facilitate the definition and enforcement of these "agreements."
But I digress! Though I've covered much of what I intended for today anyway. All of these interfaces are starting to give me some more tangible ideas on what to write unit tests for. I think tomorrow I will probably write up unit tests for testing a lot of my interfaces via their concrete implementations. I never seem to be able to find any material on writing tests that are related to games programming, so maybe I'll be providing a valuable service! At any rate, it's high time I practice what I preach too!
In order to help drive the importance of unit testing home, I'll probably implement some loaders for an engine like Sphere or ika, so that my unit tests will be able to thoroughlly test GameMap objects created from two separate game creation systems. It will also help illustrate the coolness of "programming to interfaces."
Well. Another day, another mess of code. Nothing stellar, but some food for thought, and some fodder for the tinkerers. This method of just "producing" stuff is starting to grow on me. I don't think too hard, I just race toward the finish line and see what comes out. Sorta like the general energy behind compos, now that I think about it! You also start to think about things more critically than you would if ideas were just floating around in your brain, since you have to actually articulate them when writing for an audience.
10 minutes before midnight! All done and minutes to spare.
Yeah baby! Yeah! Oh yeah! USA! USA! USA!