Disclaimer (read only !) : The original translations of all tutorials provided by this blog are from the Internet and are only for learning and communication purposes. Do not conduct commercial communications. At the same time, do not remove this statement when reprinting. In the event of any dispute, it has nothing to do with the owner of this blog and the person who published the translation. Thank you for your cooperation!
Original article link: http://www.raywenderlich.com/782/harder-monsters-and-more-levels
So far, the game "How to Use cocos2d to make a simple iPhone" I am translating is very cool. We have a turret that can be rotated, a monster that can be shot, and great sound effects.
However, our turret thinks this is too simple. These monsters only need to take a shot, and now there is only one level! It hasn't warmed up yet!
In this tutorial, I will expand our projects, add monsters of different types and difficulties, and then implement multiple levels.
More fierce monsters
For fun, let's create two different types of monsters: one that is not very smooth, but fast to move, and one that is very resistant (tank level), but very slow to move! To enable gamers to differentiate these two types of monsters, download modified monster images and add them to the project. At the same time, download the explosion sound effects I made and add them to the project.
Let's create a monster class. There are many ways to model the monster class, But we chose the simplest method, that is, the monster class as a subclass of ccsprite. At the same time, we will create two sub-classes of the monster class: one for our weak and fast monsters, and the other for our strong and slow monsters.
Select File \ new file and cocoa touch class \ objective-C class to ensure that subclass of nsobject is selected. Click Next, name it monster. m, and make sure "also create monster. H" is checked.
Next, SetCodeReplace it with the following:
# Import " Cocos2d. h "
@ Interface MONSTER: ccsprite {
Int_ Curhp;
Int_ Minmoveduration;
Int_ Maxmoveduration;
}
@ Property (nonatomic, assign)IntHP;
@ Property (nonatomic, assign)IntMinmoveduration;
@ Property (nonatomic, assign)IntMaxmoveduration;
@ End
@ Interface weakandfastmonster: Monster {
}
+(ID) monster;
@ End
@ Interface strongandslowmonster: Monster {
}
+(ID) monster;
@ End
This is straightforward: We derived a monster class from ccsprite and added some member variables to record the monster status. Then, two different monster subclasses are derived from the monster class.
Now open monster. M and add the following code:
# Import " Monster. h "
@ Implementation monster
@ Synthesize HP=_ Curhp;
@ Synthesize minmoveduration=_ Minmoveduration;
@ Synthesize maxmoveduration=_ Maxmoveduration;
@ End
@ Implementation weakandfastmonster
+(ID) monster {
Weakandfastmonster * Monster = Nil;
If (Monster = [[Super alloc] initwithfile: @" Target.png " ] Autorelease]) {
Monster. HP = 1 ;
Monster. minmoveduration = 3 ;
Monster. maxmoveduration = 5 ;
}
Return Monster;
}
@ End
@ Implementation strongandslowmonster
+(ID) monster {
Strongandslowmonster * Monster = Nil;
If (Monster = [[Super alloc] initwithfile: @" Target2.png " ] Autorelease]) {
Monster. HP = 3 ;
Monster. minmoveduration = 6 ;
Monster. maxmoveduration = 12 ;
}
Return Monster;
}
@ End
The code here is very simple. Only one static method we add for each class is used to return the instance of this class. Then the time required for the default HP and mobile is first made.
Now, let's integrate the newly created monster class into the previous code! First, import the file in helloworldscene. M:
# Import " Monster. h "
Then, modify the addtarget method to construct the instance of the newly created class, instead of directly creating the sprite ). Replace the row spritewithfile as follows:
// Ccsprite * target = [ccsprite spritewithfile: @ "target.png" rect: cgrectmake (0, 0, 27, 40)];
Monster * Target = Nil;
If (Arc4random () % 2 ) = 0 ){
Target = [Weakandfastmonster Monster];
} Else {
Target = [Strongandslowmonster Monster];
}
Here, there will be a 50% chance for different types of monster. Of course, we moved the speed definition of the monster to the class. Therefore, we need to modify the min/Max moving interval and change it to the following:
Int Minduration = Target. minmoveduration; // 2.0;
Int Maxduration = Target. maxmoveduration; // 4.0;
Finally, make some changes in updatemethod. First, add a Boolean value before the targetstodelete statement.
Bool monsterhit = False;
Then, in cgrectintesectsrect, the object is not immediately added to targetstodelete, but changed to the following:
// [Targetstodelete addobject: Target];
Monsterhit = True;
Monster * Monster = (Monster * ) Target;
Monster. HP -- ;
If (Monster. HP <= 0 ){
[Targetstodelete addobject: Target];
}
Break ;
Here, we do not immediately kill the monster, but reduce its HP, and kill it only when its life value is smaller than 0. NOTE: If projectile hits a monster, we will jump out of the loop, which means a Frisbee can only hit one monster at a time.
Finally, we changed the projectilestodelete test to the following:
If (Monsterhit ){
[Projectilestodelete addobject: Projectile];
[[Simpleaudioengine sharedengine] playeffect: @" Explosion. CAF " ];
}
Compile and run the Code. If everything goes well, you will see two different types of monsters flying over the screen-which makes our turret life more challenging!
Multiple Levels
To enable the game to support multiple levels, we need to reconstruct it first. This refactoring is very simple, but there is a lot of work to do in this project. If you put all the content on this post, it will be a long and boring post.
On the contrary, I will talk about what I did from a higher perspective and provide a sample project with complete functionality.
Abstract A level class. At present, the "level" concept is hard-coded in the helloworldscene class, such as the type of monster to be launched and the frequency of launch. Therefore, our first step is to extract the information and put it into a level class. In this way, we can reuse the same logic for different levels in helloworldscene.
Reuse scenarios. Currently, every time we convert a scenario (scene), we create a new scenario class. The disadvantage here is efficiency. Every time resources are loaded in the init method of the scenario object, this will affect the game frame.
Because we are a simple game, what we need to do is to create an instance for each scene, in addition, a reset method is provided to clear any old State (such as the previous fl or monster ).
ApplicationProgramDelegate as a stepping stone. Currently, we do not have any global status, such as the level at which we are or the setting of the current level. In each scenario, it is only hard-coded. The next scenario that needs to be redirected is who.
We will modify the content and use app delegate to store pointers to some global states (such as level information. This is because all scenarios (scene) can easily get delegate objects. We will also place some methods in the app delegate class to implement centralized control over switching between different scenarios. In addition, mutual dependencies between scenarios are reduced.
Well, the above is my main refactoring content-More details can be found in the sample project. Remember, this is just one of the ways to implement functions. If you have other better ways to organize scenarios and Game objects, please share them here!
Download the code and run it. We have a very good game-a rotating turret, thousands of different types of enemies, multiple levels, win/lose scenarios, of course, there are great sound effects!
Summary
You can download the complete source code of this series of tutorials so far.
Now, you know how to make a simple game. Why not go deeper? I learned how to use cocos2d to create tile-based games? After all, who do not like ninja to eat watermelon?
I hope you will like this series of tutorials and these tutorials will help you with your project.
PS: Next, we will try to translate some tutorials on box2d, so stay tuned!
Copyright statement: This article consistsHttp://www.cnblogs.com/andyquetranslation. You are welcome to enjoy the conversion and sharing. Please respect the work of the author. Keep this note and the author's blog link when reprinting. Thank you!