You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift SpriteKit匹配游戏:双节点触摸追踪与纹理匹配/重置功能实现技术问询

Hey there! Let's tackle your matching game requirements step by step using SpriteKit in Swift. I'll start by breaking down the core logic gaps in your current code, then provide a complete, modified implementation that covers all three features you need.

Core Problem Breakdown

Your current code handles basic touch detection but lacks:

  • A way to track the two selected cards for comparison
  • State management for each card (original texture, matched texture, whether it's already paired)
  • Logic to disable interaction when cards match, or reset textures when they don't
Solution Implementation

1. Create a Custom MatchCard Class

First, let's make a reusable MatchCard subclass of SKSpriteNode to encapsulate each card's state and behavior. This will make your code cleaner and easier to maintain:

import SpriteKit

class MatchCard: SKSpriteNode {
    // Store the original back texture and the front match texture
    let originalTexture: SKTexture
    let matchTexture: SKTexture
    // Track if this card has already been matched (and should ignore touches)
    var isMatched: Bool = false
    
    init(originalImageName: String, matchImageName: String) {
        self.originalTexture = SKTexture(imageNamed: originalImageName)
        self.matchTexture = SKTexture(imageNamed: matchImageName)
        super.init(texture: originalTexture, color: .clear, size: CGSize(width: 150, height: 300))
        // Enable user interaction for the card
        isUserInteractionEnabled = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // Flip the card to show its match texture
    func flipToMatch() {
        texture = matchTexture
    }
    
    // Reset the card back to its original texture
    func resetToBack() {
        texture = originalTexture
    }
}

2. Modified EasyScreen Scene

Now let's update your EasyScreen class to manage selected cards, handle touch logic, and implement the matching/reset behavior:

import Foundation
import SpriteKit

class EasyScreen: SKScene {
    // Track the two currently selected (unmatched) cards
    private var selectedCards: [MatchCard] = []
    // Timer counter (made a property so we can manage it easily)
    private var timerCounter: Int = 90
    
    override func didMove(to view: SKView) {
        // Enable multi-touch (though we'll handle sequential taps, this ensures no restrictions)
        view.isMultipleTouchEnabled = true
        
        // Background setup
        let background = SKSpriteNode(imageNamed: "Easy Screen Background")
        background.position = CGPoint(x: size.width/2, y: size.height/2)
        background.size = size
        background.anchorPoint = CGPoint(x: 0.5,y: 0.5)
        addChild(background)
        
        // Timer label setup
        let timerText = SKLabelNode(fontNamed: "Arial")
        timerText.fontSize = 40
        timerText.fontColor = .white
        timerText.position = CGPoint(x: 20, y: 400)
        timerText.zPosition = 1
        timerText.text = " Time: \(timerCounter)"
        
        // Timer action
        timerText.run(SKAction.repeatForever(SKAction.sequence([
            SKAction.run { [weak self] in
                guard let self = self else { return }
                self.timerCounter -= 1
                timerText.text = " Time: \(self.timerCounter)"
                print("\(self.timerCounter)")
                
                if self.timerCounter <= 0 {
                    guard let newScene = TryAgainScreen(fileNamed: "Try Again Screen") else { return }
                    newScene.scaleMode = .aspectFill
                    self.view?.presentScene(newScene)
                }
            },
            SKAction.wait(forDuration: 1)
        ])))
        addChild(timerText)
        
        // Create all match cards using our custom class
        let card1 = MatchCard(originalImageName: "Fruit Match Card", matchImageName: "Apple")
        card1.name = "FruitMatchCard1"
        card1.position = CGPoint(x: -125, y: 60)
        card1.zPosition = 1
        
        let card2 = MatchCard(originalImageName: "Fruit Match Card", matchImageName: "Apple")
        card2.name = "FruitMatchCard2"
        card2.position = CGPoint(x: -125, y: -260)
        card2.zPosition = 1
        
        let card3 = MatchCard(originalImageName: "Fruit Match Card", matchImageName: "Grapes")
        card3.name = "FruitMatchCard3"
        card3.position = CGPoint(x: 70, y: 60)
        card3.zPosition = 1
        
        let card4 = MatchCard(originalImageName: "Fruit Match Card", matchImageName: "Grapes")
        card4.name = "FruitMatchCard4"
        card4.position = CGPoint(x: 70 , y: -260)
        card4.zPosition = 1
        
        // Sound button setup
        let soundButton = SKSpriteNode(imageNamed: "Sound On")
        soundButton.name = "Sound"
        soundButton.size = CGSize(width: 75, height: 75)
        soundButton.position = CGPoint(x: -180, y: -600)
        soundButton.zPosition = 3
        
        // Add all nodes to the scene
        addChild(card1)
        addChild(card2)
        addChild(card3)
        addChild(card4)
        addChild(soundButton)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let touchLocation = touch.location(in: self)
        let tappedNode = atPoint(touchLocation)
        
        // Handle sound button tap separately
        if tappedNode.name == "Sound" {
            print("Sound button tapped - add your toggle logic here!")
            return
        }
        
        // Make sure we tapped a MatchCard that hasn't been matched yet
        guard let tappedCard = tappedNode as? MatchCard, !tappedCard.isMatched else { return }
        
        // Don't let the user select more than 2 cards at once
        guard selectedCards.count < 2 else { return }
        
        // Flip the card to show its front texture
        tappedCard.flipToMatch()
        // Add it to our selected cards list
        selectedCards.append(tappedCard)
        
        // If we have 2 selected cards, check for a match
        if selectedCards.count == 2 {
            let firstCard = selectedCards[0]
            let secondCard = selectedCards[1]
            
            // Compare the match textures to see if they're a pair
            let isMatch = firstCard.matchTexture == secondCard.matchTexture
            
            if isMatch {
                // Match successful: disable interaction for both cards
                firstCard.isMatched = true
                secondCard.isMatched = true
                firstCard.isUserInteractionEnabled = false
                secondCard.isUserInteractionEnabled = false
                selectedCards.removeAll()
                print("Match found! Cards disabled.")
            } else {
                // Match failed: wait 1 second, then reset both cards
                run(SKAction.wait(forDuration: 1.0)) { [weak self] in
                    firstCard.resetToBack()
                    secondCard.resetToBack()
                    self?.selectedCards.removeAll()
                    print("No match! Cards reset.")
                }
            }
        }
    }
}
Key Feature Explanations
  1. Dual Touch Tracking: The selectedCards array keeps track of up to 2 unmatched cards. We ignore taps once 2 cards are selected until the match check completes.
  2. Disable Interaction on Match: When cards match, we set isMatched to true and turn off isUserInteractionEnabled, so the user can't tap those cards again.
  3. Reset Textures on No Match: We add a 1-second delay (using SKAction.wait) to let the user see both cards, then reset them back to their original texture and clear the selected list.
Bonus Optimization Tips
  • Add flip animations: Use SKAction.scaleX(to: 0, duration: 0.2) before switching textures, then scale back to 1 for a smooth flip effect.
  • Add sound effects: Play a success sound when cards match, and a different sound when they don't.
  • Handle edge cases: Make sure the user can't tap the same card twice (add a check in touchesBegan to see if tappedCard is already in selectedCards).

内容的提问来源于stack exchange,提问作者Developer0113

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 19:37:37