swift - 当当前的 SKSpriteNode 被触摸时,另一个 SKSpriteNode 会被移除

标签 swift xcode

我正在使用 Xcode 开发应用程序,目前遇到有关 SKSpriteNodes 的问题。当有多个 SKSpriteNode 且该节点被触摸时,被触摸的节点不会被移除,但另一个未被触摸的节点会被移除。我还注意到,当屏幕上有多个节点时,只有来自屏幕顶部的最新节点被删除,而其他节点仍在向下移动,尽管它们正在被触摸。有人可以帮助确定为什么会发生这种情况以及防止此类错误的方法吗?

作为引用,我已经包含了错误所在的类。

import SpriteKit
import GameplayKit
class GameScene: SKScene {

    private var gameCounter: Int = 0
    private var currentLevel: Int = 0

    private var debug: SKLabelNode?

    private var increasedTouchArea:SKSpriteNode?
    private var generatedNode:SKSpriteNode?

    private var moveAndRemove:SKAction?
    private var moveNode:SKAction?

    // Here we set initial values of counter and level. Debug label is created here as well.
    override func didMove(to view: SKView) {
        print(action(forKey: "counting") == nil)
        gameCounter = 0
        currentLevel = 1
        //backgroundColor = SKColor.gray
        debug = SKLabelNode(fontNamed: "ArialMT")
        debug?.fontColor = SKColor.red
        debug?.fontSize = 30.0
        debug?.position = CGPoint(x: frame.midX, y: frame.midY)
        debug?.text = "Counter : [ \(gameCounter) ], Level [ \(currentLevel) ]"
        if let aDebug = debug {
            addChild(aDebug)
        }
    }

    //Method to start a timer. SKAction is used here to track a time passed and to maintain current level
    func startTimer() {
        print("Timer Started...")
        weak var weakSelf: GameScene? = self
        //make a weak reference to scene to avoid retain cycle
        let block = SKAction.run({
            weakSelf?.gameCounter = (weakSelf?.gameCounter ?? 0) + 1
            //Maintaining level
            if (weakSelf?.gameCounter ?? 0) < 5 {
                //level 1
                weakSelf?.currentLevel = 1
            } else if (weakSelf?.gameCounter ?? 0) >= 5 && (weakSelf?.gameCounter ?? 0) < 10 {
                //level 2
                weakSelf?.currentLevel = 2
            } else {
                //level 3
                weakSelf?.currentLevel = 3
            }
            weakSelf?.debug?.text = "Counter : [ \(Int(weakSelf?.gameCounter ?? 0)) ], Level [ \(Int(weakSelf?.currentLevel ?? 0)) ]"
        })
        run(SKAction.repeatForever(SKAction.sequence([SKAction.wait(forDuration: 1), block])), withKey: "counting")
    }

    //Method for stopping timer and reseting everything to default state.
    func stopTimer() {
         print("Timer Stopped...")
        if action(forKey: "counting") != nil {
            removeAction(forKey: "counting")
        }
        gameCounter = Int(0.0)
        currentLevel = 1
        debug?.text = "Counter : [ \(gameCounter) ], Level [ \(currentLevel) ]"
    }

    //Get current speed based on time passed (based on counter variable)
    func getCurrentSpeed() -> CGFloat {
        if gameCounter < 30 {
            //level 1
            return 1.0
        } else if gameCounter >= 31 && gameCounter < 49 {
            //level 2
            return 2.0
        } else {
            //level 3
            return 3.0
        }
    }

    //Method which stop generating stones, called in touchesBegan
    func stopGeneratingStones() {
         print("STOPPED GENERATING STONES...")
        if action(forKey: "spawning") != nil {
            removeAction(forKey: "spawning")
        }
    }

    func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> CGFloat {
        let diff: CGFloat = bigNumber - smallNumber
        return CGFloat(arc4random() % (UInt32(RAND_MAX) + 1)) / CGFloat(RAND_MAX) * diff + smallNumber
    }

    //Method for generating stones, you run this method when you want to start spawning nodes (eg. didMoveToView or when some button is clicked)
    func generateStones() {
         print("Generating Stones...")
        let delay = SKAction.wait(forDuration: 1, withRange: 0.5) //Change forDuration: delay decreases as game progresses.
        //randomizing delay time
        weak var weakSelf: GameScene? = self
        //make a weak reference to scene to avoid retain cycle
        let block = SKAction.run({
            let stone: SKSpriteNode? = weakSelf?.spawnNodes(withSpeed: weakSelf?.getCurrentSpeed() ?? 0.0)
            stone?.zPosition = 20
            if let aStone = stone {
                weakSelf?.addChild(aStone)
            }
        })
        run(SKAction.repeatForever(SKAction.sequence([delay, block])), withKey: "spawning")
    }

    func spawnNodes(withSpeed stoneSpeed: CGFloat) -> SKSpriteNode? {
        let nodeSize = CGSize(width: 60, height: 60) //size of shape.
        let initalNodePosition = CGPoint(x: randomFloatBetween(0.0, and: (self.view?.bounds.size.width)!) - 110, y: frame.maxY)
        generatedNode = SKSpriteNode(color: SKColor.green, size: nodeSize)
        generatedNode?.position = initalNodePosition 
        moveNode = SKAction.moveBy(x: 0, y: self.view!.scene!.frame.minY + self.view!.scene!.frame.minY , duration: 5.25)
        generatedNode?.isUserInteractionEnabled = false //Allows users to touch shape.
        increasedTouchArea = SKSpriteNode(color: UIColor.clear, size: CGSize(width: nodeSize.width * 1.35, height: nodeSize.height * 1.35))
        increasedTouchArea?.name = "generatedNode"
        increasedTouchArea?.isUserInteractionEnabled = false
        generatedNode?.addChild(increasedTouchArea!)
        moveNode?.speed = stoneSpeed
        moveAndRemove = SKAction.sequence([moveNode!, SKAction.removeFromParent()])
        generatedNode?.run(moveAndRemove!, withKey: "moving")
        generatedNode?.name = "generatedNode"
        return generatedNode
    }

    func deleteNode(){
        moveAndRemove = SKAction.sequence([SKAction.removeFromParent()])
        generatedNode?.run(moveAndRemove!, withKey: "moving")
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent? {
        for touch in touches {
            let locationTocuhed = touch.location(in: self)
            let touchedNode : SKNode = self.atPoint(locationTocuhed)
            if touchedNode.name == generatedNode?.name {
                print("Node touched")
                deleteNode()
            }
        }
        if action(forKey: "counting") == nil {
            print("Game started...")
            startTimer()
            generateStones()
        } else {
            print("Game paused...")
        }
    }
}

最佳答案

您的方法deleteNode()在 generatedNode指向的节点上运行删除动画,而不是最后触摸的节点:

func deleteNode(){
    moveAndRemove = SKAction.sequence([SKAction.removeFromParent()])
    generatedNode?.run(moveAndRemove!, withKey: "moving")
}

如果要删除上次触摸的节点,请将此节点的引用传递给方法deleteNode,然后在其中运行删除动画,而不是在generateNode中。

关于swift - 当当前的 SKSpriteNode 被触摸时,另一个 SKSpriteNode 会被移除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52025348/

相关文章:

swift - Metal/Metal 2 + swift : How to pass complex Swift structure as shader argument?

iOS Swift 自动完成下拉菜单也有自己的关键字

ios - 在导航 Controller xcode 中添加 "Sub" View

ios - FileManager 无法在 Xcode 项目中找到 PDF 目录

image - 如何在分配之前确保下载的数据不同

ios - Swift 中的音频播放未恢复到原始音量

ios - ios推送通知续订

c++ - 由于更新到 Xcode 10 文件未找到错误/派生数据

swift - 将 ProductModuleName-Swift.h 导出到其他目标?

ios - xcode 4.2.1 构建失败不允许操作