4
votes

My Goal: To get an SKSpriteNode to move to another SKSpriteNodes position. (To create a magnet for my sprite kit game)

Hi, I am trying to get multiple SKSpriteNodes with the same name to move towards and collide with an sprite node that i’m going to be calling a magnet i just don’t understand where or how i would go about doing this, i have tried using this code but i’m left scratching my head on what to do:

func update(_ currentTime: TimeInterval) {

   let node = childNode(withName: "specialObstacle")

        let magnetLocation = magnet.position
        let specialObjectLocation = node?.position

        let x = node?.position.x - magnetLocation.x
        let y = node?.position.y - magnetLocation.y

}

Note: My magnet’s location will be changing due to the fact the user will be moving the magnet around the screen and would like it to keep going towards the magnet but i just can’t figure out how to do this.

EDIT 1

I tried using the code you had whirlwind and it seems to work for the x-axis but it seems to not work for the y axis for some reason it looks like it tries to go down but fails and just vibrates in the one spot. i have added my code below and a image

whirlwind

HERE is the code i'm using:

 let playerLocation:CGPoint = self.convert(thePlayer.position, from: worldNode)

        let location = playerLocation
        let nodeSpeed:CGFloat = 3.5

        worldNode.enumerateChildNodes(withName: "levelUnit"){
            node, stop in

            let levelUnit:LevelUnit = node as! LevelUnit  //cast as an actual LevelUnit class


            levelUnit.enumerateChildNodes(withName: "specialObstacle"){
                node, stop in

                //Aim
                let dx = location.x - (node.position.x)
                let dy = location.y - (node.position.y)
                let angle = atan2(dy, dx)

                node.zRotation = angle

                //Seek
                let vx = cos(angle) * nodeSpeed
                let vy = sin(angle) * nodeSpeed

                node.position.x += vx
                node.position.y += vy

            }
        }
1
SKFieldNode has a magnetic fieldKnight0fDragon
@Knight0fDragon Could you provide an example on how to use an SKFieldNode because this is the first time i'm hearing about it and can't find any in depth tutorial that shows me how they work or how to implement themAstrum
never used it, just know it has what you want. Start at documentation.developer.apple.com/reference/spritekit/skfieldnodeKnight0fDragon
@Knight0fDragon Is there another way to do it without using an SKFieldNode?Astrum
sure, but why would you want to do that? you have the tool learn how to use it, guess, make mistakesKnight0fDragon

1 Answers

3
votes

Something like this?

enter image description here

Code

First of all here's the code

import SpriteKit

class GameScene: SKScene {

    let magnet = SKFieldNode.linearGravityField(withVector: vector_float3(0, 9.8 * 2, 0))
    let circle = SKShapeNode(circleOfRadius: 30)
    override func didMove(to view: SKView) {
        circle.fillColor = .white
        circle.position.x = 0
        circle.position.y = frame.maxY
        addChild(circle)

        magnet.region = SKRegion(size: self.frame.size)
        magnet.isEnabled = false
        magnet.categoryBitMask = 0x1            
        circle.addChild(magnet)

        self.physicsBody = SKPhysicsBody(edgeLoopFrom: frame)

        for i in 0..<20 {
            let ball = SKShapeNode(circleOfRadius: 30)
            ball.fillColor = .yellow
            ball.physicsBody = SKPhysicsBody(circleOfRadius: 30)
            ball.position.x = CGFloat(i) * 10
            ball.physicsBody!.fieldBitMask = 0x1
            addChild(ball)
        }

        let ball = SKShapeNode(circleOfRadius: 30)
        ball.fillColor = .green
        ball.physicsBody = SKPhysicsBody(circleOfRadius: 30)
        ball.position.y = 40
        ball.physicsBody!.fieldBitMask = 0x2
        addChild(ball)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        circle.fillColor = .red
        magnet.isEnabled = true
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        circle.fillColor = .white
        magnet.isEnabled = false
    }
}

How does it work?

Here there are the core concepts

  1. There's an SKFieldNode on top of the screen whose categoryBitMask is 0x1
  2. The yellow balls have a physics body with fieldBitMask = 0x1 (this will make the interact with the FieldNode)
  3. The green ball has a physics body with fieldBitMask = 0x2 (which makes it not affected by the SKFieldNode)

Finally I am simply turning on/off the SKFieldNode when you touch/untouch the screen.

Oh, and there's a red sprite exactly at the same position of the SKFieldNode but that's only for UI reasons.