Search code examples
iosswiftsprite-kitcollisionskspritenode

Contain a sprite node within the screen/view


I have a sprite node which moves left to right with user touch. However currently it will exit the screen, I want to add a node either side so if the sprite node touches the node on either side it hugs it and remains there until user touch to make it travel the opposite direction.

This is what I thought of doing but it isn't working currently.

    let shipTexture = SKTexture(imageNamed: "ship.png")
    ship = SKSpriteNode(texture: shipTexture)
    ship.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
    ship.zPosition = 3
    ship.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 100))
    ship.physicsBody!.isDynamic = true
    ship.physicsBody?.collisionBitMask = 0b1
    ship.physicsBody?.contactTestBitMask = 0b1
    ship.physicsBody!.collisionBitMask = 0b1
    ship.physicsBody?.affectedByGravity = false
    self.addChild(ship)



    let side = SKNode()
    side.position = CGPoint(x: self.frame.width / 2, y: self.frame.midY)

    side.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: -240, y: -160, width: 480, height: 320))

    side.physicsBody!.isDynamic = false
    side.physicsBody?.collisionBitMask = 0b1
    side.physicsBody?.contactTestBitMask = 0b1
    side.physicsBody!.collisionBitMask = 0b1

    self.addChild(side)

    func didBegin(_ contact: SKPhysicsContact) {
        print("Collision")
    }
}

//var moveLeft = SKAction.moveBy(x: 800, y: 0, duration: 2)
//frame.size.width




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




    ship.removeAllActions()

    switch direction ?? .left {
    case .left:
        ship.run(SKAction.moveBy(x: -frame.size.width, y: 0, duration: 3))
    case .right:
        ship.run(SKAction.moveBy(x: frame.size.width, y: 0, duration: 3))
    }

    direction = direction == nil || direction == .right ? .left : .right
}

Solution

  • I got it. The reason is - you use action to move your node, but should use physics - force and impulse

    Try this one:

    import SpriteKit
    import GameplayKit
    
    var ship = SKSpriteNode()
    var bg = SKSpriteNode()
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
    
    
        override func didMove(to view: SKView) {
    
    
            let bgTexture = SKTexture(imageNamed: "bg.png")
            let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
            let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
            let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
    
            var i: CGFloat = 0
    
            while i < 3 {
    
                bg = SKSpriteNode(texture: bgTexture)
                bg.position = CGPoint(x: self.frame.midX, y: bgTexture.size().height * i)
                bg.size.width = self.frame.width
    
                bg.run(moveBGForever)
                self.addChild(bg)
    
                i += 1
    
            }
    
            let shipTexture = SKTexture(imageNamed: "ship.png")
            ship = SKSpriteNode(texture: shipTexture)
            ship.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
            ship.zPosition = 3
            ship.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 100))
            ship.physicsBody!.isDynamic = true
            ship.physicsBody?.collisionBitMask = 0b1
            ship.physicsBody?.contactTestBitMask = 0b1
            ship.physicsBody!.categoryBitMask = 0b1
            ship.physicsBody?.affectedByGravity = false
            self.addChild(ship)
    
            let side = SKNode()
            side.position = CGPoint(x: 0, y: 0)
            side.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: -self.frame.width/2, y: -self.frame.height/2, width: self.frame.width, height: self.frame.height))
    
            side.physicsBody!.isDynamic = false
            side.physicsBody?.collisionBitMask = 0b1
            side.physicsBody?.contactTestBitMask = 0b1
            side.physicsBody!.categoryBitMask = 0b1
    
            self.addChild(side)
    
            self.physicsWorld.contactDelegate = self
    
            func didBegin(_ contact: SKPhysicsContact) {
                print("Collision")
            }
    
        }
    
        //var moveLeft = SKAction.moveBy(x: 800, y: 0, duration: 2)
        //frame.size.width
    
        enum Direction: Int {
            case left = 0
            case right
        }
    
        var direction: Direction?
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    
    
    
    
            ship.removeAllActions()
    
            switch direction ?? .left {
            case .left:
                ship.physicsBody?.applyImpulse(CGVector(dx: -20, dy: 0))
                //ship.run(SKAction.moveBy(x: -frame.size.width, y: 0, duration: 3))
            case .right:
                ship.physicsBody?.applyImpulse(CGVector(dx: 20, dy: 0))
                //ship.run(SKAction.moveBy(x: frame.size.width, y: 0, duration: 3))
            }
    
            direction = direction == nil || direction == .right ? .left : .right
        }
    
    
    
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    
    
    
        }
    
        override func update(_ currentTime: TimeInterval) {
    
    
        }
    }