In the last article we started our quest to implement Space Demon iPhone game. We created the moving background of the game using the particle engine in Cocos2d framework. In this article we are going to make our code more readable by refactoring the code base.
Refactoring Old Code:In
the last article we wrote all the code in the same file. This is called
Spagetti coding and it will become a further mess in the future when
you want to make changes to the game. It is always a good idea to
refactor the code as you develop. In this article you will also notice
that a lot of code has been refactored and separated into smaller
classes.
Environment Class:
In the previous
implementation we had a method called "buildSeaOfFire" which was
responsible for created the background of the game. The method was part
of the main game layer. In the latest version of the codebase we have
moved the code to a new class called Environment.m. The header and the
implementation files are shown below:
05 | @ interface Environment : NSObject { |
13 | @property (nonatomic,retain) CCLayer *layer; |
31 | #import "Environment.h" |
35 | @implementation Environment |
39 | -(Environment *) initWithLayer:(CCLayer *) l |
59 | CCParticleFire *emitter = [[CCParticleFire alloc]init]; |
61 | CGSize windowSize = [[CCDirector sharedDirector] winSize]; |
63 | y = windowSize.height + 50; |
65 | int noOfFireBallsNeeded = windowSize.width / emitter.texture.contentSize.width; |
67 | for ( int i=1; i<=noOfFireBallsNeeded;i++) |
71 | CCParticleFire *seaOfFire = [[CCParticleFire alloc] init]; |
73 | [seaOfFire setStartSize:10]; |
75 | [seaOfFire setEmissionRate:10]; |
77 | [seaOfFire setLife:20]; |
79 | [seaOfFire setGravity:ccp(0,-90)]; |
81 | seaOfFire.position = ccp(x,y); |
83 | [self.layer addChild:seaOfFire z:-1]; |
85 | x += emitter.texture.contentSize.width; |
The
Enviroment.m class can be instantiated using the custom constructor
called initWithLayer. The initWithLayer constructor takes in the layer
and then assigns to a public property exposed by the Environment.m
class.
The main game layer can now use the Environment class inside the constructor init:
3 | Environment *env = [[Environment alloc] initWithLayer:self]; |
As
you can see the above approach is much cleaner than adding all the code
in the game layer file. In the next section we will describe how we
created separate classes for the Demon and the Spaceship.
Implementing Demon:
Once
again you can always go ahead and create a CCSprite property in the
game layer file and then use that as your Demon but it is always a good
idea to keep responsibilities separate. The main layer should not be
responsible for controlling the Demon. It is the responsibility of the
Demon class to control the activities performed by the Demon. The Demon
class header file is shown below:
13 | #import <Foundation/Foundation.h> |
21 | @ interface Demon : BaseEntity { |
27 | CCParticleSun *fireball; |
39 | @property (nonatomic,retain) CCSprite *sprite; |
41 | @property (nonatomic,retain) CCLayer *layer; |
43 | @property (nonatomic,retain) CCParticleSun *fireball; |
45 | @property (nonatomic,retain) Spaceship *spaceship; |
The
first thing to note about Demon class is that instead of inheriting
from NSObject it inherits from the BaseEntity class. The BaseEntity
class contains properties which will be used by most of your classes.
One of those property is called windowSize which is used to retrieve the
screen size of the iPhone or the iPad.
The Spaceship class looks similar to the Demon class. The header file implementation is shown below:
05 | @ interface Spaceship : BaseEntity { |
09 | CCParticleMeteor *laser; |
13 | CCParticleSmoke *smoke; |
17 | -( void ) move:(CGPoint) location; |
29 | @property (nonatomic,retain) CCSprite *sprite; |
31 | @property (nonatomic,retain) CCParticleMeteor *laser; |
33 | @property (nonatomic,retain) CCLayer *layer; |
35 | @property (nonatomic,retain) CCParticleSmoke *smoke; |
37 | @property (nonatomic,retain) CCParticleFire *explosion; |
By
separating the responsibility into different classes your code looks
more cleaner and can be changed easily for future updates.
Conclusion:
In
this article we took the old codebase and refactored the code. The
refactoring will allow us to make future changes easily with less
headache. In the next article we will dive into the details of putting
the Demon and the Spaceship on the screen and starting the war.