Cocos 2D - 从另一个类改变游戏角色状态

时间:2013-11-21 14:51:21

标签: iphone objective-c class cocos2d-iphone

我在业余时间从Ray Wenderlich的书中学习Cocos2D,但如果它没有解释如何做一些我认为自己将来需要的东西,也会对它进行修改。我目前因为知识非常有限而陷入困境。

我希望使用GamePlayLayer类随机更改TBT类的字符状态。

我已经检查了每个状态并且它们都工作(通过使它们成为spawn状态进行检查)所以问题最有可能发生在我试图制作自己的方法的gamePlayLayer.m文件中。

我似乎能够让它将状态更改为kStateThrowing但它会在播放动画之前直接返回(以0.3秒为单位!)到kStateIdle并具有以下输出...

2013-11-21 13:45:07.938 Spaceviking[981:12c03] CHANGING STATE TBT!!!!!!

2013-11-21 13:45:07.939 Spaceviking[981:12c03] TBT->Changing State to throwing

2013-11-21 13:45:07.967 Spaceviking[981:12c03] TBT Going to Idle

2013-11-21 13:45:07.970 Spaceviking[981:12c03] TBT->changing state to idle

对此的任何帮助将不胜感激。

下面列出的代码......

//  CommonProtocols.h

#ifndef SpaceViking_CommonProtocols_h
#define SpaceViking_CommonProtocols_h

typedef enum {
    kDirectionLeft,
    kDirectionRight
}
PhaserDirection;

typedef enum {
    kStatespawning,
    kStateIdle,
    kStateWalking,
    kStateIdleTilt,
    kStatebackTilting,
    kStateforwardTilting,
    kStateAttacking,
    kStateTakingDamage,
    kStateThrowing,
    kStateLosingALife,
    kStateDead,
    kStateTravelling,
    kStateRotating,
    kStatetest

}
CharacterStates; //1

typedef enum {
    kObjectTypeNone,
    kPowerUpTypeHealth,
    kPowerTypeMallet,
    kEnemyType1BT,
    kEnemyType2BT,
    kEnemyType3BT,
    kEnemyTypePhaser,
    kVikingType,

} GameObjectType;


@protocol GamePlayLayerDelegate

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

-(void)createPhaserWithDirection: (PhaserDirection)phaserDirection
                     andPosition:(CGPoint)spawnPosition;


#endif

//  GamePlayLayer.h

#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "CCLayer.h"
#import "SneakyJoystick.h"
#import "SneakyButton.h"
#import "SneakyButtonSkinnedBase.h"
#import "SneakyJoystickSkinnedBase.h"
#import "Constants.h"
#import "CommonProtocols.h"
#import "TBT.h"

@interface GamePlayLayer : CCLayer <GamePlayLayerDelegate> {
    CCSprite *vikingSprite;
    SneakyJoystick *leftJoystick;
    SneakyButton *jumpButton;
    SneakyButton *attackButton;
    CCSpriteBatchNode *sceneSpriteBatchNode;
}
@end

------------------------------------------------

//  GamePlayLayer.m
#import "GamePlayLayer.h"

@implementation GamePlayLayer
-(void) dealloc {
    [leftJoystick release];
    [jumpButton release];
    [attackButton release];
    [super dealloc];
    }

    --DELETED BELOW 2 METHODS AS NOT NEEDED FOR THIS QUESTION--
-(void)initJoystickAndButtons {
    }
-(void)applyJoystick:(SneakyJoystick *)aJoystick toNode: (CCNode *)tempNode forTimeDelta:(float)deltaTime
{  
    }

-(void) update:(ccTime)deltaTime {
    CCArray *listOfGameObjects =
    [sceneSpriteBatchNode children];                     
    for (GameCharacter *tempChar in listOfGameObjects) {         
        [tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:listOfGameObjects];                         
    }
}
-(void) createObjectOfType: (GameObjectType)objectType
                withHealth:(int)initialHealth atLocation:(CGPoint)spawnLocation withZValue:(int)ZValue {
    if (objectType == kEnemyType1BT) {
        CCLOG(@"creating 1BT");
        TBT *tBT = [[TBT alloc] initWithSpriteFrameName:@"BT_anim_1.png"];
        [tBT setCharacterHealth:initialHealth];
        [tBT setPosition:spawnLocation];
        [sceneSpriteBatchNode addChild:tBT
                                     z:ZValue
                                   tag:k1BTTagValue];
        [tBT release]; 
    }
}

--BELOW IS THE METHOD I HAVE CREATED TO CHANGE THE STATE--

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

    int x =  (arc4random() % 3);

    TBT *tBT = [[TBT alloc]
                  initWithSpriteFrame:[[CCSpriteFrameCache
                                        sharedSpriteFrameCache]
                                       spriteFrameByName:@"BT_anim_1.png"]];
    if (x>0) {
        CCLOG(@"CHANGING STATE TBT!!!!!!");

        [tBT changeState:kStateThrowing];

        [tBT setDelegate:self];
        [tBT release];    
    }   
}

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

    if (self !=nil) {
        CGSize screenSize = [CCDirector sharedDirector]. winSize;
        self.TouchEnabled = YES;
        srandom(time(NULL)); 

        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
            [[CCSpriteFrameCache sharedSpriteFrameCache]
             addSpriteFramesWithFile:@"scene1atlas.plist"];          // 1
            sceneSpriteBatchNode =
            [CCSpriteBatchNode batchNodeWithFile:@"scene1atlas.png"]; // 2
        } else {
            [[CCSpriteFrameCache sharedSpriteFrameCache]
             addSpriteFramesWithFile:@"scene1atlasiPhone.plist"];          // 1
            sceneSpriteBatchNode =
            [CCSpriteBatchNode batchNodeWithFile:@"scene1atlasiPhone.png"];
        }
        [self addChild:sceneSpriteBatchNode z:0];                
        [self initJoystickAndButtons];                           
        BC *viking = [[BC alloc]
                          initWithSpriteFrame:[[CCSpriteFrameCache
                                                sharedSpriteFrameCache]
                                               spriteFrameByName:@"BCmoving_anim_1.png"]];            
        [viking setJumpButton:jumpButton];
        [viking setAttackButton:attackButton];
        [viking setPosition:ccp(screenSize.width * 0.19f,
                                screenSize.height * 0.19f)];
        [viking setCharacterHealth:3];

        [sceneSpriteBatchNode
         addChild:viking
         z:kVikingSpriteZValue
         tag:kVikingSpriteTagValue];          



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

       ---THE BELOW SELECTOR IS WHAT I HAVE USED TO DO A TIMED STATE CHANGE (METHOD ABOVE)--

       [self schedule:@selector(changeState:) interval:1.0f];

        [self scheduleUpdate];
    }
    return self;   
}
@end   

//  TBT.h

#import <Foundation/Foundation.h>
#import "GameCharacter.h"

@interface TBT : GameCharacter {   
    //This is for the required animations
    CCAnimation *tiltingAnim;
    CCAnimation *transmittingAnim;
    CCAnimation *loseLifeAnim;
    CCAnimation *throwingAnim;
    CCAnimation *afterThrowingAnim;    
    CCAnimation *shootPhaserAnim;    

    GameCharacter *vikingCharacter;
    id <GamePlayLayerDelegate> delegate;

}
@property (nonatomic,assign) id <GamePlayLayerDelegate> delegate;
@property (nonatomic, retain) CCAnimation *tiltingAnim;
@property (nonatomic, retain) CCAnimation *transmittingAnim;
@property (nonatomic, retain) CCAnimation *loseLifeAnim;
@property (nonatomic, retain) CCAnimation *throwingAnim;
@property (nonatomic,retain) CCAnimation *afterThrowingAnim;
@property (nonatomic,retain) CCAnimation *shootPhaserAnim;

-(void)initAnimations;
-(void)changeState:(CharacterStates)newState;
@end


//  TBT.m
#import "TBT.h"

@implementation TBT

@synthesize delegate;
@synthesize tiltingAnim;
@synthesize transmittingAnim;
@synthesize loseLifeAnim;
@synthesize throwingAnim;
@synthesize afterThrowingAnim;
@synthesize shootPhaserAnim;

-(void) dealloc {
    delegate = nil;

    [tiltingAnim release];
    [transmittingAnim release];
    [loseLifeAnim release];
    [throwingAnim release];
    [afterThrowingAnim release];
    [shootPhaserAnim release];

    [super dealloc];
}
--BELOW METHOD NOT NEEDED FOR THIS QUESTION
-(void)shootPhaser {}

-(CGRect)TBTboundingBox {
    CGRect tbtBoundingBox = [self boundingBox];
    float xOffset;
    float xCropAmount = tbtBoundingBox.size.width * 0.5482f;
    float yCropAmount = tbtBoundingBox.size.height * 0.1f;

    tbtBoundingBox =
    CGRectMake(tbtBoundingBox.origin.x + xOffset,
               tbtBoundingBox.origin.y,
               tbtBoundingBox.size.width - xCropAmount,
               tbtBoundingBox.size.height - yCropAmount);

    return tbtBoundingBox;

}

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

    [self setCharacterState:newState];

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


        case kStateIdle:
            CCLOG(@"TBT->schaning state to idle");
            [self setDisplayFrame:
             [[CCSpriteFrameCache sharedSpriteFrameCache]
              spriteFrameByName:@"BT_anim_1.png"]];

            break;

        case kStateThrowing:
            CCLOG(@"TBT->Changing State to throwing");
            action = [CCSequence actions:
                      [CCAnimate actionWithAnimation:throwingAnim
                                restoreOriginalFrame:NO],
                      [CCDelayTime actionWithDuration:1.0f],
                      //[CCAnimate actionWithAnimation:shootPhaserAnim
                      //          restoreOriginalFrame:NO],
                      [CCCallFunc actionWithTarget:self
                                          selector:@selector(shootPhaser)],
                      [CCAnimate actionWithAnimation:afterThrowingAnim
                                restoreOriginalFrame:NO],
                      [CCDelayTime actionWithDuration:0.1f],
                      nil];

            break;

        case kStateLosingALife:
            CCLOG(@"TBT->Losing a life");

            break;

            case kStateDead:
            CCLOG(@"TBT->changing state to dead");
            action = [CCAnimate actionWithAnimation:loseLifeAnim];

            break;

        default:
            CCLOG(@"unhandled state %d in TBT", newState);
            break;
    }
    if (action !=nil) {
        [self runAction:action];
        }
}

-(void)updateStateWithDeltaTime: (ccTime)deltaTime andListOfGameObjects:(CCArray*)listOfGameObjects {
    if (characterState == kStateDead)
        return;
    vikingCharacter =
    (GameCharacter*)[[self parent]
                     getChildByTag:kVikingSpriteTagValue];
    CGRect vikingBoudingBox =
    [vikingCharacter adjustedBoundingBox];
    CharacterStates vikingState = [vikingCharacter characterState];
    if ((vikingState == kStateAttacking) && (CGRectIntersectsRect ([self adjustedBoundingBox], vikingBoudingBox))) {
        if (characterState != kStateTakingDamage) {
            [self changeState:kStateTakingDamage];
            return;
        }
    }
    if ((([self numberOfRunningActions] == 0) && (characterState != kStateDead)) ) {
        CCLOG(@"TBT Going to Idle");
        [self changeState:kStateIdle];
        return;
    }

}


-(void)initAnimations {  
    [self setTransmittingAnim:[self loadPlistForAnimationWithName:@"transmittingAnim" andClassName:NSStringFromClass([self class])]];

    [self setThrowingAnim:[self loadPlistForAnimationWithName:@"throwingAnim" andClassName:NSStringFromClass([self class])]];

    [self setAfterThrowingAnim:[self loadPlistForAnimationWithName:@"afterThrowingAnim" andClassName:NSStringFromClass([self class])]];
}

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

            CCLOG(@"### TBT initialized");
            [self initAnimations];                                   
            characterHealth = 3.0f;                               
            gameObjectType = kEnemyType1BT;                    
            [self changeState:kStatespawning];                       
            }
    }
    return self;  
}
@end

1 个答案:

答案 0 :(得分:0)

我的猜测是你没有将TBT对象作为孩子添加到任何东西(即CCScene / CCNode / CCSprite)。尝试将其添加到“sceneSpriteBatchNode”中,就像在createObjectOfType:方法中一样。

[sceneSpriteBatchNode addChild:tBT
                       z:ZValue
                       tag:k1BTTagValue];