ios – SpriteKit moving nodes with gesture


I’m practicing with writing SpriteKit games.
I’m trying to write merge game using SpriteKit (https://plays.org/merge-the-gems/).
enter image description here

For now I’ve created game scene with board, added gems on board and created moving interaction.

Here is Gem node’s code:

import SpriteKit

class Gem: SKSpriteNode {
    
    private var touchOffset: CGPoint = CGPoint.zero
    private var originalPosition: CGPoint = CGPoint.zero
    
    init(size: CGSize) {
        super.init(
            texture: nil,
            color: .red,
            size: size
        )
        let numberLabel: SKLabelNode = .init(text: name)
        
        physicsBody = SKPhysicsBody(rectangleOf: .init(width: size.width - 2, height: size.height))
        physicsBody?.affectedByGravity = true
        physicsBody?.restitution = 0
        physicsBody?.friction = 0
        physicsBody?.allowsRotation = false
        physicsBody?.categoryBitMask = 0b0001
        physicsBody?.collisionBitMask = 0b0001
        physicsBody?.contactTestBitMask = 0b0001
        
        physicsBody?.node?.zPosition = 1
        
        physicsBody?.isDynamic = true
        
        isUserInteractionEnabled = true
        
        addChild(numberLabel)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        physicsBody?.affectedByGravity = false
        
        let location = touch.location(in: parent!)
        
        if contains(location) {
            
            touchOffset = CGPoint(x: position.x - location.x, y: position.y - location.y)
            originalPosition = position
        }
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        
        let location = touch.location(in: parent!)
        
        var newPosition = CGPoint(x: location.x + touchOffset.x, y: location.y + touchOffset.y)
        
        newPosition.x = max(min(newPosition.x, (scene?.size.width ?? 0) - size.width / 2), size.width / 2)
        newPosition.y = max(min(newPosition.y, (scene?.size.height ?? 0) - size.height / 2), size.height / 2)
        
        
        position = newPosition
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        let column: Int = Int(position.x / size.width)
        
        position.x = (CGFloat(column) * size.width) + (size.width / 2)
        
        physicsBody?.affectedByGravity = true
    }
}

Here’s scene code:

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {
    
    override init(size: CGSize) {
        super.init(size: size)
        setupScene()
        createGameBoard()
        isUserInteractionEnabled = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setupScene() {
        physicsWorld.gravity = CGVector(dx: 0, dy: -7)
        physicsWorld.contactDelegate = self
        
        let borderBody: SKPhysicsBody = .init(edgeLoopFrom: self.frame)
        borderBody.friction = 0
        borderBody.restitution = 0
        
        self.physicsBody = borderBody
    }
    
    func createGameBoard() {
        let gemWidth: CGFloat = size.width / 6.0
        let gemSize: CGSize = .init(width: gemWidth, height: gemWidth)
        
        for row in 0..<8 {
            for column in 0..<6 {
                let positionX: CGFloat = CGFloat(column) * gemWidth + gemWidth / 2
                let positionY: CGFloat = size.height - (CGFloat(row) * gemWidth + gemWidth / 2)
           
                let backgroundNode: SKSpriteNode = getBackgroundNode()
                backgroundNode.size = gemSize
                backgroundNode.position = CGPoint(x: positionX, y: positionY)
                
                addChild(backgroundNode)
                
                if row >= 6 {
                    let gem: Gem = .init(size: gemSize)
                    
                    gem.size = gemSize
                    gem.position = CGPoint(x: positionX, y: positionY)
                    
                    addChild(gem)
                    gems.append(gem)
                }
            }
        }
    }

    
    func getBackgroundNode() -> SKSpriteNode {
        let background: SKSpriteNode = .init(imageNamed: "Diamond/empty")
        background.isUserInteractionEnabled = false
        return background
    }
}

Problem.
The problem is I can’t achieve same behavior as in example, where I can move gem only when there is no other gems on it’s way. Now it’s just pushing other gems. I need exactly the same moving behavior as in example above.

While I’m moving gem with gesture I need other gems to be “walls”, so I can slide along their sides.

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img