【问题标题】:Select multiple nodes while dragging拖动时选择多个节点
【发布时间】:2023-03-26 12:02:01
【问题描述】:

我正在尝试制作一款游戏,让玩家在特定时间在屏幕上绘制图案。我的解决方案是在屏幕上添加多个节点,这些节点可以通过 SKSpriteNode 的扩展来触摸。 当玩家触摸一个节点时,我想调用 touchesmoved,并将所有触摸到的节点添加到一个数组中。 然后,当玩家停止触摸屏幕时,我想将该数组匹配到另一个数组,然后发生了一些事情。

我一直在玩更新函数,并尝试在每个更新循环中运行一个函数,但效果不佳。我还尝试让 gameScene 类成为我的 touchableShapeNode 类的代表,但我很难让它发挥作用。

class TouchableShapeNode: SKShapeNode {
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if (name != nil) {
            print("\(name ?? "node") touched")

        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if (name != nil) { 
            print("\(name ?? "node") touched")

        }
    }
  }

我的问题是,现在唯一被选中的节点是我触摸的第一个节点,而不是玩家手指移动过的节点。现在我只是打印触摸节点的名称。

【问题讨论】:

  • 嗨,Dan - 我不确定从该代码中如何检测到第一个节点被触摸,因为您的touchesBegan 中没有任何内容可以在触摸时建立节点。但是,为什么不使用 touchesMoved` 来简单地检查每个触摸位置的节点并将其添加到数组中呢?这是在touchesBegan 中将节点标记为“已触摸”的一些代码 - 我认为您需要做的就是将类似的代码添加到touchesMoved stackoverflow.com/a/56490384/1430420
  • 你不能这样做。您需要在场景级别进行操作。没有 touchBegin 就不会发生 touchMoved 事件,而获得 touchBegin 的唯一方法是将所有节点堆叠在一起并确保它们都不吸收触摸
  • @SteveIves 感谢您的回复!我不确定我是否遵循:) 按照您的链接,我的问题是,当我调用 touchesMoved 时,当我将手指移到除第一个节点之外的任何节点上时,什么都没有发生。这是我尝试过的:覆盖 func touchesMoved(_ touches: Set, with event: UIEvent?) { if nodeIsTouched { for touch in touches { print("(nodes(at: touch.location(in: self)) )") } } } 但我仍然只将我触摸的第一个节点打印到控制台
  • @DanielUllenius 我添加了一个答案,其中包含一个可能有帮助的小程序。试试看,如果我误解了您的问题,请告诉我,我会尽力解决。

标签: swift sprite-kit 2d-games


【解决方案1】:

我不太确定你在追求什么,但这里有一个小程序,它执行以下操作:

  1. 在屏幕上放置 15 个红色方块
  2. 当您在屏幕上拖动时,您触摸的任何节点都会添加到一个集合中。
  3. 当您停止触摸时,所有被触摸的节点的颜色都会变为绿色。
  4. 当您开始新的触摸时,被触摸的节点集被清空,所有节点都恢复到它们的起始颜色(红色)。

要使用,只需启动一个新的、空的 SpriteKit 项目并用此代码替换 gameScene.swift。

import SpriteKit
import UIKit

class GameScene: SKScene {

    let shipSize = CGSize(width: 25, height: 25)
    let normalColour = UIColor.red
    let touchedColour = UIColor.green
    var touchedNodes = Set<SKSpriteNode>()

    override func didMove(to view: SKView) {

        let sceneWidth = self.scene?.size.width
        let sceneHeight = self.scene?.size.height

        // Add 15 colour sprites to the screen in random places.
        for _ in 1...15 {
            let ship = SKSpriteNode(color: normalColour, size: shipSize)
            ship.position.x = CGFloat.random(in: -sceneWidth!/2...sceneWidth!/2) * 0.7
            ship.position.y = CGFloat.random(in: -sceneHeight!/2...sceneHeight!/2) * 0.7
            ship.name = "ship"
            addChild(ship)
        }
    }

    // When the screen is toucheed, empty the 'touchedNodes' set and rest all nodes back to their normal colour.
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        resetTouchedNodes()
    }

    // As the touch moves, if we touch a node then add it to our 'touchedNodes' set.
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let location = touch!.location(in: self)

        // If there is a node at the touch location, add it to our 'touchedSprites' set.
        if let touchedNode = selectNodeForTouch(location) {
            touchedNodes.insert(touchedNode)
        }
    }

    // When the touch ends, make all nodes that were touched change colour.
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        for node in touchedNodes {
            node.color = touchedColour
        }
    }

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

    // Return the first sprite where the user touched the screen, else nil
    func selectNodeForTouch(_ touchLocation: CGPoint) -> SKSpriteNode? {
        let nodes = self.nodes(at: touchLocation)
        for node in nodes {
            if node is SKSpriteNode {
                return (node as! SKSpriteNode)
            }
        }
        return nil
    }

    // Clear the touchedSprites set and return all nodes on screen to their normal colour
    func resetTouchedNodes() {
        touchedNodes.removeAll()
        enumerateChildNodes(withName: "//ship") { node, _ in
            let shipNode = node as! SKSpriteNode
            shipNode.color = self.normalColour
        }
    }

}

您可以通过各种方式对此进行修改。例如,您可以在touchesMoved 等中立即更改精灵的颜色。

【讨论】:

  • 哇,史蒂夫,非常感谢!这正是我一直在寻找的。我尝试通过拖动一个节点并将其重叠的某种类型的所有节点添加到一个工作正常的数组中来解决它,但这更加优雅。非常感谢,您是社区的真正拥护者!
  • @DanielUllenius 没问题 - 尝试为人们遇到的问题设计解决方案很有趣。如果适用,请不要忘记投票并标记为解决方案?!
  • 嗨!新问题:如果我想在拖动时突出显示每个节点,我该怎么做?我可以在 touchesmoved 期间以某种方式将它们添加到集合中吗?
  • @DanielUllenius 在touchesMoved 里面,以及将touchedNode 添加到touchedNodes 集合中,可以输入命令touchedNode.color = touchedcolour。在touchesMoved 期间,每个接触的节点添加到集合中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-17
  • 2014-02-10
  • 2010-10-12
相关资源
最近更新 更多