【问题标题】:How to properly remove node when out of screen bounds?超出屏幕范围时如何正确删除节点?
【发布时间】:2014-06-11 18:19:46
【问题描述】:

我正在开发一个 sprite-kit 游戏,其中节点在屏幕最低点下方生成,并且重力设置为让它们漂浮到屏幕顶部。一切正常,但它很快就开始减慢 FPS,最终滞后和故障变得非常缓慢。我认为解决这个问题的方法是在它们超过一个点后从父节点中删除节点,这是我在更新中使用的代码:

-(void)update:(CFTimeInterval)currentTime {

    if (_bubble1.position.y > CGRectGetMaxX(self.frame)+40) {
        [self removeFromParent];
    }

}

如果需要,这就是我在initWithSize 方法下方生成气泡的方式:

-(void)didMoveToView:(SKView *)view {

    [self performSelector:@selector(spawnBubbles) withObject:nil afterDelay:1.0];
    [self performSelector:@selector(spawnBubbles1) withObject:nil afterDelay:1.5];

}

-(void)spawnBubbles {
    randomPosition = arc4random() %260*DoubleIfIpad;
    randomPosition = randomPosition + 20*DoubleIfIpad;

    randomNumber = arc4random() %7;
    randomNumber = randomNumber + 1;

    myColorArray = [[NSArray alloc] initWithObjects:colorCombo1, colorCombo2, colorCombo3, colorCombo4, colorCombo5, colorCombo6, colorCombo7, colorCombo8, nil];
    myRandomColor = [myColorArray objectAtIndex:randomNumber];

    _bubble1 = [SKShapeNode node];
    [_bubble1 setPath:CGPathCreateWithEllipseInRect(CGRectMake(-25*DoubleIfIpad, -25*DoubleIfIpad, 50*DoubleIfIpad, 50*DoubleIfIpad), nil)];
    _bubble1.strokeColor = _bubble1.fillColor = myRandomColor;
    _bubble1.position = CGPointMake(randomPosition, CGRectGetMinY(self.frame)-60);
    _bubble1.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20];
    _bubble1.physicsBody.categoryBitMask = CollisionBubble;

    [self addChild:_bubble1];

    [self runAction:[SKAction sequence:@[
                                         [SKAction waitForDuration:1.0],
                                         [SKAction performSelector:@selector(spawnBubbles) onTarget:self],
                                         ]]];

}

如何才能使节点在离开屏幕时得到妥善处理?以及如何将 FPS 保持在 60 FPS 的恒定速率?

提前致谢!!

【问题讨论】:

  • "FPS" 仅与节点数松散相关。其他因素将对此做出更多贡献。
  • 真的吗?!喜欢什么@BradAllred
  • 你只有一个bubble ivar,以后你需要使用一个数组来访问它们。使用您的更新代码,您将只能删除最后创建的气泡。您可以更轻松地让每个气泡运行一个自定义操作,该操作经常检查其位置并在必要时调用 removeFromParent。

标签: ios objective-c xcode sprite-kit


【解决方案1】:

我建议使用 spritekit 中内置的接触检测。创建一个模仿屋顶的 skspritenode,该屋顶具有设置为检测与气泡接触的物理主体。在屋顶节点和气泡节点之间创建一个接触事件,该事件将简单地移除气泡。这将确保消除气泡并保持恒定的 FPS。

联系人调用事件示例:

- (void)bubble:(SKSpritenode*)bubble didCollideWithRoof:(SKSpriteNode*)roof{
[bubble removeFromParent];}

接触检测示例:

- (void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
    firstBody = contact.bodyA;
    secondBody = contact.bodyB;
}
else
{
    firstBody = contact.bodyB;
    secondBody = contact.bodyA;
}

if (firstBody.categoryBitMask==bubbleCategory && secondBody.categoryBitMask == roofCategory)
{
    [self bubble:(SKSpriteNode*)firstBody.node didCollideWithRoof:(SKSpriteNode*)secondBody.node];
}}

泡泡需求:

 _bubble.physicsBody.contactTestBitMask = roofCategory;

屋顶:

SKSpriteNode *roof = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(self.scene.size.width, 1)];   
roof.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.scene.size.width, 1)];

    roof.position = CGPointMake(self.scene.size.width/2,self.scene.size.height)
    roof.physicsBody.dynamic = NO;
    roof.physicsBody.categoryBitMask = floorCategory;
    roof.physicsBody.contactTestBitMask = bubbleCategory;
    [self addChild:roof];

【讨论】:

    【解决方案2】:

    使用 Swift 1.1 / iOS 8,您可以使用以下模式来解决您的问题。


    1.使用以下代码初始化场景的 physicsBody 属性:

    physicsBody = SKPhysicsBody(edgeLoopFromRect: frame) // or CGRectInset(frame, -10, -10) if you need insets 
    

    2。为您的场景和精灵节点创建类别蒙版:

    let boundaryCategoryMask: UInt32 =  0x1 << 1
    let someNodeCategoryMask: UInt32 =  0x1 << 2
    

    3.为您的场景和精灵节点physicsBody 属性设置正确的categoryBitMaskcollisionBitMaskcontactTestBitMask

    // Scene
    physicsBody!.categoryBitMask = boundaryCategoryMask
    
    // Sprite node
    /* ... */
    someNode.physicsBody!.categoryBitMask = someNodeCategoryMask
    someNode.physicsBody!.contactTestBitMask = boundaryCategoryMask 
    

    例如,以下 Swift SKScene 实现向您展示了如何删除超出场景框架的所有精灵节点:

    class GameScene: SKScene, SKPhysicsContactDelegate {
    
        let boundaryCategoryMask: UInt32 =  0x1 << 1
        let squareCategoryMask: UInt32 =  0x1 << 2
    
    
        override func didMoveToView(view: SKView) {
            // Scene
            backgroundColor = SKColor.whiteColor()
            physicsWorld.contactDelegate = self
            physicsBody = SKPhysicsBody(edgeLoopFromRect: frame)
            physicsBody!.categoryBitMask = boundaryCategoryMask
    
            // Square
            let square = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 80, height: 80))
            square.zPosition = 0.1
            square.position = CGPoint(x: size.width / 2.0 - square.size.width / 2, y: size.height - square.size.height)
            square.physicsBody = SKPhysicsBody(rectangleOfSize: square.frame.size)
            square.physicsBody!.dynamic = true
            square.physicsBody!.affectedByGravity = true
            square.physicsBody!.categoryBitMask = squareCategoryMask
            // square.physicsBody!.collisionBitMask = 0 // don't set collisions (you don't want any collision)
            square.physicsBody!.contactTestBitMask = boundaryCategoryMask // this will trigger -didBeginContact: and -didEndContact: 
            addChild(square)
        }
    
        override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
            // Check if the array containing the scene’s children is empty
            println("children: \(children)")
        }
    
        func didBeginContact(contact: SKPhysicsContact) {
            if contact.bodyA.categoryBitMask == squareCategoryMask {
                contact.bodyA.node?.removeFromParent()
                println("square removed")
            }
    
            if contact.bodyB.categoryBitMask == squareCategoryMask {
                contact.bodyB.node?.removeFromParent()
                println("square removed")
            }
        }
    
        func didEndContact(contact: SKPhysicsContact) {
            /* ... */
        }
    
        override func update(currentTime: CFTimeInterval) {
            /* Called before each frame is rendered */
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2011-09-26
      • 1970-01-01
      • 2019-11-23
      • 2015-02-04
      • 2022-10-14
      相关资源
      最近更新 更多