4

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

            }
        }
Astrum
  • 375
  • 6
  • 21
  • 1
    SKFieldNode has a magnetic field – Knight0fDragon Nov 18 '16 at 00:44
  • @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 them – Astrum Nov 18 '16 at 02:25
  • 1
    never used it, just know it has what you want. Start at documentation.https://developer.apple.com/reference/spritekit/skfieldnode – Knight0fDragon Nov 18 '16 at 02:27
  • @Knight0fDragon Is there another way to do it without using an SKFieldNode? – Astrum Nov 18 '16 at 02:35
  • sure, but why would you want to do that? you have the tool learn how to use it, guess, make mistakes – Knight0fDragon Nov 18 '16 at 02:37
  • @Knight0fDragon I would still like to know how to do it without an SKFieldNode even if I end up doing it using an SKFieldNode. – Astrum Nov 18 '16 at 03:03
  • You could run a block of code inside an SKAction that moves one node to your magnets position, then repeat that action forever – DreamerNo56 Nov 18 '16 at 03:48
  • @DreamerNo56 could you provide an example please – Astrum Nov 18 '16 at 05:13
  • This may be what you're looking for http://stackoverflow.com/questions/31500104/simulate-universal-gravitation-for-two-sprite-kit-nodes – 0x141E Nov 18 '16 at 06:56
  • Fields are part of physics in SpriteKit, and one of them provides a magnetic style attraction. Count your blessings, and pursue that technique until it's exhaustively proven as inappropriate in some way. Chances are it's exactly what you want. @Knight0fDragon has steered you correctly. If there's nothing online about these things, I doubt asking someone here (where most programming bloggers and writers spend at least some of their time) then you can be pretty sure the world is a bit dry on details, and you'll have to experiment to get it working. And this is the case. Very few use SK Fields. – Confused Nov 18 '16 at 19:25
  • Take a look at this as well : http://stackoverflow.com/q/36230619/3402095 – Whirlwind Nov 19 '16 at 07:49
  • I suggest you avoid using a magnetic field because 1) it doesn't seem to work correctly and 2) even if it did work, it doesn't do what you want. A magnetic field causes objects to rotate around the center of the field. – 0x141E Nov 20 '16 at 07:44
  • @Whirlwind I tried using that code in the link you gave me and it seems to work well but then again it doesn't i have updated my original post with an edit to show what is going on with it because it doesn't seem to follow the y-axis to the player's (magnets) location. but i seems to follow the x-axis fine. – Astrum Dec 21 '16 at 16:04

1 Answers1

3

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.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    This doesn't work the way I want it to because it only goes to the top of the screen when pressed i need it to go to a certain position that is always changing due to the fact i am moving the the magnet all the time and along with this when i change the position of the circle to be the middle of the screen it doesn't go to the circle position instead it just keeps going past the circle to the top of the screen. The way i want it is for it to be like a vacuum sucking up all the coins and gems i come across in my game when it gets within a certain radius of the magnet. – Astrum Nov 21 '16 at 00:17
  • @Astrum You could always make the x and y values of the vector of the magnet be variables. Those variables could be determined by using the x and y values of the moving magnet and the node(s) being magnetized. You would also have to do some calculations. Disclaimer: this is purely hypothetical and not tested – Nik Nov 24 '16 at 01:04