IOS - 应用程序使用Cocos2d在游戏中冻结

时间:2014-08-01 14:10:32

标签: ios objective-c cocos2d-iphone

我刚刚开始开发一款新的Objective-c游戏。基本上此刻你可以移动宇宙飞船,宇宙飞船不断射击,并且有小行星从屏幕顶部射出。但我的应用程序每次冻结一分钟为什么会这样?

CODE

#import "AppDelegate.h"

#pragma mark - HelloWorldLayer

// HelloWorldLayer implementation
@implementation HelloWorldLayer

// Helper class method that creates a Scene with the HelloWorldLayer as the only child.
+(CCScene *) scene
{
    // 'scene' is an autorelease object.
    CCScene *scene = [CCScene node];

    // 'layer' is an autorelease object.
    HelloWorldLayer *layer = [HelloWorldLayer node];

    // add layer as a child to scene
    [scene addChild: layer];

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
-(id) init
{
    if( (self=[super init]) ) {
        self.isTouchEnabled = YES;

        moveLeft = NO;
        moveRight = NO;

        speed = 3;
        fireSpeed = 8;

        fireArray = [[NSMutableArray alloc] init];

        CGSize winSize = [[CCDirector sharedDirector] winSize];
        CCSprite *bg = [[CCSprite alloc] initWithFile:@"space_bg.jpg"];
        [bg setPosition:ccp(160, 240)];
        CGSize imageSize = bg.contentSize;
        bg.scaleX = winSize.width / imageSize.width;
        bg.scaleY = winSize.height / imageSize.height;
        bg.position = ccp(winSize.width/2, winSize.height/2);
        [self addChild:bg];

        ship = [[CCSprite alloc] initWithFile:@"ship.png"];
        [ship setPosition:ccp(100, 100)];
        [self addChild:ship];

        [self schedule:@selector(fireLoop:)];

        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1
                                                          target:self
                                                        selector:@selector(fireCreate)
                                                        userInfo:nil
                                                         repeats:YES];
        int t = arc4random() % 5;
        timer3 = [NSTimer scheduledTimerWithTimeInterval:t
                                                  target:self
                                                selector:@selector(asteroidTimer)
                                                userInfo:nil
                                                 repeats:YES];
    }
    return self;
}

NSTimer *timer3;
NSTimer *timer2;
NSTimer *tmpTimer;

-(void)asteroidTimer {
    int t = arc4random() % 10;
    timer2 = [NSTimer scheduledTimerWithTimeInterval:0
                                              target:self
                                            selector:@selector(asteroidCreate)
                                            userInfo:nil
                                             repeats:YES];
}

-(void)asteroidCreate {

    [timer2 invalidate];
    [tmpTimer invalidate];
    CGSize winSize = [[CCDirector sharedDirector] winSize];

    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"asteroids.plist"];
    CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode batchNodeWithFile:@"asteroids.png"];

    NSMutableArray *asteroidAnimFrames = [NSMutableArray array];

    for(int i=1; i <= 8; i++) {
        [asteroidAnimFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"asteroid%d.png", i]]];
    }

    CCAnimation *moveAsteroidAnim = [CCAnimation animationWithFrames:asteroidAnimFrames delay:0.1f];

    CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:@"asteroid1.png"];
    int x = arc4random() % 320;
    int y = arc4random() % 480;
    asteroid.position = ccp(x, 480);
    CCAction *asteroidAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:moveAsteroidAnim restoreOriginalFrame:NO]];

    int q = arc4random() % 320;
    int r = arc4random() % 10;
    CCAction *moveAction = [CCMoveTo actionWithDuration:r position:ccp(q, -50)];

    [asteroid runAction:moveAction];
    [asteroid runAction:asteroidAction];
    [spriteSheet addChild:asteroid];
    [self addChild:spriteSheet];


    int t = arc4random() % 10;
    tmpTimer = [NSTimer scheduledTimerWithTimeInterval:t
                                                target:self
                                              selector:@selector(asteroidTimer)
                                              userInfo:nil
                                               repeats:YES];
}

-(void)fireLoop:(ccTime)fl {

    if(fireArray.count > 0) {
        for(int i = 0; i < fireArray.count; i++){
            CCSprite *tmpFire = [fireArray objectAtIndex:i];
            if(tmpFire.position.y < 500){
                [tmpFire setPosition:ccp([tmpFire position].x, [tmpFire position].y + fireSpeed)];
            }else{
                [fireArray removeObjectAtIndex:i];
            }
        }
    } else
    {

    }
}

-(void)fireCreate {
    int shootPositionX = [ship position].x;
    int shootPositionY = ([ship position].y) + 35;

    CCSprite *fire;
    fire = [[CCSprite alloc] initWithFile:@"fire.png"];
    [fire setPosition:ccp(shootPositionX, shootPositionY)];
    [fireArray addObject:fire];
    [self addChild:fire];
    [fire release];
}

-(void)gameLoop:(ccTime)dt {
    int shipPositionX = 41/2;
    if([ship position].x > shipPositionX){
        [ship setPosition:ccp([ship position].x - speed, [ship position].y)];
    }
}

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event  {
    for(UITouch *t in touches){
        CGPoint point = [self convertTouchToNodeSpace:t];
        //if(point.x <= 160){
        //    moveRight = NO;
        //    moveLeft = YES;
        //}else{
        //    moveRight =YES;
        //    moveLeft = NO;
        //}

        if(allowedToMove)
            [ship setPosition:ccp(point.x, point.y + 76)];
    }
}

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    for(UITouch *t in touches){
        CGPoint point = [self convertTouchToNodeSpace:t];

        int shipX = [ship position].x;
        int shipY = [ship position].y;

        if (CGRectContainsPoint(CGRectMake (shipX - 20.5, shipY - 96, 50, 50), point))
        {
            allowedToMove = true;
        }
    }
}

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    for(UITouch *t in touches){
        CGPoint point = [self convertTouchToNodeSpace:t];
        pointXLeft = point.x;
        pointYLeft = point.y;
        allowedToMove = false;
    }
}

// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
    // in case you have something to dealloc, do it in this method
    // in this particular example nothing needs to be released.
    // cocos2d will automatically release all the children (Label)

    // don't forget to call "super dealloc"
    [super dealloc];
}

1 个答案:

答案 0 :(得分:1)

一般来说,追踪似乎导致它的原因。调试器说什么?你是否停止执行或在可能有问题的地方设置断点?异常断点怎么样?如果那些不工作的人拿出你的计时器,看看你是否有任何改变。你的火力方法怎么样?

你对定时器的使用看起来很奇怪,应该是你看的第一个区域。旁注,对于小行星,你为什么不使用CCSpawn运行你想要在新小行星上运行的两个动作?

此外,你是否曾经从屏幕上射出的射弹或不再需要的小行星?如果没有,你应该。

但是要回答你的问题,问题看起来很可能是计时器问题。你使用定时器是错误的。你有定时器-3调用小行星定时器,它反过来创建调用小行星创建的定时器-2,这反过来使定时器-2无效(间隔为0使得它看起来有点不必要)并且还创建了一个tmp-timer称为小行星创造。定时器3可以连续完成它想要的操作,这是上述所有步骤,每隔x秒。尽管tmp-timer似乎试图产生更多的小行星创造并接管这个过程,但它看起来既错误又奇怪。而你正在用一些全局计时器来做这件事,这些计时器似乎有一个有效的计时器,但被一个新的分配所覆盖,只是为了在不久之后被另一种方法随机失效,即使它试图在技术上无效的东西已经泄露而且不再有一个指向它的指针,从而使错误的实例无效到错误的计时器。请记住,您的tmp-timer和timer-3具有随机间隔。如果tmp-timer的间隔为3秒,而timer-3在某个时刻有9秒的间隔,那么看起来肯定会出错。很难说通过如何看待它,但看起来不可避免。

或者至少我认为这就是正在发生的事情。同样,代码使用定时器非常奇怪并且可能容易出错。

此外,计时器-1将继续创建未经检查的精灵,而这些精灵不会消失。值得肯定的事情。

修改(解决方案):

如果我理解你想要做什么,你想要创建每个可变秒数的计时器,最后创建一个新的小行星。这有两个突出的事情。你想要一些东西来调用小行星的创建,还有其他东西来做实际的创建:

- (void)countDownToCreateNextAsteroid
{
    int minTime = 1;
    int maxTime = 10;

    int randomTime = (arc4random() % (maxTime - minTime)) + minTime;

    id countdownDelay = [CCDelayTime actionWithDuration:randomTime];
    id creationMethod = [CCCallFunc actionWithTarget:self selector:@selector(createAsteroid)];

    id countdownToCreateSeq = [CCSequence actions:countdownDelay, creationMethod, nil];

    [self stopAllActions];
    [self runAction:countdownToCreateSeq];
}


- (void)createAsteroid
{
    CGPoint someStartPosition = ccp(1024.0f, 512.0f);

    CCSprite* asteroid = [CCSprite spriteWithFile:@"someImage.png"];
    asteroid.position = someStartPosition;

    // asterdoid dot yada yada = ....

    [self addChild:asteroid];

    float someDuration = 10.0f;
    CGPoint someOffscreenPos = ccp(-1024.0f, 512.0f);

    // Move off screen, then remove yourself...

    id asteroidMove = [CCMoveTo actionWithDuration:someDuration
                                          position:someOffscreenPos];

    id asteroidRemove = [CCCallBlock actionWithBlock:^
    {
        [asteroid removeFromParentAndCleanup:YES];
    }];

    id asteroidSeq = [CCSequence actions:asteroidMove, asteroidRemove, nil];
    [asteroid runAction:asteroidSeq];

    [self countDownToCreateNextAsteroid];
}

因此,在你的onEnter上,你可以有所收获的东西,并且就是这样:

- (void)onEnter
{
    [super onEnter];

    // yada yada

    [self countDownToCreateNextAsteroid];
}

剩下的就会照顾好自己。这假设这种快速而简单的方法就是你所追求的。倒计时方法设置倒计时,调用方法在该时间结束时创建小行星,然后退出。创建小行星后,将调用对倒计数方法的新调用,这将设置另一个在另一个随机时间创建的小行星。这是一种快速而简单的方法,可以完成您实际上尝试使用所有计时器完成的工作。