通过NSTimer添加SpriteNodes时,SKScene不会检测到联系

时间:2014-08-23 03:51:47

标签: objective-c cocoa sprite-kit

概述:我是从场景顶部添加一个敌人。敌人最初以150速度X向右移动。地图有左墙和右墙。当敌人他的左右墙时,他应该立即反转方向。

问题:当我从initWithSize调用函数spawnEnemy时,当敌人撞到每个墙壁时,敌人会按照预期的方向行事。当我使用NSTimer每2秒调用spawnEnemy时,SKScene不会识别敌人与墙壁接触并且不会反转敌人的方向。代码如下。

SPAWN ENEMY方法:

-(void)spawnEnemy{

    self.testingEnemy = [SKSpriteNode spriteNodeWithImageNamed:@"normalEnemy.png"];

    self.testingEnemy.position = (CGPoint) {
        CGRectGetMidX(self.scene.frame),
        300
    };

    self.testingEnemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.testingEnemy.frame.size];

    self.testingEnemy.physicsBody.dynamic = TRUE;

    self.testingEnemy.physicsBody.affectedByGravity = TRUE;

    self.testingEnemy.physicsBody.mass = 0.00150;

    self.testingEnemy.physicsBody.restitution = 0.0;

    self.testingEnemy.physicsBody.allowsRotation = FALSE;

    self.testingEnemy.physicsBody.linearDamping = 0.0;

    [self addChild:self.testingEnemy];
}

initWithSize

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {

        //[self spawnEnemy]; <--- This works with expected behavior

        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(spawnEnemy) userInfo:nil repeats:NO];

    }
    return self
}

didBeginContact

- (void)didBeginContact:(SKPhysicsContact *)contact
{   
    if (contact.bodyA == self.testingEnemy.physicsBody && contact.bodyB == [self.map rightWall].physicsBody) {
        NSLog(@"Hit right wall");

        normalEnemyVelocityX = -normalEnemyVelocityX;

    }
}

以下是项目文件的链接:

https://www.dropbox.com/s/e59piru3q1hcu0e/Goldrush.zip?dl=0

1 个答案:

答案 0 :(得分:2)

我的2美分......

  1. 你没有处理contact.bodyA是墙和contact.bodyB是敌人的情况。
  2. 您在哪里设置categoryBitMask和contactTestBitMask?
  3. 您应该考虑使用SKAction而不是NSTimer,因为当您暂停/恢复游戏时SKActions会暂停/恢复。
  4. 这是一个例子......

    SKAction *wait = [SKAction waitForDuration:2.0];
    SKAction *spawn = [SKAction performSelector:@selector(spawnEnemy) onTarget:self];
    SKAction *waitThenSpawn = [SKAction sequence:@[wait, spawn]];
    
    [self runAction:[SKAction repeatActionForever:waitThenSpawn]];
    

    编辑:尝试以下内容......

    1)代码不检查联系人体是否被交换,如果场景中有多个敌人,它将无法工作。这是解决这些问题的方法:

    static inline SKSpriteNode *bodyToNode(SKPhysicsBody *body1,
                                           SKPhysicsBody *body2,
                                           NSString *name) {
        SKSpriteNode *node = nil;
        if ([body1.node.name isEqualToString:name]) {
            node = (SKSpriteNode *)body1.node;
        }
        else if ([body2.node.name isEqualToString:name]) {
            node = (SKSpriteNode *)body2.node;
        }
        return node;
    }
    
    - (void)didBeginContact:(SKPhysicsContact *)contact
    {
        SKSpriteNode *enemyNode = nil;
        SKSpriteNode *wallNode = nil;
    
        enemyNode = bodyToNode (contact.bodyA, contact.bodyB, @"enemy");
        wallNode = bodyToNode (contact.bodyA,contact.bodyB, @"wall");
    
        if (enemyNode && wallNode) {
            NSLog(@"Hit right wall %@", self.testingEnemy);
            normalEnemyVelocityX = -normalEnemyVelocityX;
        }
    } 
    

    2)将以下内容从Map.m移到Map.h

    static const uint32_t playerCategory =  1 << 0;
    static const uint32_t platformCategory =  1 << 1;
    

    3)你没有为敌人设置类别,你需要命名敌人,以便didBeginContact正常工作。将以下内容添加到名为testing的方法中:

    self.testingEnemy.physicsBody.categoryBitMask = playerCategory;
    self.testingEnemy.name = @"enemy";
    

    4)在Map.m中,在代码中的适当位置添加以下内容:

    self.leftWall.name = @"wall";
    
    self.rightWall.name = @"wall";
    

    5)从此声明中删除playerCategory:

    self.bottomRightHorizWall.physicsBody.contactTestBitMask = platformCategory;