You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GameplayKit:路径被特定障碍物阻挡时终止寻路

解决GameplayKit寻路中区分危险/友好障碍物的问题

你不需要使用GKRule或GKRuleSystem来实现这个需求,核心思路是仅将危险障碍物纳入寻路障碍图,让GameplayKit自动避开它们;友好障碍物因为允许主角接触,不需要加入障碍图(寻路时会忽略其存在)。当所有可行路径都被危险障碍物阻挡时,findPath会返回长度不足2的路径,此时即可判定寻路失败。

具体实现步骤

  1. 自定义障碍物类型标识
    通过扩展GKPolygonObstacle添加关联属性,标记每个障碍物是友好还是危险:
enum ObstacleType {
    case friendly
    case dangerous
}

extension GKPolygonObstacle {
    private static let typeKey = UnsafeRawPointer(bitPattern: "ObstacleType".hashValue)!
    
    var obstacleType: ObstacleType {
        get {
            objc_getAssociatedObject(self, Self.typeKey) as? ObstacleType ?? .friendly
        }
        set {
            objc_setAssociatedObject(self, Self.typeKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}
  1. 分离存储两类障碍物
    创建两个数组分别存储友好和危险障碍物,根据实际场景逻辑设置每个障碍物的类型:
var friendlyObstacles = [GKPolygonObstacle]()
var dangerousObstacles = [GKPolygonObstacle]()

// 示例:创建危险障碍物(多边形模拟圆形)
let pegRadius: Float = 0.15
let numOfPoints = 12
let totalRadians: Float = 2 * .pi
let radiansPerPoint: Float = totalRadians / Float(numOfPoints)
var polyPoints = [SIMD2<Float>]()
let pegPosition = SIMD2(x: 0, y: 0) // 替换为实际位置

for i in 0..<numOfPoints {
    let angle = radiansPerPoint * Float(i)
    let x = pegPosition.x + (pegRadius * cos(angle))
    let y = pegPosition.y + (pegRadius * sin(angle))
    polyPoints.append(SIMD2(x: x, y: y))
}

let obstacle = GKPolygonObstacle(points: polyPoints)
obstacle.obstacleType = .dangerous // 标记为危险障碍物
dangerousObstacles.append(obstacle)

// 如果是友好障碍物,加入friendlyObstacles数组即可,无需加入障碍图
  1. 仅用危险障碍物构建寻路图
    GKObstacleGraph只传入危险障碍物,这样寻路时会自动避开危险区域:
let graph = GKObstacleGraph(obstacles: dangerousObstacles, bufferRadius: 0.05)
  1. 执行寻路并判断结果
    当findPath返回的路径长度小于2时,说明所有可行路径都被危险障碍物阻挡,进入失败分支:
// 获取起点和终点节点
guard let receptors = scnView.scene?.rootNode.childNodes(passingTest: { theNode, stop in
    return theNode.name == "receptors"
}) as? [SCNNodeIdentifiable], receptors.count >= 2 else {
    return
}

let receptorIndex: Int = 0
let startPosition = receptors[receptorIndex].presentation.worldPosition
let startNode = GKGraphNode2D(point: vector_float2(x: Float(startPosition.x), y: Float(startPosition.y)))

let endPosition = receptors[receptorIndex+1].presentation.worldPosition
let endNode = GKGraphNode2D(point: vector_float2(x: Float(endPosition.x), y: Float(endPosition.y)))

// 连接节点到寻路图
graph.connectUsingObstacles(node: startNode)
graph.connectUsingObstacles(node: endNode)

// 执行寻路
let path = graph.findPath(from: startNode, to: endNode)

if path.count >= 2 {
    // 找到可行路径(未被危险障碍物完全阻挡)
    // 处理路径逻辑
} else {
    // 寻路失败:所有路径被危险障碍物阻挡
    // 触发关卡失败逻辑
}

补充:关于GKCircleObstacle的使用

你之前无法使用GKCircleObstacle,可以尝试强制转换为GKPolygonObstacle(因为它是子类):

let circleObstacle = GKCircleObstacle(radius: pegRadius)
circleObstacle.position = vector_float2(x: pegPosition.x, y: pegPosition.y)
circleObstacle.obstacleType = .dangerous
dangerousObstacles.append(circleObstacle as! GKPolygonObstacle)

内容的提问来源于stack exchange,提问作者West1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:37:11