ios - 将 SpriteNode 与碰撞表面对齐 SpriteKit Swift3

标签 ios swift sprite-kit

我试图对齐 SKSpriteNode 以匹配碰撞时 PhysicsBody 的“撞击表面”。

我正在做的是将 SpriteNode 射向立方体。我已经设置了碰撞和节点附件(固定关节)。 一切正常,但我需要找到一种方法来旋转 spriteNode 以匹配命中表面,如下所示:

enter image description here

请注意,立方体可以旋转等,因此我们并不总是在立方体上有固定的旋转值。

有什么解决办法吗?

提前致谢 /马格纳斯

最佳答案

以下是我认为可行的大部分答案。稍后我会更新。

基本上,目标是将两个粘性节点分别放置在接触点的磁铁和立方体上。

然后,您将磁铁的 zRotation 与立方体的旋转相匹配,然后根据两个粘性节点的位置将磁铁与立方体对齐。

我还没有完成旋转匹配或粘性对齐,但是如果你想完成其他一切都在这里,直到我稍后再做:

// Props:
class GameScene: SKScene, SKPhysicsContactDelegate {

  struct Category {
    static let
    border = UInt32(2),
    cube = UInt32(4),
    magnet = UInt32(8)
  }

  let names = (border: "border", cube: "cube", magnet: "magnet", stickyPoint: "stickyPoint")

  var flag_hitThisSimulation = false
}


// Setup:
extension GameScene {

  private func setupNodes() {
    border: do {
      let pb = SKPhysicsBody(edgeLoopFrom: frame)
      pb.categoryBitMask = Category.border
      physicsBody = pb
    }
    cube: do {
      let cubeNode = SKSpriteNode(color: .blue, size: CGSize(width: 150, height: 150))
      let pb = SKPhysicsBody(rectangleOf: cubeNode.size)
      pb.affectedByGravity = false
      pb.isDynamic = false
      pb.categoryBitMask = Category.cube
      pb.contactTestBitMask = Category.magnet
      cubeNode.physicsBody = pb
      cubeNode.position.y += 200
      cubeNode.name = names.cube
      cubeNode.run(.repeatForever(.rotate(byAngle: 3.14, duration: 3)))
      addChild(cubeNode)
    }
    magnet: do {
      let magnetNode = SKSpriteNode(color: .green, size: CGSize(width: 50, height: 12))
      let pb = SKPhysicsBody(rectangleOf: magnetNode.size)
      pb.categoryBitMask = Category.magnet
      pb.affectedByGravity = false
      magnetNode.physicsBody = pb
      magnetNode.name = names.magnet
      addChild(magnetNode)
    }
  }

  override func didMove(to view: SKView) {

    removeAllChildren()
    physicsWorld.contactDelegate = self
    setupNodes()

  }
}

// Physics:
extension GameScene {

  private func assignNodeOfName(_ name: String, contact: SKPhysicsContact) -> SKNode? {
    guard let nodeA = contact.bodyA.node, let nodeB = contact.bodyB.node else { fatalError("how are there no nodes?") }
    if      nodeA.name == name { return nodeA }
    else if nodeB.name == name { return nodeB }
    else                       { return nil   }
  }

  private func addNodeToPoint(_ point: CGPoint, parent: SKNode) {
    let node = SKSpriteNode(color: .orange, size: CGSize(width: 5, height: 5))
    node.position = point
    node.name = names.stickyPoint
    parent.addChild(node)
  }

  func alignMagnetToCube() {

  }

  func didBegin(_ contact: SKPhysicsContact) {
    defer { flag_hitThisSimulation = true }
    if flag_hitThisSimulation { return }

    let contactedNodes = contact.bodyA.categoryBitMask + contact.bodyB.categoryBitMask

    switch contactedNodes {

    case Category.magnet + Category.cube:
      // Place the two sticky nodes:
      let cube   = assignNodeOfName(names.cube,   contact: contact)!
      let magnet = assignNodeOfName(names.magnet, contact: contact)!

      let cubePoint   = convert(contact.contactPoint, to: cube)
      let magnetPoint = convert(contact.contactPoint, to: magnet)

      addNodeToPoint(cubePoint,   parent: cube)
      addNodeToPoint(magnetPoint, parent: magnet)

      // Set the magnet's zRotation to the cube's zRotation, then align the two stickyNodes:
      // fluidity.SLEEPY(for: now)
      // finish.later()

    default: ()
    }
  }
}

// Game loop:
extension GameScene {

  // Change to touchesBegan for iOS:
  override func mouseDown(with event: NSEvent) {

    let magnet = childNode(withName: names.magnet) as! SKSpriteNode

    // Start simulation:
    magnet.removeAllActions()
    magnet.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 25))

    // End simulation:
    magnet.run(.wait(forDuration: 2)) {
      print("resetting simulation! \(event.timestamp)")
      magnet.physicsBody!.velocity = CGVector.zero
      magnet.zRotation = 0 // FIXME: This isn't working..
      magnet.position = CGPoint.zero
      self.flag_hitThisSimulation = false

      // Remove sticky nodes:
      for node in self.children {
        for childNode in node.children {
          if childNode.name == self.names.stickyPoint { childNode.removeFromParent() }
        }
      }
    }
  }
}

关于ios - 将 SpriteNode 与碰撞表面对齐 SpriteKit Swift3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44986417/

相关文章:

swift - 为什么 Swift 认为我的数组是一个函数?

iOS - 绘制渐变 - Swift

ios - 计算游戏结束的节点

ios - layoutSubview 重置 UILabel 的属性

ios - 重新加载 tableview ios 8 时编辑选项消失

swift - 根据段显示正确的文本颜色?

ios - 作为一个单元旋转时重叠 SpriteNode

ios - 如何使节点位置适应横向和纵向

ios - 是否可以在 Cordova 应用程序中将静态图像放在 webview 的顶部

ios - 表格 View 重叠单元格swift2