Uno*_*ome 1 artificial-intelligence ios swift
首先作为免责声明,我完全知道 SpriteKit 物理体能够收集碰撞。这不是我想做的。我正在尝试构建一个势场人工智能,并进行吸引力和排斥向量的部分计算,需要两个物体之间的距离。
我认为找到距离只需使用距离公式,但由于某种原因,我得到的距离结果非常不稳定,所以我想咨询是否有人能发现我做错了什么。
下面我使用一个简单的距离公式,其中点位置与其中心对齐。
func getDistanceBetweenTwoObjects(sourceNode:SKSpriteNode, destinationNode:SKSpriteNode) -> CGFloat{
var centerSourceNode = CGPoint(x: sourceNode.position.x, y: sourceNode.position.y)
centerSourceNode.x += sourceNode.size.width/2
centerSourceNode.y += sourceNode.size.width/2
var centerDestNode = CGPoint(x: destinationNode.position.x, y: destinationNode.position.y)
centerDestNode.x += destinationNode.size.width/2
centerDestNode.y += destinationNode.size.width/2
var distance = sqrt(pow((centerSourceNode.x - centerDestNode.x), 2) + pow((centerSourceNode.y - centerDestNode.y), 2))
return distance
}
Run Code Online (Sandbox Code Playgroud)
这是我用来创建吸引力向量的函数。
func getAttractionVector(node:SKSpriteNode, destinationNode:SKSpriteNode, spread:CGFloat, strength:CGFloat) -> (xSpeed: CGFloat, ySpeed: CGFloat){
var sourceNodeRadius = sqrt(pow(node.size.width/2,2))
var destNodeRadius = sqrt(pow(destinationNode.size.width/2,2))
var radius = sourceNodeRadius + destNodeRadius
var distance = getDistanceBetweenTwoObjects(node, destinationNode: destinationNode)
if distance < radius{
return (0,0)
}
var angle = atan((destinationNode.position.y - node.position.y)/(destinationNode.position.x - node.position.x))
var xSpeed:CGFloat = 0
var ySpeed:CGFloat = 0
if radius <= distance && distance <= spread + radius{
xSpeed = strength * (distance - radius) * cos(angle)
ySpeed = strength * (distance - radius) * sin(angle)
}else if distance > spread + radius{
xSpeed = strength * spread * cos(angle)
ySpeed = strength * spread * sin(angle)
}
return (xSpeed, ySpeed)
}
Run Code Online (Sandbox Code Playgroud)
我使用类似的数学来计算排斥向量:
func getRepelVector(node:SKSpriteNode, destinationNode:SKSpriteNode, spread:CGFloat, strength:CGFloat) -> (xSpeed: CGFloat, ySpeed: CGFloat){
var sourceNodeRadius = sqrt(pow(node.size.width/2,2))
var destNodeRadius = sqrt(pow(destinationNode.size.width/2,2))
var radius = sourceNodeRadius + destNodeRadius
var distance = getDistanceBetweenTwoObjects(node, destinationNode: destinationNode)
if distance > spread + radius{
return (0,0)
}
var angle = atan((destinationNode.position.y - node.position.y)/(destinationNode.position.x - node.position.x))
var xSpeed:CGFloat = 0
var ySpeed:CGFloat = 0
println("\(distance) : \(radius)")
if radius <= distance && distance <= spread + radius{
xSpeed = strength * (spread + radius - distance) * cos(angle)
ySpeed = strength * (spread + radius - distance) * sin(angle)
}else if distance < radius{
xSpeed = getSign(cos(angle)) * CGFloat.max
ySpeed = getSign(sin(angle)) * CGFloat.max
println("HERE")
}
return (xSpeed, ySpeed)
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,距离公式显然让我失望了,我多次捕捉到节点,要么接触但它没有拿起它,或者不接触,但认为它接触。谁能看出我在哪里做错了,或者建议一种更简单的方法来准确计算两个 SpriteNode 之间的距离?希望它是简单的东西。谢谢。
下图显示了我的 AINode 正在解决我的迷宫(橙色)、需要避开的障碍(蓝色)和我的目标(绿色)。
在此示例中,AINode 的宽度为 20。在此示例中,障碍物的宽度为 50。
当调试器暂停在 AINode 非法与障碍物相交的无效状态时,使用上面提供的公式得出的中心点之间的距离读数为“28.28”。实际距离是7。

更新
我在吸引和排斥向量中发现了一个重大错误,这加剧了问题。我的距离公式有点偏差,但由于我计算角度的错误,它被放大了。角度需要用atan2not来计算atan。原因是,如果atan2不使用该角度,则会在不正确的象限中返回角度,这会扭曲排斥矢量的方向并导致重大错误。
Larry 可能有所发现,因为您的使用centerSourceNode.x += sourceNode.size.width/2表明您的节点的锚点为 (0,0) 而不是默认的 (0.5, 0.5)。
使用默认值时,精灵的位置是其中心在父节点中的位置,这意味着除了两个节点的位置之外,您不需要考虑任何内容。
正如我在评论中提到的,这也使我们能够通过 CGPoint 的扩展来解决它:
extension CGPoint {
func distanceFromCGPoint(point:CGPoint)->CGFloat{
return sqrt(pow(self.x - point.x,2) + pow(self.y - point.y,2))
}
}
Run Code Online (Sandbox Code Playgroud)
然后,无论您在哪里需要这个,您都可以通过简单的调用来获取距离:
let distance = spriteA.position.distanceFromCGPoint(spriteB.position)
| 归档时间: |
|
| 查看次数: |
1087 次 |
| 最近记录: |