Saturday, July 9, 2011

Object Oriented Design And Game Development

In this week blog I will tackle a more programming/design topics which have been in the back of my head and that I wanted to share with the rest of you.  Especially as it involve the actual design in code of Mythlound (yes my elusive game ;-p) in a kind of Object Oriented way, well this is how I see it ;-).  But how does Object Oriented Design get mix up in Game Development?  Well if you think about it, in a game they are several thing that you interact with, it could be your own character/player, the enemies, background, projectiles, etc...  As seen in the following diagram for a maze game, several object has been defined that regroup thing that are related together.


So how did I came up with the design of the different objects required in Mythlound?  Let's find out!

Identifying Object
Well since I had a paper prototype of Mythlound it was quite easy to see how many different elements were used to play the game.  In my case they were 2 elements, the first one being the the game board itself where the tiles in the game will be place/move around.  The second being of course the tile themself, which will be created at regular interval and be place/move around the game board by the player.

//Name of my objects
QBRGameView
QBRStoneView


You might wonder why they are call like this, I went for a prefix of our company (QBR is the abbreviation for Quebarium), then a generic name (Game, Stone) and finally the suffix to help identify what kind of object it related to (it's parent).  I will discuss further about this in the next section.

If you want to also get your game in a more object oriented way, you can do the same exercise that I did by decomposing the different elements that compose your game.  The best imho is to distill everything you see at the highest level (be more generic) and also see if one elements is part of another one, as you can probably start with a more generic elements then define a sub-elements (defining sub-classes of the main class).  Remember you can always go back and change the design if you see you miss something, you can add/remove thing or maybe even merge thing.  Of course the more late in the design/implementation phase you are it can be more annoying/painful.

Describing Object
Now that we have identify the objects that compose our game, we need to properly define them by describing what they contains in terms of information (data) and how they behave/do (method).For the 2 object that were identified above I note down what I think the information that each of them should contain and what kind of interaction those objects should have.

//Data for my objects* (which may contain trace of other objects ;-))
//QBRGameView

  • GUI elements for menu
  • GUI elements for our special stones
  • Audio elements for our our Sound/FX
  • Metal stones quantity
  • Special stones counter
  • Score
  • Game Over Status
  • ...
//QBRStoneView
  • Stone image
  • Surface
  • Symbol
  • Location/Position
  • Moveable
  • Was moved
  • Broken
  • ...
//Method for my objects* (which may contain trace of functions ;-))
//QBRGameView

  • Set up Sound/FX
  • Set up Game Board
  • Set Stone Location
  • Set Difficulty Level
  • Set Dropping Speed
  • Creating Stone
  • Dropping Stone
  • ...
//QBRStoneView
  • Animate Flip
  • Animate Match
  • Animate Move
  • Animate Creation
  • Animate Bomb
  • Animate Crystal Ball
  • Animate Jester
  • ...
Like I mentioned in the previous section, I also determined by describing my objects that were many thing related to GUI elements and as I am currently using UIKit for doing all interface related work, I decided that my objects would be a sub-class of UIView.

As you did in the previous exercise by identifying the object in your game, now it's time to take a look at what kind of information (data) are related to those elements and what belong in there.  Those data can be related to the position of your character/player, it could be the number of energy/life remaining, the score/point made so far, etc...  Now you have to determine which interaction (method) each one of your object is doing, which can involve moving around the screen, loosing energy/life, gaining power ups, getting points, increasing score, etc...  And like I mentioned in the previous section you might need to review/adjust your design several times don't worry about that, it's difficult to capture all the information/interaction in one pass, you just need reiterate on your design ;-).

Implementing Object
One more thing... ;-), after you have identified and describe your objects it's time to do the proper implementation of your class that represent your object.  So now let's fire Xcode and type in some code, well I will leave the rest for you ;-), and I will end this article with the current code of the 2 objects I have discuss above.


//
//  QBRGameView.h
//  iQBR1
//
//  Created by Frederic Tessier on 16/06/09.
//  Copyright 2009 Québarium. All rights reserved.
//

#import

#import "QBRConstants.h"

@class QBRGameViewController;

@class QBRStoneView;

@class AVAudioPlayer;

@interface QBRGameView : UIView {
    QBRGameViewController *gameViewController;

    QBRStoneView *stoneViewFirst;
    QBRStoneView *stoneViewSecond;
    QBRStoneView *stoneViewImpact;
    QBRStoneView *stoneViewTemp;
    QBRStoneView *gameBoardArray [QBRGameBoardHeight][QBRGameBoardWidth];

    // GUI elements for menu
    UIImage *mainMenuImage;
    UIImageView *mainMenuView;
   
    // GUI elements for our special stones
    UIImage *crystallBallImage;
    UIImage *jesterImage;
    UIImage *divineInterventionImage;
    UIImageView *crystalBallView;
    UIImageView *jesterView;
    UIImageView    *divineInterventionView;
   
    // Audio elements for our Sound/FX
    AVAudioPlayer *stoneTurnSoundFX;
    AVAudioPlayer *stoneMoveSoundFX;
    AVAudioPlayer *stoneMatchSoundFX;
    AVAudioPlayer *stoneMatchRegularSoundFX;
    AVAudioPlayer *stoneMatchDoubleSoundFX;
    AVAudioPlayer *stoneMatchSpecialSoundFX;
    AVAudioPlayer *stoneNoMatchSoundFX;
    AVAudioPlayer *bombSoundFX;
    AVAudioPlayer *crystalBallSoundFX;
    AVAudioPlayer *jesterSoundFX;
    AVAudioPlayer *divineInterventionSoundFX;
    AVAudioPlayer *failureSoundFX;

    NSTimer *stoneArrivalTimer;

    NSUInteger difficultyLevel;
    NSUInteger stoneDroppingSpeed;
    NSUInteger stoneOnGameBoard;
    NSUInteger currentRatioStoneOnGameBoard;
    NSUInteger previousRatioStoneOnGameBoard;
   
    NSUInteger stoneSelectedFirst;
    NSUInteger stoneSelectedSecond;
    NSUInteger stoneSymbolFirst;
    NSUInteger stoneSymbolSecond;
   
    // Metals stones quantity
    NSUInteger quantityOfGold;
    NSUInteger quantityOfSilver;
    NSUInteger quantityOfCopper;
    NSUInteger quantityOfIron;
    NSUInteger quantityOfTin;
    NSUInteger quantityOfMercury;
    NSUInteger quantityOfLead;
   
    // Special stone counter
    NSUInteger numberOfCrystalBall;
    NSUInteger numberOfJester;
    NSUInteger numberOfDivineIntervention;

    CGPoint stoneLocationBeforeMove;
   
    BOOL gameOver;
   
    BOOL firstTime;
   
    BOOL summoningCrystalBall;
    BOOL summoningJester;
    BOOL summoningDivineIntervention;
   
    int myScore;
    int myBonus;
   
    int testLocationX;
    int testLocationY;
   
    UILabel *myScoreLabel;
    UILabel *myGoldLabel;
    UILabel *mySilverLabel;
    UILabel *myCopperLabel;
    UILabel *myIronLabel;
    UILabel *myTinLabel;
    UILabel *myMercuryLabel;
    UILabel *myLeadLabel;
   
    CGFloat fontSize;
    CGSize textSize;
       
}

@property (retain, nonatomic) QBRGameViewController *gameViewController;

- (void)setUpSoundFX;
- (void)setUpGameBoard;
- (void)setUpStoneAtLocation:(NSInteger)locationY atLocationX:(NSInteger)locationX;

@end




//
//  QBRStoneView.h
//  iQBR1
//
//  Created by Frederic Tessier on 16/06/09.
//  Copyright 2009 Québarium. All rights reserved.
//

#import

@class AVAudioPlayer;

@interface QBRStoneView : UIView {
    UIImage *stoneImage;
    UIImage *stoneImageTop;
    UIImage *stoneImageUnder;
    UIImage *stoneImageBroken;
   
    NSUInteger stoneSurface;
    NSUInteger stoneSymbol;
   
    NSUInteger stoneLocationY;
    NSUInteger stoneLocationX;
   
    BOOL stoneMoveable;
    BOOL stoneWasMoved;
    BOOL stoneBroken;
}

@property (readonly) NSUInteger stoneSurface;
@property (readonly) NSUInteger stoneSymbol;
@property NSUInteger stoneLocationY;
@property NSUInteger stoneLocationX;
@property BOOL stoneMoveable;
@property BOOL stoneWasMoved;
@property BOOL stoneBroken;

- (void)animateFlip:(BOOL)firstStone soundFX:(AVAudioPlayer *)soundFX;

- (void)animateMatch:(BOOL)hasStoneAbove soundFX:(AVAudioPlayer *)soundFX;

- (void)animateMove:(CGPoint)moveLocation soundFX:(AVAudioPlayer *)soundFX;

- (void)animateCreation:(BOOL)firstTime soundFX:(AVAudioPlayer *)soundFX;

- (void)animateBomb:(BOOL)firstTime soundFX:(AVAudioPlayer *)soundFX;

- (void)animateCrystalBall:(BOOL)firstTime soundFX:(AVAudioPlayer *)soundFX;

- (void)animateJester:(BOOL)firstTime soundFX:(AVAudioPlayer *)soundFX;

- (void)animateDivineIntervention:(BOOL)firstTime soundFX:(AVAudioPlayer *)soundFX;

- (void)animationStart:(NSString *)animationID context:(void *)context;

- (void)animationFinish:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;

@end




This post is part of iDevBlogADay, a group of indie iPhone development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.

1 comment: