【问题标题】:Detect other Spritenode within range of Spritenode?检测到 Spritenode 范围内的其他 Spritenode?
【发布时间】:2016-03-17 01:08:39
【问题描述】:

我有一个(移动的)精灵节点。

我想在这个节点的一定范围内检测其他(移动的)精灵节点。一旦检测到一个,它应该执行一个动作。

玩动作部分对我来说没问题,但我似乎无法弄清楚范围内的检测。有什么想法如何去做吗?

【问题讨论】:

    标签: swift sprite-kit


    【解决方案1】:

    一个简单但有效的方法是在场景的didEvaluateActions 方法中比较位置。 didEvaluateActions 每帧调用一次(在评估动作之后但在运行物理模拟计算之前)。您触发的任何新操作都将在下一帧开始评估。

    由于计算真实距离需要平方根运算(这可能代价高昂),我们可以编写自己的squaredDistance 并跳过该步骤。只要我们的检测范围/半径也是平方的,我们的比较就会按预期进行。此示例显示“真实范围”为 25 的检测。

    // calculated the squared distance to avoid costly sqrt operation
    func squaredDistance(p1: CGPoint, p2: CGPoint) -> CGFloat {
        return pow(p2.x - p1.x, 2) + pow(p2.x - p1.x, 2)
    }
    
    // override the didEvaluateActions function of your scene
    public override func didEvaluateActions() {
        // assumes main node is called nodeToTest and
        // all the nodes to check are in the array nodesToDetect
        let squaredRadius: CGFloat = 25 * 25
        for node in nodesToDetect {
            if squareDistance(nodeToTest.position, p2: node.position) < squaredRadius {
                // trigger action
            }
        }
    }
    

    如果该操作应该只触发一次,则您需要在第一次检测后跳出循环并添加某种检查,以便在没有适当冷却时间的情况下在下一次更新时不会再次触发它。您可能还需要将位置转换为正确的坐标系。

    另外,看看documentation for SKScene。根据您的设置,didEvaluateActions 可能不是您的最佳选择。例如,如果您的游戏还依赖物理来移动节点,最好将此逻辑移动到didFinishUpdate(场景渲染前的最终回调,在所有动作、物理模拟和约束应用于帧后调用) .

    【讨论】:

    • 难道 didFinishUpdate 也不是一个更好的地方吗?
    • 这将导致性能下降,因为您在多个节点上调用距离公式,距离公式使用平方根,这可能会很慢
    • 更新为使用平方距离(避免平方根调用)。 didFinishUpdate 可能是某些游戏的最佳位置,但我将其更改为 didEvaluateActions,因为听起来它们只是使用动作来移动节点。添加了对各种逻辑回调的解释,并提到 didFinishUpdate 可能是他们游戏的答案。
    【解决方案2】:

    在不影响性能的情况下,我能想到的最简单的方法是添加一个带有SKPhysicsBody 的子SKNode 用于您要命中的范围,并使用这个新节点contactBitMask 来确定它们是否在该范围内。

    类似这样的东西(伪代码):

    //Somewhere inside of setup of node
    let node = SKNode()
    node.physicsBody = SKPhysicsBody(circleOfRadius: 100)
    node.categoryBitMask = DistanceCategory
    node.contactBitMask = EnemyCategory
    sprite.addNode(node)
    
    
    
    //GameScene
    func didBeginContact(...)
    {
      if body1 contactacted body2
      {
         do something with body1.node.parent
         //we want parent because the contact is going to test the bigger node
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多