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

221 views Asked by At

With my current code, the node is extremely laggy, and moves or teleports in random directions for some reason when its flicked. How can i fix this, and also can someone explain why it is teleporting and moving to random places in the scene.

Also, is there anyway to allow the node to be moved only when it is dragged from its position, rather than being at the gesturerecognizer's coordinates at all times?


    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))



    }
    
    
    
}

   

2

There are 2 answers

12
Stefan Ovomate On BEST ANSWER

enter image description hereHere is some code I was playing around with. I'm able to drag and flick a spear (spear Image) and also "pop" a pig head. This is the whole GameScene.Remove the code you don't need. :)

 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
    }
  }
}
1
jglasse On

Why not simply impart a force to the object based upon the swipe gesture rather than turning off gravity, manually moving the object, and then turning on gravity again when the swipe is over?