After coding for a bit, redesigning, testing, then coding some more, we ended up with the basic elaboration to our software design. Please note that this is a live process. In other words, when we found snags, re-analyzed what we were doing, and asked ourselves how we could go about doing it better, we scrapped some work "for the greater good" (whatever that means).
So, here is a breakdown of the major classes of the project and what they do on a conceptual level. Normally a UML diagram or something here would be sufficient, but we're renegades like that.
Bubble
This class deals with every "bubble" in the game. The gameplay is such that new bubbles are spawned at the top of the playing field and slowly descend towards the bottom of the screen. This class handles the updating process (how much and how far does each bubble move), as well as drawing each bubble. Each bubble also has a value which pertains to its assigned color (which is randomly assigned in generation).
For some static functionality, this also handled loading all game resources associated with bubbles (like the bubble graphics themselves). The most important point here is that all graphics should be loaded once and only once then drawn per instance of a bubble.
Gamedata
This is a convenience class that handles persistent data about the game itself. Specifically, this remembers the player's options whether to have the sound on or off. Originally, it was designed to also keep track of in game purchases with points, but as the design evolved, this feature was removed. Because all of the "persistence layer" stuff was conveniently packaged in this one class, adding and removing new things is easy.
GameThread
The bulk of the higher level stuff is in this class. Big questions are handled here, like "is the player in any menu", what to do when the player wants to pause/resume the game (this is the in game feature, not the activity pause/resume), high level resource initialization, the game loop itself, touch event propagation to support classes/objects, and things like this.
This class also handles the Android lifecycle events of pausing and resuming, which is completely different than the in-game feature. We put this functionality here because it has high level access to basically everything in the actual game logic that needs to know about activity life cycle events such as these.
GameView
Not too much to say here other than this is our version of the SurfaceView class used by Android.
Marble
Like the bubble, this class handles everything that has to do with the player marbles. These marbles need to be updated every game cycle so they have an update method, need to be drawn on the playing field, and need to be spawned based on player input.
There are some methods that let us query what kind of marble this is. Specifically, is this a "normal" marble or is this a "special" marble. In the gameplay, normal marbles are simple red, green, blue, yellow playing pieces, and special marbles are just that. They do things that normal ones don't. The game design had changed over development - originally, we had rainbow marbles, rocks, purple marbles, and heart marbles. This changed to only have rocks and purple marbles (more on this in the post-production article later).
At any rate, this class is very similar to bubbles and share the same design, but different code from each other.
MarbleSlot
This class is "part of" the playing field. This handles the player's desire to launch marbles from it. Each slot contains a marble value and when it comes time, the playing field spawns a new marble based on which slot the player initially touched.
Logically, these slots are just defined zones in the playing field that define whether or not the player touched a specific area and don't do much else other than that. Based on the assigned marble value, it also draws a colored marble to represent what marble will spawn when interaction occurs.
PlayingField
This is the over-arching class one step down from the game thread itself. This "contains" every intractable aspect of the game, all marbles, all bubbles, and even the GUI while playing. This large class handles all the essential gameplay logic to include setting up a new game, actually creating new marbles from the slots, propagating update method calls, propagating draw method calls, increasing player marble stock, harming the player, resource management, and lots of supporting methods - including collision detection/response.
From the game thread, a playing field instance is created and basically sticks around until the program is considered "finished".
PlayingPiece
This class is a parent class to Marbles and Bubbles and defines what exactly makes them playing pieces. The class defines a collision flag (used for collision detecting), a velocity vector, a RectF object used to define piece positions (and drawing boundaries), a method to calculate the distance to another playing piece (used again for collision detection between marbles and bubbles), and some convenience methods shared by marbles and bubbles.
Almost anytime there is overlapping features or methods used by more than one class, it is almost always a good idea to create a parent class. Essentially, this is like saying "ok, so, we have this cool new game, it involves some playing pieces that collide with each other"... what does that mean? Well, those pieces are either marbles or bubbles and their interaction with each other. Excellent candidate for a parent with two children sort of situation.
Technical blog posts about programming, graphics, technology, animation, games, maybe some politics or game reviews.
Showing posts with label software architecture. Show all posts
Showing posts with label software architecture. Show all posts
Wednesday, February 29, 2012
Wednesday, February 22, 2012
Design to Product - Software Design (12 / 17)
Finally, let's talk about how the code should be set up.
We mentioned earlier that we took the game design, analyzed it, and figured that nouns become classes and verbs become methods. This sounds good on paper, and there are even tools available to help this process. We could sit around and chart UML all day, every day in regards to the design, but is it necessary? That depends.
Because our product isn't an enterprise solution, our team is small, and one guy is basically doing everything, a massive UML chart isn't really necessary. Of course, we could never discount the idea that someday in the future these things could become useful (like if we sold our products off to another company, as an example).
Regardless, the best way forward for us is to pick apart the major components of the design and start designing what logic should go where and what it should be called.
Honestly, because of our development methodology (or lack there of, depending on who you ask), we take more of an extreme programming measure in this regard. We make classes as we need them. We start with a basic skeleton framework, then start adding new classes as they are needed in the code itself as we program the meat and bones of the product.
We start with the largest classes in the skeleton. Specifically, for Android programming, we start with the GameActivity class. This class acts, more or less, as the "starting point" for the program and interfaces with the OS. Because of how Android itself is designed, we must make a GameThread class that contains the top level logic for the flow of the game itself. We also will need an extension of a View class so that we can interact with the screen and display stuff.
Right away we have:
GameActivity
GameThread
GameView
Without really even going further, based on the game design, we know we already have 2 major components to the product, a Marble, and a Bubble. These playing pieces are what are the basic, interactable things in the game itself. Because both things follow the same physics, we decided that it is best they share a common parent class; PlayingPiece. This parent class defines movement vectors, collision information, the abstract methods of how the pieces are updated and that each child class should know how to draw itself to the screen.
At the same time, we can't really play the game without some sort of logical thing to interact with and where the playing pieces do their magic. Enter the PlayingField, a logical container that contains everything the player can interact with and see.
The game design indicates the need for persistent data over game launches, so we made another class Gamedata that is our "middle man" that handles data saved and loaded between game sessions.
We also ended up needing a class called MarbleSlot, a place where players can touch and interact with the playing field in which marbles can be spawned from.
All that said we now have:
Bubble
Gamedata
GameThread
GameView
Marble
MarbleSlot
PlayingField
PlayingPiece
There are one or two utility classes that are used to assist in the passing of data and messages between classes, but those are fairly technical and don't have anything to do with the direct design of the content of the game. Suffice to say, those can take a while to design and program as well. Just because a game design is "simple" doesn't mean the work behind it will take a set number of hours based on the relative ease of that design. Lots of "stuff" can go on behind the scenes that can take days or even weeks to implement that have no actual, obvious visual effect on the product itself.
For example, a programmer could spend a month just drawing some graphics on a display. They are very proud of this accomplishment, but to non-programmers they usually have the attitude of "you spent a month on this, and only have this to show for it?!". Get used to scenarios like this because it happens more often than not.
Anyways, now that we have our basic classes determined, the essentials are fleshed out.
Tune in next time for elaboration of the class designs and the overall flow of the logic for some of them.
We mentioned earlier that we took the game design, analyzed it, and figured that nouns become classes and verbs become methods. This sounds good on paper, and there are even tools available to help this process. We could sit around and chart UML all day, every day in regards to the design, but is it necessary? That depends.
Because our product isn't an enterprise solution, our team is small, and one guy is basically doing everything, a massive UML chart isn't really necessary. Of course, we could never discount the idea that someday in the future these things could become useful (like if we sold our products off to another company, as an example).
Regardless, the best way forward for us is to pick apart the major components of the design and start designing what logic should go where and what it should be called.
Honestly, because of our development methodology (or lack there of, depending on who you ask), we take more of an extreme programming measure in this regard. We make classes as we need them. We start with a basic skeleton framework, then start adding new classes as they are needed in the code itself as we program the meat and bones of the product.
We start with the largest classes in the skeleton. Specifically, for Android programming, we start with the GameActivity class. This class acts, more or less, as the "starting point" for the program and interfaces with the OS. Because of how Android itself is designed, we must make a GameThread class that contains the top level logic for the flow of the game itself. We also will need an extension of a View class so that we can interact with the screen and display stuff.
Right away we have:
GameActivity
GameThread
GameView
Without really even going further, based on the game design, we know we already have 2 major components to the product, a Marble, and a Bubble. These playing pieces are what are the basic, interactable things in the game itself. Because both things follow the same physics, we decided that it is best they share a common parent class; PlayingPiece. This parent class defines movement vectors, collision information, the abstract methods of how the pieces are updated and that each child class should know how to draw itself to the screen.
At the same time, we can't really play the game without some sort of logical thing to interact with and where the playing pieces do their magic. Enter the PlayingField, a logical container that contains everything the player can interact with and see.
The game design indicates the need for persistent data over game launches, so we made another class Gamedata that is our "middle man" that handles data saved and loaded between game sessions.
We also ended up needing a class called MarbleSlot, a place where players can touch and interact with the playing field in which marbles can be spawned from.
All that said we now have:
Bubble
Gamedata
GameThread
GameView
Marble
MarbleSlot
PlayingField
PlayingPiece
There are one or two utility classes that are used to assist in the passing of data and messages between classes, but those are fairly technical and don't have anything to do with the direct design of the content of the game. Suffice to say, those can take a while to design and program as well. Just because a game design is "simple" doesn't mean the work behind it will take a set number of hours based on the relative ease of that design. Lots of "stuff" can go on behind the scenes that can take days or even weeks to implement that have no actual, obvious visual effect on the product itself.
For example, a programmer could spend a month just drawing some graphics on a display. They are very proud of this accomplishment, but to non-programmers they usually have the attitude of "you spent a month on this, and only have this to show for it?!". Get used to scenarios like this because it happens more often than not.
Anyways, now that we have our basic classes determined, the essentials are fleshed out.
Tune in next time for elaboration of the class designs and the overall flow of the logic for some of them.
Subscribe to:
Posts (Atom)