RPG Battle in cocos2d part two.

This post is a continuation of RPG Battle in cocos2d part one. We are going to add a random attack strength with in a given range, a critical attack and an animation for the attacks.First make sure you have the code from part one it is at the bottom of the RPG Battle in cocos2d part one page. Now, in your Caricters.h add the following after int _strength;.

int _range;
int _criticalstrength;
int _criticalrange;
int _critical;
 

Then add the following after the other @propertys

@property (nonatomic, assign) int range;
@property (nonatomic, assign) int criticalStrength;
@property (nonatomic, assign) int criticalRange;
@property (nonatomic, assign) int critical;
 

Now in the Caricters.m add the following after the other synthesize items.

@synthesize range= _range;
@synthesize criticalStrength= _criticalStrength;
@synthesize criticalRange= _criticalRange;
@synthesize critical=_critical;
 

Then add the following to the Player Caricter.

                caricters.range=6;
                caricters.criticalStrength=20;
                caricters.criticalRange=6;
                caricters.critical=5;
 

Then add the following to the Oct Caricter.

                caricters.range=11;
                caricters.criticalStrength=20;
                caricters.criticalRange=6;
                caricters.critical=5;
 

Ok what we just did is add four new variables that our caricature will use . The range will be used with strength to create a random amount for the attack strength. CriticalStrength, criticalRange, and critical will be used to determine if the attack will be critical and what the attack strength will be if it is critical.
Now on to RpgBattel.h, all we need to do is change

-(void)monsterAttack;
-(void)PlayerAttack;
 

to

-(void)monsterAttack:(id)sender;
-(void)PlayerAttack:(id)sender;
 

I will show you later why this is important. For now lets go on to RpgBattel.m we need to change the monsterAttack, PlayerAttack, and Attack to the following.

-(void)PlayerAttack:(id)sender{
        const int CRITICAL_NUM=10, CRITICAL_RANGE=10;
        int randomcritical=(arc4random() % CRITICAL_RANGE)+_player.critical;
        int randomStrength;
        if(randomcritical>CRITICAL_NUM){
                randomStrength=(arc4random() % _player.criticalRange)+_player.criticalStrength;
        }
        else{
                randomStrength=(arc4random() % _player.range)+_player.strength;
        }
        if(_monster.curHp>=randomStrength){
                _monster.curHp = _monster.curHp-randomStrength;
                [self monsterAttack:sender];
                [_labelHp2 setString:[NSString stringWithFormat:@"Monster HP: %d/%d", _monster.curHp, _monster.maxHp]];
                [_labelMp2 setString:[NSString stringWithFormat:@"Monster HP: %d/%d", _monster.curHp, _monster.maxHp]];
               
        }
        else {
                _monster.curHp =0;
                [_labelHp2 setString:[NSString stringWithFormat:@"Monster HP: %d/%d", _monster.curHp, _monster.maxHp]];
                [_labelMp2 setString:[NSString stringWithFormat:@"Monster HP: %d/%d", _monster.curHp, _monster.maxHp]];
                //RpgGameAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
                //[delegate loadMainScene];
        }
}
-(void)monsterAttack:(id)sender{
        const int CRITICAL_NUM=10, CRITICAL_RANGE=10;
        int randomcritical=(arc4random() % CRITICAL_RANGE)+_monster.critical;
        int randomStrength;
        if(randomcritical>CRITICAL_NUM){
                randomStrength=(arc4random() % _monster.criticalRange)+_monster.criticalStrength;
        }
        else{
                randomStrength=(arc4random() % _monster.range)+_monster.strength;
        }
        if(_player.curHp>=randomStrength){
                _player.curHp = _player.curHp-randomStrength;
                [_labelHp setString:[NSString stringWithFormat:@"Player HP: %d/%d", _player.curHp, _player.maxHp]];
                [_labelMp setString:[NSString stringWithFormat:@"Player HP: %d/%d", _player.curHp, _player.maxHp]];
        }
        else {
                _player.curHp=0;
                [_labelHp setString:[NSString stringWithFormat:@"Player HP: %d/%d", _player.curHp, _player.maxHp]];
                [_labelMp setString:[NSString stringWithFormat:@"Player HP: %d/%d", _player.curHp, _player.maxHp]];
                //RpgGameAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
                //[delegate loadMainScene];
        }
}
-(void)Attack:(id)sender{
        [self PlayerAttack:sender];
}
 

It is a lot of code so lets go over the important lines.

const int CRITICAL_NUM=10, CRITICAL_RANGE=10;
 

These are constant integers meaning that once they are created they cannot be changed. You will want to create a const int instead of using a magic number. A magic number is best described with an example. Lets say you have an if statement like the following.

if (count > 3.14)
 

3.14 is a magic number. You don’t want to use magic numbers because they are hard to change. All your variables should be defined at the top of your function, so they will be easy to manipulate. Lets say that 3.14 was Pi and you wanted to multiply something by Pi you would have to retype 3.14 in every place you multiplyed by Pi. What if you wanted to change Pi? Do you see how difficult it could be? The basic rule of programming is never use magic numbers.

Now back to the code at hand.

int randomcritical=(arc4random() % CRITICAL_RANGE)+_player.critical;
 

This creates a random number that we will use to determine weather the player hits a critical shot or not. randomcritical will be a random number between _player.critical(5) and _player.critical+CRITICAL_RANGE(5+6=10).

if(randomcritical>CRITICAL_NUM){
                randomStrength=(arc4random() % _player.criticalRange)+_player.criticalStrength;
        }
        else{
                randomStrength=(arc4random() % _player.range)+_player.strength;
        }
 

If the random number randomcritical greater then CRITICAL_NUM which at the moment is 10 then we will get a critical hit. As you can tell randomcritical will never be greater then 10 because it is a random number 5-10. Just Change any of the values used with randomcritical to create critical hits. If we get a critical hit then we will get a randomStrength between 20-25, and if we don’t then the randomStrength will be between 10-15.

else {
_monster.curHp =0;
                [_labelHp2 setString:[NSString stringWithFormat:@"Monster HP: %d/%d", _monster.curHp, _monster.maxHp]];
                [_labelMp2 setString:[NSString stringWithFormat:@"Monster HP: %d/%d", _monster.curHp, _monster.maxHp]];
        }
 

This code allows us to set the monsters Hp to 0 if the randomStrength is greater then the monsters current hit points. You should be able to run your code. If you run it you will see the hit points go down randomly but we need to put in an animation for the attack.

In the PlayerAttack function comment out or delete the following line.

[self monsterAttack:sender];
 

Then edit the Attack function.

-(void)Attack:(id)sender{
        [self animatePlayerAttack:sender];
}
 

Add this image to your game.

Now add the following three functions.

- (void)spriteDone:(id)sender {
        CCSprite *sprite = (CCSprite *)sender;
        [sprite.parent removeChild:sprite cleanup:YES];
        [self removeChild:sprite.parent cleanup:YES];
}
-(void)animatePlayerAttack:(id)sender
{
        CCSprite *sprite = [CCSprite spriteWithFile:@"Slash.jpg"];      
        sprite.position = _player.position;;
        [self addChild:sprite z:1];
        [sprite runAction:[CCSequence actions:[CCMoveTo actionWithDuration:2 position:_monster.position],
                                           [CCCallFuncN actionWithTarget:self selector:@selector(spriteDone:)],
                                           [CCCallFuncN actionWithTarget:self selector:@selector(PlayerAttack:)],
                                           [CCCallFuncN actionWithTarget:self selector:@selector(animateMonsterAttack:)],nil]];
       
}
-(void)animateMonsterAttack:(id)sender
{
        CCSprite *sprite = [CCSprite spriteWithFile:@"Slash.jpg"];      
        sprite.position = _monster.position;
        [self addChild:sprite z:1];
        [sprite runAction:[CCSequence actions:[CCSpawn actions:[CCFlipX actionWithFlipX:YES],[CCMoveTo actionWithDuration:2 position:_player.position],nil],
                                           [CCCallFuncN actionWithTarget:self selector:@selector(spriteDone:)],
                                           [CCCallFuncN actionWithTarget:self selector:@selector(monsterAttack:)],nil]];
}
 

The sprite done will delete any sprite sent to it. The animatePlayerAttack function will create a sprite that uses the Slash.jpg image we added to our game and move it from the player to the monster. When it is done it will call the spriteDone, then PlayerAttack, and then animateMonsterAttack. This makes it so the image will move across the screen then the monsters hp will go down and then the monster will attack the player. The animateMonsterAttack function does about the same thing but it calls [CCFlipX actionWithFlipX:YES] which will flip the image on the x axis.

RPG Battle in cocos2d part two Code

Copy right Britney Lee Johnson October 2010.

This entry was posted in cocos2d. Bookmark the permalink.

12 Responses to RPG Battle in cocos2d part two.

  1. chris 420 says:

    Sweet update, I learned a lot from your posts and cant wait to learn more, I added a few labels on top of the charactor that display the name of the attack while that attack animation runs also changed the attack and defend to buttons and added a game over and win scene and background and effects music, only thing im stuck on right now is how to delay the monster attack about 2 seconds after the player attack ends and make it so that the player can only attack again after the monster attack scene is finished.

    Thank You very much for these posts!!!

    • admin says:

      To make it so the player can only attack once the monster is finished you can create a bool value. You can name the bool value anything you want but make it meaningful for example isAttaking. In the reset set isAttaking to false, in PlayerAttack and monsterAttack check to see if isAttaking ==true if it is then return if not set isAttaking to true and let the player or monster attack.
      For the delay try looking up timers and see if that will work I can create a tutorial if you would like to show you how to do it but I must finish my homework first.

  2. chris420 says:

    Thanks again i really appreciate the quick reply’s :) I’ve only been learning xcode, objective c and cocos2d for a few weeks now so usually its hard for me to fully understand a lot of things lol, i tried researching timers and things last night and actions i must have tried a few hundred different things but just could not grasp how to incorporate what i was reading into the code,ill research the BOOL idea you mentioned tonight, Although i did get it to kinda work with [CCDelayTime action with duration:3] but that would only work with the animation and the player hp only decreased after the delay when i tried to use it after the attack action it had no effect, also for some reason when the monster get to 0 hp it starts the new scene but the old scene continues and when the monster attack hit the player the game shuts down it tries to grab both the next battle scene and the game over scene, only happens when both hp values are 0 on the same attack i tried using ( if else) statements to fix that but it didnt work, one other thing i cant get to happen is when i wanted to clean up the labels for when the games resets i used,
    —————————————————————————————————–
    if {
    _player.curHp <= 0;
    [self removeChild:_labelHp2 cleanup:YES];
    [self removeChild:_labelMp2 cleanup:YES];
    [self removeChild:_labelHp cleanup:YES];
    [self removeChild:_labelMp cleanup:YES];

    [[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:2 scene:[HelloWorld scene]]];
    ——————————————————————————————————
    it worked well with the first tutorial but the else stament below seems to not work along side my if stament, (im sure there is an easy way to remove all of the layers and scenes of the game at once during scene transitions i just havent stumbled on it yet lol)
    ——————————————————————————————————
    else {
    _player.curHp = 0;
    [_labelHp setString:[NSString stringWithFormat:@" HP: %d/%d", _player.curHp, _player.maxHp]];
    [_labelMp setString:[NSString stringWithFormat:@" MP: %d/%d", _player.curMp, _player.maxMp]];
    ——————————————————————————————————

    Thanks so much for taking the time to read my questions!!

    • admin says:

      How about I do another tutorial that will only allow you to attack once the animations have finished, delays the monster attack by two seconds, and add in the sound and everything else you have working that way you know the tutorial will work with the rest of your code. Is there anything else you want to know? It might take me a bit of time to get it up I am still working on my homework.

  3. chris420 says:

    WoW that would be awsome of you :) only other things i can think of at the moment would be a few extra attacks for monster and player (maby random monster attacks) which would help me understand how to implement more and more attacks, i have allready added extra monsters because i made a few extra fight scenes and understand how to change the values to how strong or weak i want the monster or player to be, Another sweet addition would be xp points and level up i could probably figure the xp and level out on my own but id be very interested to see how you would set it up, as you code is much much more well put together then how i would be able to do it on my own lol. I been trying to make a pause button that pauses the game and loads a main menu for stats equipment and so on and save game but failed pretty bad tons of errors any advice on that would be sweet, Once again Thank so very much for helping me with this!!

    • admin says:

      Ok sounds like the best thing is going to be to do a tutorial first on saving and then update this code that way you understand saving I will start on it but it will take a bit of time.

  4. chris420 says:

    Sweet thanks :) looking forward to your next post

  5. chris420 says:

    My project is starting to really take shape thanks to your help and posts although i think im making a bit of a mess with the memory because i get really bad lag when i click on any menu buttons lol id love to send you what i have so far and see if you could point out a few of my mistakes if thats anyway posible :)

    Thanks again very much for your time cant wait til the next tutorial!!

  6. chris420 says:

    Hi sorry i didnt get a chance to send my project yet but im trying to clean it up and organize it so that it dont just look like a big mess, and take out any art work that i didnt make my self and music tracks since i havent recorded any of my own yet lol
    ill have it sent soon tho hopfully tonight.

    Thanks again :)

    • admin says:

      any time I am trying to get the next post up it is taking some time because I have ran into some strange errors with my game that will be out soon.

  7. chris420 says:

    Hope you have good luck with the errors ill definatly grab your app from the appstore once its released and also looking forward to your next tutorial

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>