Cocos2d为多个敌人使用1级分数错误

时间:2014-11-11 15:34:18

标签: cocos2d-iphone

感谢您抽出宝贵时间来查看我的问题,因为我非常擅长编程,所以我们非常感谢任何帮助或指导方向。

...概述 我有一个我想要创建的简单游戏,它包括一个类“Ball'从屏幕左侧向右侧发射的精灵。这个" Ball"的速度精灵创建是随机的,每次都是" Ball"移动到屏幕右侧,一个点被添加到分数中。

enter image description here

问题.... 我遇到的问题是2" Balls"几乎在同一时间点火(随机发生一些时间)它们通过屏幕的右手不到一秒钟,当发生这种情况时,它似乎只增加1,当它应该加2得分(作为2球已通过右侧)。

下面是我的Ball启动器类的代码(使用此类随机调用球)。

如果您已经使用过或经历过Ray Wenderlichs'学习Cocos2D然后分配这个看起来很熟悉,因为在阅读完他的书之后我试图编辑他的代码来做我想要的事情(在阅读本书后,通过阅读本书的最佳学习方法,通过弄乱代码等)。 / p>

@implementation BL

@synthesize delegate;
@synthesize lauchingAnim;
@synthesize afterlauchingAnim;

-(void) dealloc {
    delegate = nil;
    [lauchingAnim release];
    [afterlauchingAnim release];

    [super dealloc];
}

//--The below shootPhaser method takes the current direction the launcher is facing and asks the delegate (gameplaylayer) to create the ball moving in that direction.
//--The below createPhaserWithDirection method was declared (created) in the GamePlayLayerDelegate protocol.

-(void)shootPhaser {
    CGPoint phaserFiringPosition;
    PhaserDirection phaserDir;
    CGPoint position = [self position];



    float xPosition = position.x + position.x * 0.51f;
    float yPosition = position.y + position.y * 0.045f;

    {
        phaserDir = kDirectionRight;
    }

    phaserFiringPosition = ccp(xPosition, yPosition);

    [delegate createPhaserWithDirection:phaserDir andPosition:phaserFiringPosition];


}

-(void)changeState:(CharacterStates)newState {
    [self stopAllActions];
    id action = nil;

    characterState = newState;

    switch (newState) {
        case kStatespawning:
           // CCLOG(@“launcher->Changing State to Spwaning");
            [self setDisplayFrame:
             [[CCSpriteFrameCache sharedSpriteFrameCache]
              spriteFrameByName:@“lancher_1.png"]];
            break;


        case kStateIdle:
           //  CCLOG(@“laucher->Changing state to idle");
            [self setDisplayFrame:
             [[CCSpriteFrameCache sharedSpriteFrameCache]
              spriteFrameByName:@"lancher_1.png"]];

            break;


        case kStateFiring:
           // CCLOG(@“launcher->Changing State to firing");


            action = [CCSequence actions:
                      [CCAnimate actionWithAnimation:lauchingAnim],
                      [CCCallFunc actionWithTarget:self
                                          selector:@selector(shootPhaser)],
                      [CCAnimate actionWithAnimation:afterlauchingAnim],
                      [CCDelayTime actionWithDuration:2.0f],
                      nil];


            lauchingAnim.restoreOriginalFrame = NO;
            afterlauchingAnim.restoreOriginalFrame = NO;

            [self changeState:kStateIdle];

            break;



        case kStateDead:
            CCLOG(@“launcher->changing state to dead");

            break;

        default:
            CCLOG(@"unhandled state %d in launcher", newState);
            break;
    }

    if (action !=nil) {
        [self runAction:action];

    }
}

-(void)updateStateWithDeltaTime: (ccTime)deltaTime andListOfGameObjects:(CCArray*)listOfGameObjects {


    if (characterState == kStateFiring) {

        // 5
        if (characterState != kStateFiring) {
            // If RadarDish is NOT already taking Damage
            [self changeState:kStateFiring];
            return;
        }
    }

    if ((([self numberOfRunningActions] == 0) && (characterState != kStateDead)) ) {
       // CCLOG(@"launcher Going to Idle!!!");
        [self changeState:kStateIdle];
        return;
    }

}


-(void)initAnimations {

    [self setLauchingAnim:[self loadPlistForAnimationWithName:@"lauchingAnim" andClassName:NSStringFromClass([self class])]];

    [self setAfterlauchingAnim:[self loadPlistForAnimationWithName:@"afterlauchingAnim" andClassName:NSStringFromClass([self class])]];
}



-(id) initWithSpriteFrameName:(NSString*)frameName{
    if ((self=[super init])) {
        if ((self = [super initWithSpriteFrameName:frameName])) {

            CCLOG(@"### Laauncher initialized");
            [self initAnimations];                                   
            characterHealth = 3.0f;                                
            gameObjectType = kBallLaucher;
            // 3
            [self changeState:kStateIdle];                       

        }
    }
    return self;  
}




@end

以下是我" Ball"的代码。类...

#import “Ball.h"


@implementation Ball


@synthesize delegate;
@synthesize myDirection;
@synthesize travelingAnim;
@synthesize ScoreAnim;

-(void) dealloc {
    delegate = nil;
    [travelingAnim release];
    [ScoreAnim release];
    [super dealloc];

}

-(void)changeState:(CharacterStates)newState {
    [self stopAllActions];
    [self setCharacterState:newState];

   CGSize screenSize1 = [CCDirector sharedDirector].winSize;
   CGPoint position = [self position];

   CGPoint endPosition = ccp(screenSize1.width*1.5f, screenSize1.height*0.20f);


    id action = nil;
    //id action1 = nil;

    switch (newState) {
        case kStatespawning:
        CCLOG(@“Spawning Ball");
            [self setDisplayFrame:[[CCSpriteFrameCache
                                    sharedSpriteFrameCache]
                                   spriteFrameByName:@"Ball_1.png"]];

            break;

        case kStateTravelling: {

    movementAction = [CCMoveTo actionWithDuration:5.0f
                                                 position:endPosition];



            }

            break;


        case kStateScore:

            PLAYSOUNDEFFECT(SCORE);

            CCLOG(@“Ball Past Left Of Screen => Add 1 to Score");

            action = [CCSequence actions:
                      [CCCallFunc actionWithTarget:self selector:@selector(removeSelf)],
                      nil];
            break;


        default:
            CCLOG(@“Ball -> Unknown CharState %d",
                  characterState);

            break;
    }
    if (action !=nil)
        [self runAction:action];
}



-(void)removeSelf{
    CCLOG(@"Removing Ball Object Has Scored.");


    [self setVisible:NO];
    [self removeFromParentAndCleanup:YES];

    return;

}


-(void)updateStateWithDeltaTime:(ccTime)deltaTime andListOfGameObjects:(CCArray *)listOfGameObjects {


    CGPoint currentSpitePosition = [self position];

    CGSize screenSize = [CCDirector sharedDirector].winSize;



    if (currentSpitePosition.x > screenSize.width*1.1f)  {{


             [self changeState:kStateScore];
        }
    }

    return;
    }


    if ([self numberOfRunningActions] == 0) {

        if (characterState == kStatespawning) {
            [self changeState:kStateTravelling];
            return;
        }

}


}

-(void)initAnimations {

    [self setTravelingAnim:[self loadPlistForAnimationWithName:@"travelingAnim" andClassName:NSStringFromClass([self class])]];

    [self setScoreAnim:[self loadPlistForAnimationWithName:@"ScoreAnim" andClassName:NSStringFromClass([self class])]];    
}


-(id) initWithSpriteFrameName:(NSString*)frameName{
    if ((self=[super init])) {
        if ((self = [super initWithSpriteFrameName:frameName])) {

            CCLOG(@"### Ball Initialised");
            [self initAnimations];                                   
            characterHealth = 3.0f;                                
            gameObjectType = kEnemyTypeBall;                    
            [self changeState:kStatespawning];                       

        }
    }
    return self;  
}

@end

以下是我" GameplayLayer"的代码。类...

    #import "GamePlayLayer.h"
#import “Ball.h"
#import “BL.h"

@implementation GamePlayLayer

@synthesize delegate;

-(void) dealloc {
    delegate = nil;
    [super dealloc];
    }


-(void) update:(ccTime)deltaTime {
    CCArray *listOfGameObjects =
    [sceneSpriteBatchNode children];




    for (GameCharacter *tempChar in listOfGameObjects) {         
        [tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:listOfGameObjects];                        
    }

    GameCharacter *tempChar = (GameCharacter*)[sceneSpriteBatchNode
                                                getChildByTag:kEnemyTypeBall];


    if ([tempChar characterState] == kStateScore)  <==HERE I AM SEEING IF THE BALL HAS SCORED - THIS IS ALSO WHERE I THINK I MAY BE GOING WRONG SOMEHOW.
    {
        CCLOG(@"Add 1 Points To Score");

        [self addPoint];
        return;
     }

}




-(void)addPoint
{
score = score + 1; 
   [scoreLabel setString:[NSString stringWithFormat:@"$%i", score]];   <===ADDING THE POINT TO THE SCORE
return;
}




-(void) createObjectOfType: (GameObjectType)objectType
                withHealth:(int)initialHealth atLocation:(CGPoint)spawnLocation withZValue:(int)ZValue {

if (kBallLaucher == objectType) {
        CCLOG(@"Creating launcher Object");
        BL *ballLauncher = [[[BL alloc] init] initWithSpriteFrameName:@“launcher_1.png"];
        [ballLauncher setCharacterHealth:initialHealth];
        [ballLauncher setPosition:spawnLocation];
        [sceneSpriteBatchNode addChild:tBT z:ZValue tag:kBallLaucher ];
        [ballLauncher setDelegate:self];
        [ballLauncher release];
    }



}

**BELOW IS HOW I CONTROL WHEN THE BALL IS FIRED**

-(void)ChangeStateLaucher:(int)brandnewState withState:(CharacterStates)newState andObject:(GameObjectType)objectType; {


    BL *bL = (BL*)
    [sceneSpriteBatchNode getChildByTag:kBallLaucher];

    int x =  (arc4random() % 2);



    if (x==0) {
    CCLOG(@"Start Laucher Firing");
     [bL changeState:kStateFiring];

        count = 0;        

    }
    if (x==1) {
    CCLOG(@"No Laucher Firing");

      count = count + 1;

        if (count == 2) {
            CCLOG(@"No Laucher Firing x2 - Start Laucher Firing");

            [bL changeState:kStateFiring];

        } else if (count > 3) {
            CCLOG(@"No Laucher Firing x3 - Start Laucher Firing");

            [bL changeState:kStateFiring];

        }
    }


    [delegate ChangeStateLaucher:x withState:kStateFiring andObject:objectType];
    }

-(void)createPhaserWithDirection:(PhaserDirection)phaserDirection andPosition:(CGPoint)spawnPosition {
   CCLOG(@"Creating Ball from Gameplay Layer");
  Ball *ballSprite = [[Ball alloc]initWithSpriteFrame:[[CCSpriteFrameCache
                                                                  sharedSpriteFrameCache]
                                                                 spriteFrameByName:@"Ball_1.png"]];
   [ballSprite setPosition:spawnPosition];
    [ballSprite setMyDirection:phaserDirection];
    [ballSprite setCharacterState:kStatespawning];
    [ballSprite setCharacterHealth:3.0f];
    [sceneSpriteBatchNode addChild:ballSprite z:20  tag:kEnemyTypeBall];

    [ballSprite release];
}



-(id)init {
    self = [super init];

    if (self !=nil) {
        CGSize screenSize = [CCDirector sharedDirector]. winSize;

        self.TouchEnabled = YES;

        srandom(arc4random()); // Seeds the random number generator


            [[CCSpriteFrameCache sharedSpriteFrameCache]
             addSpriteFramesWithFile:@"scene1atlas.plist"];          // 1
            sceneSpriteBatchNode =
            [CCSpriteBatchNode batchNodeWithFile:@"scene1atlas.png"]; // 2




        [self createObjectOfType:kBallLaucher  withHealth:3 atLocation:ccp(screenSize.width * 0.05f, screenSize.height * 0.822f) withZValue:10];




        [gameBeginLabel setPosition:ccp(screenSize.width/2,screenSize.height/2)];          // 2
        [self addChild:gameBeginLabel];                                    // 3
        id labelAction = [CCSpawn actions:
                          [CCFadeOut actionWithDuration:2.5f],
                          nil];                                          // 4
        [gameBeginLabel runAction:labelAction];

        lives = 3;


        scoreLabel = [CCLabelBMFont labelWithString:@"$0"
                                            fntFile:@“BallTest.fnt"];

        scoreLabel.position = ccp(screenSize.width * 0.5f, screenSize.height * 0.9f);
        [self addChild:scoreLabel
                     z:-1 tag:kNewScoreTagValue];

        [self scheduleUpdate];

    }
    return self;
}


@end

我再次感谢任何花时间看这个问题的人,无论你是否发布了指针或答案。

感谢。

1 个答案:

答案 0 :(得分:1)

我认为当屏幕上有多个Ball对象时,GamePlayLayer update方法无法接收其中一个球的状态变化,因为该球是一进入kStateScore即被删除。 如果你在移除球之前添加一定的延迟,更新方法应该检测所有球的变化,你的问题应该得到解决。

Ball.m -(void)changeState:(CharacterStates)newState函数中,修改状态kStateScore上的操作,如

action = [CCSequence actions:[CCDelayTime actionWithDuration:0.2],
                      [CCCallFunc actionWithTarget:self selector:@selector(removeSelf)],
                      nil];

尝试一下,让我知道这是否适合你!

修改

上述解决方案最终会增加多个点,因为球会因延迟而长时间保持在kStateScore状态。为了解决这个问题,我们可以引入一个新的状态调用kStateDead,并在添加点后将球状态更改为kStateDead。这将确保一个点只添加一次,我们也可以将球移除到kStateDead状态。新代码如下:

Ball.m

case kStateScore:

            PLAYSOUNDEFFECT(SCORE);

            CCLOG(@“Ball Past Left Of Screen => Add 1 to Score");

            break;

case kStateDead:

        action = [CCSequence actions:
                      [CCCallFunc actionWithTarget:self selector:@selector(removeSelf)],
                      nil];

        default:
            CCLOG(@“Ball -> Unknown CharState %d",
                  characterState);

            break;

并在你的Gameplayer.m中

if ([tempChar characterState] == kStateScore)  <==HERE I AM SEEING IF THE BALL HAS SCORED - THIS IS ALSO WHERE I THINK I MAY BE GOING WRONG SOMEHOW.
    {
        CCLOG(@"Add 1 Points To Score");

        [self addPoint];
        [tempChar changeState:kStateDead]; //change the state to dead after the point is added
        return;
     }