在 SKScene 中间保留一个物理体?

Posted

技术标签:

【中文标题】在 SKScene 中间保留一个物理体?【英文标题】:Keeping a physicsBody in the middle of the SKScene? 【发布时间】:2015-09-23 14:36:22 【问题描述】:

我不知道如何提出这个问题,但我的 SKScene 中有一个 SKSpriteNode。我希望它位于 y 轴的中间,但在滑动(向上/向下)时,重力会影响它,直到它返回到 y 轴的中间。

设置示例: 1- SKSpriteNode 在其默认位置(在 x 轴上的位置并不重要,但在 y 轴的中间) 2- 用户向上滑动 3- SKSpriteNode 在 +y 或 -y 方向上受到 applyImpulse() 的影响 4- 重力在 -y 或 +y(分别)方向上影响 SKSpriteNote 5- SKSpriteNode 移回其默认位置(由于重力)

我将如何执行此操作? 我尝试过的事情: -radialGravityField(没有像我预期的那样表现) - linearGravityFieldWithVector(我有点失败) - 创建 2 个具有不同重力的矩形(失败得很惨) - 检查 SKSpriteNode y 位置是否小于或 > 屏幕中间,具体取决于滑动是向上还是向下,如果是,则重置位置。签入didSimulatePhysics。这不起作用,据我所知,它会重置位置,但是在调试时,即使在重置之后 SKSpriteNode 也不在 y 轴的中间

如果您需要我的代码,请告诉我,但我正在寻找的只是一种方法

谢谢:)

编辑

这是我用来检查精灵位置是否 而不是 y 轴中间的代码

override func didMoveToView(view: SKView) 

//set the players default position
playerDefaultPosition = CGPoint(x: self.size.width * 0.2, y: self.size.height / 2)


//background
backgroundColor = SKColor.whiteColor()

//world physics
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)

//create player
playerNode.position = playerDefaultPosition
playerNode.physicsBody = SKPhysicsBody(rectangleOfSize: playerNode.size)
playerNode.physicsBody?.mass = 300
playerNode.physicsBody?.linearDamping = 0

addChild(playerNode)





override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) 
    if let yTouch = touches.first?.locationInNode(self).y 
        self.touches.append(yTouch)
        startTime = NSDate()

        
    

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) 
    if let yTouch = touches.first?.locationInNode(self).y 
        self.touches.append(yTouch)

    


override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) 
    if let yTouch = touches.first?.locationInNode(self).y 
        endTime = NSDate()
        self.touches.append(yTouch)
        if !self.touches.isEmpty 
            let velocity = getVelocity(self.touches, startTime: startTime, endTime: endTime)
            movePlayer(velocity)

        


    

func getVelocity(touchArray: [CGFloat], startTime: NSDate, endTime: NSDate) -> CGFloat 
    var v: CGFloat = 0
    if !touchArray.isEmpty 

        //get velocity from v = d/t
        let t = CGFloat(endTime.timeIntervalSinceDate(startTime))
        let d = touchArray.last! - touchArray.first!
        v = d / t
    

    return v



func movePlayer(v: CGFloat) 
    let vector = CGVector(dx: 0.0, dy: v * 30)

    if vector.dy > 0 
        //player going in +y direction
        swipedUp = true
        self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -10)
     else 
        //player going in -y direction
        swipedUp = false
        self.physicsWorld.gravity = CGVector(dx: 0.0, dy: 10)
    

    playerNode.physicsBody?.applyImpulse(vector)




override func didSimulatePhysics() 

    if playerNode.position.y < (self.view?.frame.height)! / 2 - 1 && swipedUp || playerNode.position.y > (self.view?.frame.height)! / 2 + 1 && !swipedUp 

        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        playerNode.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 0))
        print("gravity set to 0")
        playerNode.position = playerDefaultPosition

    


经过更多的调试,似乎设置了playerNode.position = playerDefaultPosition后,下一帧的playerNode.position.y &lt; (self.view?.frame.height)! / 2 - 1 &amp;&amp; swipedUp仍然为真

编辑 2

查看documentation,我实现了一帧期间调用的每个函数,并在每个函数调用期间检查了playerNode.position.y 的位置,似乎当SKScene 模拟使playerNode 从其默认位置移动到一个不同的。

【问题讨论】:

也许给它更多的错误,然后只是 -1 尝试 -10 或其他东西。 @Steve 不走运。我将(self.view?.frame.height)! / 2 - 1 更改为(self.view?.frame.height)! / 2 - 10 以夸大发生的任何事情,我可以看到节点出现在(self.view?.frame.height)! / 2 - 10,然后又回到defaultPlayerPosition 等等。 也许尝试用向量(0,0)给它一个冲动?抱歉,我现在没有 xCode 来尝试任何东西。 没关系,感谢您的帮助。我尝试将 applyImpulse 设置为 (0,0) 但没有运气。现在会继续努力寻找。 【参考方案1】:

也许只检查节点的 y 位置以及当节点的 y )关闭该节点的重力时。滑动后重新开启。

【讨论】:

忘了我试过了,编辑过的问题。出于某种原因,它会重置位置,但在下一帧,SKSpriteNode 被移动了。【参考方案2】:

尝试将脉冲向量在 Y 方向设置回 0

override func update(currentTime: NSTimeInterval) 

    if playerNode.position.y < (self.view?.frame.height)! / 2 - 1 && swipedUp || playerNode.position.y > (self.view?.frame.height)! / 2 + 1 && !swipedUp 

        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        print("gravity set to 0")
        let vector = CGVector(dx: 0.0, dy: 0.0)
        playerNode.physicsBody?.applyImpulse(vector)
        playerNode.position = playerDefaultPosition


    


【讨论】:

也试过了。有关帧数据的信息,请参阅编辑后的帖子【参考方案3】:

@Steve 在didSimulatePhysics() 中对applyImpulse() 说是在正确的轨道上。由于物体仍然有作用力(由于它下落),我不得不将其移除。 你可以通过找到它下降的力量来做到这一点(这对我来说比需要的代码更多)或者我可以将它设为.dynamic = false 并在需要时重新启用它。

这是我现在拥有的:

override func didFinishUpdate() 
    print(playerNode.position.y)
    if playerNode.position.y < (self.view?.frame.height)! / 2 - 10 && swipedUp || playerNode.position.y > (self.view?.frame.height)! / 2 + 10 && !swipedUp 
        //turn off all forces on the Node    
        playerNode.physicsBody?.dynamic = false
        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        playerNode.position = playerDefaultPosition
    


【讨论】:

很高兴你找到它。我知道它必须与类似的东西有关

以上是关于在 SKScene 中间保留一个物理体?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SKSpriteNode 中正确封装触摸事件处理并将数据传回 SKScene

iPad 模拟器上的 SKScene 问题无法在 Xcode 11 beta 7 中填满屏幕

didBeginContact:(SKPhysicsContact *)联系人未调用

如何给屏幕边缘一个物理体

Unity之碰撞体组件

如何在没有物理的情况下检测碰撞