HomeiOS DevelopmentSpriteKit dragging a node with a SKPhysicsJointSpring is there a option to...

SpriteKit dragging a node with a SKPhysicsJointSpring is there a option to get the spring to trace its anchor level tightly however damp quickly?


A major mechanic of a undertaking I’m engaged on goes to contain dragging objects along with your fingers and having the item being dragged work together correctly with physics, pushing different objects away.

I created this proof of idea with 5 inexperienced containers meant to be hit by a crimson field that follows the finger location (in debug mode marked in blue) and makes use of a spring joint.

The difficult bit right here is that I want the physics physique for the crimson field I’m transferring to not be static. So I have to someway transfer it in a manner the physics simulation can react to. I’ve heard of individuals making use of the fingers motion as velocity to the physics node however I don’t count on this to work almost as easily as if I might simulate a really tight rubber band which damps rapidly someway.

Points with transferring with velocity:

  • If you happen to push the crimson field into an object that object pushes again and because of this the crimson field is now not beneath your finger and is step by step additional away.

Points with spring:

  • Would not really feel strongly sufficient hooked up to the dragging node
  • Oscillations/vibrations/loops and many others

See gif and code.

Are there values of damping/frequency/friction/mass that may get this to really feel good? As a notice I’m not certain why however the blue drag deal with node does collide with the inexperienced containers though it’s static and set to not collide… Unsure why.

class GameScene: SKScene {
    let field = {
        let node = DraggableNode(coloration: .crimson, measurement: CGSize(width: 50, peak: 50))
        node.place = CGPointMake(150, 150)
        node.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, peak: 50))
        node.physicsBody?.allowsRotation = false
        node.physicsBody?.affectedByGravity = false
        node.physicsBody?.isDynamic = true
        return node
    }()
    
    override func didMove(to view: SKView) {
        physicsBody = SKPhysicsBody(edgeLoopFrom: body)
        addChild(field)
        
        // Add smaller containers to collide with
        let targetCount = 5
        let targetSize = CGSize(width: 30, peak: 30)
        let targetY = measurement.peak * 0.75
        for i in 0..<targetCount {
            let fraction = (CGFloat(i) + 1) / CGFloat(targetCount + 1)
            let targetX = measurement.width * fraction
            let goal = SKSpriteNode(coloration: .inexperienced, measurement: targetSize)
            goal.place = CGPoint(x: targetX, y: targetY)
            goal.physicsBody = SKPhysicsBody(rectangleOf: targetSize)
            goal.physicsBody?.affectedByGravity = false
            goal.physicsBody?.allowsRotation = false
            addChild(goal)
        }
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with occasion: UIEvent?) {
        guard let contact = touches.first else { return }
        let location = contact.location(in: self)
        field.dragPosition = location
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with occasion: UIEvent?) {
        guard let contact = touches.first else { return }
        let location = contact.location(in: self)
        field.dragPosition = location
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with occasion: UIEvent?) {
        field.endDrag()
    }
    
    override func touchesCancelled(_ touches: Set<UITouch>, with occasion: UIEvent?) {
        field.endDrag()
    }
}

class DraggableNode: SKSpriteNode {
    let debug: Bool = true
    
    var dragPosition: CGPoint = .zero {
        didSet {
            updateDragConnection()
        }
    }
    
    personal var dragHandleNode: SKNode? = nil
    personal var dragJoint: SKPhysicsJointSpring? = nil
    
    personal func updateDragConnection() {
        if dragHandleNode == nil {
            beginDrag()
        }
        
        dragHandleNode?.place = dragPosition
    }
    
    func beginDrag() {
        assert(dragHandleNode == nil && dragJoint == nil)
        guard let scene = self.scene else {
            assertionFailure("Should be added to the scene for this to work")
            return
        }
        
        let deal with: SKNode
        if debug {
            deal with = SKSpriteNode(coloration: .blue, measurement: CGSize(width: 10, peak: 10))
        } else {
            deal with = SKNode()
        }
        deal with.physicsBody = SKPhysicsBody(circleOfRadius: 1)
        deal with.physicsBody?.isDynamic = false
        deal with.physicsBody?.affectedByGravity = false
        deal with.physicsBody?.allowsRotation = false
        // TODO: I supposed this to imply that the blue dot wouldn't collide with some other objects
        deal with.physicsBody?.collisionBitMask = 0
        deal with.physicsBody?.contactTestBitMask = 0
        dragHandleNode = deal with
        scene.addChild(deal with)
        deal with.place = dragPosition
        
        guard let handleBody = deal with.physicsBody else {
            assertionFailure("Sudden difficulty. Deal with has no physics physique")
            return
        }
        guard let nodeBody = self.physicsBody else {
            assertionFailure("Draggable node will need to have a physics physique")
            return
        }
        
        let distinction = CGPointMake(dragPosition.x - self.dragPosition.x, dragPosition.y - self.dragPosition.y)
        
        let joint = SKPhysicsJointSpring.joint(withBodyA: handleBody, bodyB: nodeBody, anchorA: dragPosition, anchorB: CGPointMake(place.x - distinction.x, place.y - distinction.y))
        // Try at fast dampening and being tied to the item
        joint.damping = 1.8
        joint.frequency = 2.5
        scene.physicsWorld.add(joint)
        dragJoint = joint
    }
    
    func endDrag() {
        guard let scene = self.scene else { return }
        if let joint = dragJoint {
            scene.physicsWorld.take away(joint)
            dragJoint = nil
        }
        dragHandleNode?.removeFromParent()
        dragHandleNode = nil
    }
}

// A pattern SwiftUI making a GameScene and sizing it
// at 300x400 factors
struct ContentView: View {
    var scene: SKScene {
        let scene = GameScene()
        scene.measurement = CGSize(width: 300, peak: 400)
        scene.scaleMode = .fill
        return scene
    }
    
    var physique: some View {
        SpriteView(scene: scene, debugOptions: .showsPhysics)
            .body(width: 300, peak: 400)
            .ignoresSafeArea()
    }
}

#Preview {
    ContentView()
}

With velocity the crimson field you might be "dragging" is rapidly away out of your finger

SpriteKit dragging a node with a SKPhysicsJointSpring is there a option to get the spring to trace its anchor level tightly however damp quickly?

With Spring there are undesirable oscillations/loops/jiggles

With Spring there are undesirable oscillations/loops/jiggles

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments