如何在存在重力的情况下拖动和轻弹 SpriteKit 中的节点?

How to drag and flick a node in SpriteKit while gravity is present?

使用我当前的代码,节点非常滞后,并且在轻弹时由于某种原因在随机方向移动或传送。我该如何解决这个问题,也有人可以解释为什么它会传送并移动到场景中的随机位置。

还有,有没有办法让节点只有在被拖离它的位置时才移动,而不是一直在手势识别器的坐标上?


    override func didMove(to view: SKView) {
    let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.pan(_:)))
    

    view.addGestureRecognizer(gestureRecognizer)
    circleNode.physicsBody = SKPhysicsBody(circleOfRadius: 20)
    self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
    self.addChild(circleNode)
}


@objc func pan(_ recognizer: UIPanGestureRecognizer) {
   

    
    if recognizer.state == .changed {

        self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        var location = recognizer.location(in: self.view!)
        location = self.convertPoint(fromView: location)
        
        
        circleNode.position = location
        
        
        
        
    }
    
    if recognizer.state == .ended {
        self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
        let transformerX = 1024/self.view!.frame.size.width
        let transformerY = 768/self.view!.frame.size.height
        let velocity = recognizer.velocity(in: self.view)
        circleNode.physicsBody?.applyForce(CGVector(dx: velocity.x * transformerX, dy: velocity.y * transformerY))



    }
    
    
    
}

   

为什么不简单地根据滑动手势向对象施加力,而不是关闭重力,手动移动对象,然后在滑动结束时再次打开重力?

这是我正在研究的一些代码。我可以拖动和轻弹长矛(长矛图片),还可以“弹出”一个猪头。这是整个 GameScene.Remove 您不需要的代码。 :)

 import SpriteKit
 import CoreMotion

class GameScene: SKScene, SKPhysicsContactDelegate  {

  enum CollisionTypes: UInt32{
    case spear = 1
    case wall = 2
    case head = 4
  }


  var touchPoint: CGPoint = CGPoint()
  var touching: Bool = false

override func didMove(to view: SKView) {
    self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
    //Add contact delegate
    physicsWorld.contactDelegate = self
    self.backgroundColor = .white
    
    self.addChild(spearNode)
    self.addChild(headNode)
}



lazy var spearNode: SKSpriteNode = {
    let node = SKSpriteNode(imageNamed: "spear2")
    node.name = "Spear"
    node.physicsBody = SKPhysicsBody(texture: node.texture!,
                                     size: CGSize(width: node.frame.width  , height: node.frame.height))
    node.position = CGPoint(x:self.frame.midX , y:self.frame.midY)
    node.physicsBody?.affectedByGravity = true
    node.physicsBody?.allowsRotation = false
    node.size = CGSize(width: node.frame.width , height: node.frame.height )
    node.physicsBody?.categoryBitMask = CollisionTypes.spear.rawValue
    node.physicsBody?.contactTestBitMask = CollisionTypes.head.rawValue
    node.physicsBody?.collisionBitMask = CollisionTypes.head.rawValue
    return node
}()

lazy var headNode: SKSpriteNode = {
    let node = SKSpriteNode(imageNamed: "Pig")
    node.name = "Pig"
    node.physicsBody = SKPhysicsBody(texture: node.texture!,
                                     size: CGSize(width: node.frame.width  , height: node.frame.height))
    node.position = CGPoint(x:self.frame.midX , y:self.frame.maxY - 100)
    node.physicsBody?.affectedByGravity = true
    node.physicsBody?.allowsRotation = false
    node.size = CGSize(width: node.frame.width / 2  , height: node.frame.height / 2 )
    node.physicsBody?.categoryBitMask = CollisionTypes.head.rawValue
    return node
    
}()

func didBegin(_ contact: SKPhysicsContact){
    guard let nodeA = contact.bodyA.node else {return}
    guard let nodeB = contact.bodyB.node else {return}
    
    print("Contacted")
    
    if nodeA.name == "Pig" && nodeB.name == "Spear"{
        nodeA.removeFromParent() 
    }
    
    if nodeA.name == "Spear" && nodeB.name == "Pig"{    
        nodeB.removeFromParent()
    }
}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first!
    let location = touch.location(in:self)
    
    if spearNode.frame.contains(location) {
        touchPoint = location
        touching = true
    }
}


override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first!
    let location = touch.location(in: self)
    touchPoint = location
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    touching = false
}


override func update(_ currentTime: TimeInterval) {
    physicsWorld.gravity = CGVector(dx:0, dy: -9.8)
    
    if touching {
        let dt:CGFloat = 1.0/60.0
        let distance = CGVector(dx: touchPoint.x-spearNode.position.x, dy: touchPoint.y-spearNode.position.y)
        let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
        spearNode.physicsBody!.velocity=velocity
    }
  }
}