我有一个(移动)精灵节点。
我想检测此节点特定范围内的其他(移动)精灵节点。一旦检测到一个,它应该执行一个动作。
演奏动作部分对我来说没有问题,但我似乎无法弄清楚范围内的检测。有任何想法如何去做?
答案 0 :(得分: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
(渲染场景之前的最终回调,在所有动作,物理模拟和约束应用于帧)。
答案 1 :(得分:0)
我能想到的最简单的方法就是为您要点击的范围添加一个SKNode
子SKPhysicsBody
,并使用这个新节点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
}
}