0

I am trying to make a maze app. The goal is to move a ball (drag the ball with your finger) through a "maze" like level which has traps and other dangers. However, when I made it so the ball/player moves when its dragged, it started to now phase though the other sprite nodes instead of staying inside of the level. How can I make it so it doesn't go outside of the level?

Code:

import SpriteKit
import GameplayKit



class GameScene: SKScene {

    var ball = SKSpriteNode()
    var danger1 = SKSpriteNode()
    var danger2 = SKSpriteNode()
    var goal = SKSpriteNode()


    override func didMove(to view: SKView) {

        ball = self.childNode(withName: "ball") as! SKSpriteNode
        danger1 = self.childNode(withName: "danger1") as! SKSpriteNode
        danger2 = self.childNode(withName: "danger2") as! SKSpriteNode
        goal = self.childNode(withName: "goal") as! SKSpriteNode

        let border = SKPhysicsBody(edgeLoopFrom: self.frame)
        border.friction = 0
        border.restitution = 0

        print("x: \(ball.position.x), y: \(ball.position.y)")

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)
            ball.position.x = location.x
            ball.position.y = location.y
        }
    }

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
    }
}

Screenshot of game: Maze Level

Schmob
  • 9
  • 3

2 Answers2

0

You need to set up a collisionBitMask for your nodes and set up your desired collision rules accordingly (i.e. prevent ball from clipping through the maze walls or dangers):

I'd recommend looking at the corresponding apple developer docs: https://developer.apple.com/documentation/spritekit/skphysicsbody/1520003-collisionbitmask

This other question's answer may also prove helpful: What are Sprite Kit's "Category Mask" and "Collision Mask"?

This was also a video that I found helpful when learning about bitmasks for detecting collisions & contact between SKSpriteNodes: https://youtu.be/467Doas5J6I?t=1114

*Edit*

You will also need to set up contact detection via contactTestBitMask so that you know when the ball has contacted the wall, at which point you can implement logic to ‘drop’ it from the dragging gesture. As @Steve Ives correctly noted, the dragging will override the collision physics and you would still get clipping without this.

10623169
  • 984
  • 1
  • 12
  • 22
  • 1
    Bear in mind that one your have physics, then dragging the ball can cause a problem as the physics tries to stop the ball moving through the wall, but as you drag it you’re actually attempting to override this. Try also setting up contact detection via `contactTestBitMask` so that you know when the ball has contacted the wall and you can ‘drop’ it from being dragged to prevent this. – Steve Ives Dec 12 '18 at 08:55
  • @SteveIves is correct here - you'll need to implement both contact and collision bit masks to get your desired behaviour. I shall amend my answer accordingly to explicitly state this. – 10623169 Dec 12 '18 at 11:51
0

Your major problem is you are moving your ball directly, ala hand of god.

What you need to do is play by the systems rules. Instead of applying the position directly, set the velocity of your ball to push your ball to where your finger is. This requires some math:

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in touches {
        //set the location's coordinate system to match the ball
        let location = touch.location(in: ball.parent)
        let angle = atan2(location.x,location.y)
        let velocity = 1.0f //(change this to whatever speed you want your ball to move at)
        ball.velocity =  CGVector(velocity * cos(angle),velocity * sin(angle)) // you may have to swap around the sin/-sin/cos/-cos to get it the way you like it,  I am assuming at angle 0 your ball is facing right, and it rotates in a counter clockwise direction)

    }
}

Now your ball will forever be pushed towards the touching point.

To avoid bouncing, make sure you set the restitution to 0 on the physics body so that it loses all of its energy when it hits a wall.

Also check categoryBitmask is of some power of 2 on all objects that require physics (1 works in your example) so that it can collide with whatever is in its way

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44