User:Benjamin Gibson/Design Study
Navigation shortcuts: Wiki users:Benjamin Gibson
Contents |
Problem overview
For my design study I have chosen to use a mobile graphics assignment (from cosc416). The goal of this assignment is to create a small pacman like game for mobile phones, using java ME. Java ME is a scaled down version of java, it works mostly like earlier versions of java (no generics etc).
I am designing code that will be able to be used to create very simple 2D games, I want a flexible code base that can be used to make several different types of games. In particular I want to be able to add new objects into the game easily (such as a new type of playable character, or add walls etc) and make it easy to change how the game is played (things like what does pushing the up button do).
For my design I have split my graphic assignments code into two parts, the Game Library and the Game Actual. The Game Library is the code base mentioned above and the Game Actual is an implementation of a PAC man game made on top of the Game Library for the purposes of my graphics assignment.
Note that my design is only about the Game Library, not about the Game Actual, while I have implemented the Game Actual it is not a part of my design study. The idea is I could make a completely different game just as easily from the same Game Library. I will provide the Game Actual as proof that the Game Library can be used to create games, though the code in the Game Actual was rushed to finish and should not be considered as part of my design. In addition any code in MyCanvas relating to the GameActual should not be considered part of the design.
Terms
- Collision detection: Collision detection is a term used in graphics applications when you are trying to find out if the graphical representation of two or more objects overlap, or "collide". An example of this would be checking if a players avatar is touching a wall, if it is then you would want to stop them from moving through the wall.
- Canvas: This is similar to JCanvas in swing, graphics are drawn on the canvas and then the canvas is drawn on the screen, for my purposes things won't get any more complex than this.
- Sprite: Sprites are animated images, much like .GIF files, these are used to represent most animations.
- Layer Manager: GameObjects are added to the Layer Manager(a part of the J2ME library) which then draws them on the screen. It also manages some other things of little relevance to my design study, such as the order in which objects are drawn on the screen.
Initial Design
UML Diagram
Note: some elements have been removed from the diagram as they relate to the Game Actual, not the Game library (such as empty part in the middle of MyCanvas's fields) ignore these parts.
Design Description
The above diagram shows my initial design for the Game Library
- Midlet is just a main class that is necessary for java ME, this class can pretty much just be ignored.
- MyCanvas is a canvas, as described above, this class is where the magic happens, it is created by Midlet and then runs the game, creating game objects and then constantly looping redrawing all the graphics and using the CollisionDetector to find collisions.
- CollisionDectector is a singleton class which maintains a list of all collidable objects, detect will check all collidable objects against each other for collisions and returns a list of collision objects, one for each collision.
- Collision represents the collision between two collidable objects, it simply takes the two objects that collided and stores them as fields, resolve calls resolveCollision on both collidables.
- GameObject is an interface that represents an object that actually exists in game (such as a player, barrel, wall etc). Collidable, Movable and InputListener are all types of GameObjects, a GameObject will most likely inherit from one or more of these types.
- Collidable is an abstract class that in its constructor adds itself to the CollisionDetector, this means that any object that extends Collidable will be added to the CollisionDectector upon creation. Collidable objects have an action method that is called when they collide with another object, this object is passed in as a parameter, in addition to this each collidable object has three boolean fields, lethal, killable and impassable, which are used to help the object understand how to react to the collidable object passed in as a parameter to action (for example if a killable object collides with a lethal object, the killable object should die).
- Movable is a simple interface for GameObjects that can move.
- InputListener is a simple interface for GameObjects that accept input from user (key presses).
Design Critique
Having the three boolean fields of Collidable is not very flexible, if I ever wanted to make a new property for Collidable objects I would have to edit the code for all classes extending collidable.
Killable is an attribute that should not belong exclusively to collidable objects, all objects should be killable.
Input listener should not inherit from GameObject, someone may at some point wish to create an input listener not attached to a GameObject, such as one that counts key presses.
When a collision occurs Collidables have to know about each others fields in order to chose how to react to the collisions, while I have achived this with out using getters, I think this still violates Tell, Don't Ask
Design Patterns
- Singleton - The CollisionDetector is a singleton class with getTheCollisionDetector as the getInstance method. The CollisionDetector stores a list of all collidable objects and checks them for collisions when asked (using the detect method). I could have made this list inside MyCanvas like I did with the list of InputListener, but I think it's better to keep this data in its own class to avoid cluttering MyCanvas and so collidable objects can easily add themselves to it.
Updates
- Refactored Collision detection system to conform to Tell, Don't Ask better.
- Restructured the program into several packages so that protected objects aren't available to the whole program.
Final Design
UML Diagram
Note: some elements have been removed from the diagram as they relate to the Game Actual, not the Game library (such as empty part in the middle of MyCanvas's fields) ignore these parts.
Design Description
UPDATE THIS The above diagram shows my initial design for the skeleton for the Game Library, it is a simplified version of the UML diagram my code generated, I have left out all the detail of the classes aside from their names and most of the detail of their relationships, later i will include the full UML diagram, but for now this suits my purposes better for describing my system.
- Midlet is just a main class that is necessary for java ME, this class can pretty much just be ignored.
- MyCanvas is a canvas, as described above, this class is where the magic happens, it is created by Midlet and then runs the game, creating game objects and then constantly looping redrawing all the graphics and using the CollisionDetector to find collisions.
- CollisionDectector is a singleton class which maintains a list of all collidable objects, when asked it will check all collidable objects against each other for collisions and construct a list of collision objects, one for each collision.
- Collision represents the collision between two collidable objects, it simply takes the two objects that collided and stores them as fields, like a pair class would.
- GameObject is an interface that represents an object that actually exists in game (such as a player, barrel, wall etc). Collidable, Movable and InputListener are all types of GameObjects, a GameObject will most likely inherit from one or more of these types.
- Collidable is an abstract class that in its constructor adds itself to the CollisionDetector, this means that any object that extends Collidable will be added to the CollisionDectector upon creation. Collidable objects have an action method that is called when they collide with another object, this object is passed in as a parameter, in addition to this each collidable object has three boolean fields, lethal, killable and impassable, which are used to help the object understand how to react to the collidable object passed in as a parameter to action (for example if a killable object collides with a lethal object, the killable object should die).
- Movable is a simple interface for GameObjects that can move.
- InputListener is a simple interface for GameObjects that accept input from user (key presses).
Design Critique
UPDATE THIS Having the three boolean fields of Collidable is not very flexible, if I ever wanted to make a new property for Collidable objects I would have to edit the code for all classes extending collidable. Ideally I should be able to find some way to achieve the same functionality without having this draw back, this feels like the kind of problem that a design pattern could fix, so I am currently looking into
Design Patterns
- Decorator
Design Maxims
I have followed a large set of design maxims, however most of these are maxims I normally follow. For this reason I will categorize the maxims I have followed into two categories, less significant maxims and more significant maxims. The more significant maxims are as such because they are new to me and I have made a special effort in applying them to my design.
Less Significant Maxims Followed
Avoid downcasting, Avoid inheritance for implementation, more to be added when I have the time
More significant Maxims Followed
- Tell, Don't Ask - In order to finish my project in time I at one point neglected this maxim, however I have recently reworked my code to follow it, however I have run into one instance where it is hard to do conform it to the rule cleanly. The instance is in the action method of the collidable class, currently the method takes a collidable object as a parameter and then asks it about three different Booleans that classify it and decides how to act based off this. One possible solution that I am looking into is having another method called on collidable that then has the object pass itself and its three Booleans as parameters into the other collidables action method, this would get rid of the need for getters for the Booleans at least. This doesn't seem like it's as clean as it could be and I think the problem lies in the existance of the booleans in the first place, I would rather not have them in the first place, but am unsure as of yet how else this design could work. (Note to self: explain why this problem exists in more detail e.g. what the booleans do)
- Encapsulation boundary - I subscribe to the idea of an object encapsulation boundary rather than a class encapsulation boundary. In class it was suggested that when using an object encapsulation boundary we should default to protected fields instead of private fields. I have done this in only one class, Collidable. This is because this is the only class that has fields that are intended to be inherited and I do not like that protected fields also grant access to classes within the same package. In java you used to be able to declare private protected fields which work like private fields but also allow subclasses access to the field, this would be my preference. Taking this approach does mean that if someone where to come along later and subclass one of my concrete classes then they would not be able to access the classes fields, I feel that this is a lesser evil than sharing all my classes fields amongst their packages since these classes are not intended to be subclassed.