用物理学创建下雨动画

Posted

技术标签:

【中文标题】用物理学创建下雨动画【英文标题】:Creating rain animation with physics 【发布时间】:2015-02-08 16:38:11 【问题描述】:

我目前正在开发一个使用 SpriteKit 游戏技术以 Swift 编写的 ios 应用程序。在这个游戏中,雨滴从屏幕顶部落到底部。当它们到达底部时(由physicsBody 表示),它们应该返回到屏幕顶部的原始位置,从而使动画在游戏的整个生命周期中继续播放。

因为我只需要几滴,所以我这样制作它们:

let drop = SKSpriteNode(imageNamed: "drop")
drop.position = CGPointMake(x,y)
drop.physicsBody = SKPhysicsBody(rectangleOfSize: drop.size)
addChild(drop)

然后我创建位掩码:

drop.physicsBody!.categoryBitmask = DropCategory
bottom.physicsBody!.categoryBitmask = BottomCategory
drop.physicsBody!.contactTestBitmask = BottomCategory    

我添加了 didBeginContact 函数,当下降到达底部时我会收到通知。然后我的控制台显示“命中”。

func didBeginContact(contact: SKPhysicsContact) 

    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask 
        firstBody = contact.bodyA
        secondBody = contact.bodyB
     else 
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    

    if firstBody.categoryBitMask == BlockCategory && secondBody.categoryBitMask == GroundCategory 
        println("hit ground")

        firstBody.node?.removeFromParent()
        let drop = SKSpriteNode(imageNamed: "drop")
        drop.name = "testNode"
        drop.position = CGPointMake(self.frame.width - self.frame.width/3*2, self.frame.height) // At start Position
        drop.physicsBody = SKPhysicsBody(rectangleOfSize: drop.size)
        drop.physicsBody?.categoryBitMask = BlockCategory
        drop.physicsBody?.contactTestBitMask = GroundCategory
        addChild(drop)
    

但是,drop 的位置不会改变。没有语法错误,那我的问题是什么?

如果我替换这个:

firstBody.node!.position = CGPointMake(x, y)

用这个:

firstBody.applyImpulse(CGVector)

它给了下降的冲动。我怎样才能使第一个选项也起作用?

【问题讨论】:

您是否尝试过设置水滴物理体的质量? 为什么不使用粒子发射器?在 XCode 中创建新粒子文件时,甚至可以选择下雨模板。 此外,即使我认为使用物理系统对于您正在尝试做的事情来说太过分了,但下落不应该需要冲动。水滴只会受到重力的影响。 我想在水滴击中我的角色时得到通知,所以我需要物理系统。 是的,为什么不直接使用粒子发射器? 【参考方案1】:

您可以尝试在触及底部时删除节点,然后再次在顶部添加新节点。将纹理加载到单独的SKTexture 变量中以供重复使用。像这样

let dropTexture = SKTexture(imageNamed: "drop.png")

这样使用

let drop = SKSpriteNode(texture: dropTexture)

然后在didBeginContact里面

func didBeginContact(contact: SKPhysicsContact) 
    println("collided")
    var bodyA : SKPhysicsBody!
    var bodyB : SKPhysicsBody!

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask
    
        bodyA = contact.bodyA!
        bodyB = contact.bodyB!
    
    else
    
        bodyB = contact.bodyA!
        bodyA = contact.bodyB!
    

    if bodyA.categoryBitMask == bottomCategoryBitMask && bodyB.categoryBitMask == raindropCategoryBitMask
    
        if bodyB.node?.parent != nil // Added line
        
            bodyB.node?.removeFromParent()
            let drop = SKSpriteNode(imageNamed: "1.png")
            drop.name = "testNode"
            drop.position = CGPointMake(self.frame.width - self.frame.width/3*2, self.frame.height) // At start Position
            drop.physicsBody = SKPhysicsBody(rectangleOfSize: drop.size)
            drop.physicsBody?.categoryBitMask = raindropCategoryBitMask
            drop.physicsBody?.contactTestBitMask = bottomCategoryBitMask
            addChild(drop)
        
    

【讨论】:

每次水滴落到底部时,水滴的数量都会乘以 2,所以我最终有数百个。如果我删除了drop,然后告诉它添加一个新的drop,它怎么能得到两个。 是的,我认为当你使用图片作为drop时会更清晰。然后它会成倍增加。 即使我用图像尝试它也能正常工作。你能展示你更新的代码吗? firstBody.node?.removeFromParent() let block1 = SKSpriteNode(imageNamed: "block") block1.name = "testNode" block1.position = CGPointMake(self.frame.width - self.frame. width/3*2, self.frame.height) // 在开始位置 block1.physicsBody = SKPhysicsBody(rectangleOfSize: block1.size) block1.physicsBody?.categoryBitMask = BlockCategory block1.physicsBody?.contactTestBitMask = GroundCategory addChild(block1) 我更新了我的代码。添加 if 条件也 if firstBody.node?.parent != nil

以上是关于用物理学创建下雨动画的主要内容,如果未能解决你的问题,请参考以下文章

用缓动函数模拟物理动画

iOS基本动画/关键帧动画/利用缓动函数实现物理动画效果

SpriteKit 动画物理

计算机图形学动画

SKPhysicsBody 改变动画/物理速度

Sprite Kit 中的单个粒子和物理