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

如何在ARKit中获取屏幕点击位置以实现子弹发射功能?

实现点击屏幕发射子弹的正确方法

问题分析

你的代码核心问题是混淆了发射起点和目标方向的逻辑:你通过射线检测获取了平面上的点,但后续计算的pointPosition并不是正确的发射路径参数,且缺少实际创建子弹节点并赋予移动逻辑的步骤。

正确实现方案

1. 处理屏幕点击事件

在ARSCNView的触摸回调中捕获点击位置,触发发射逻辑:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else { return }
    let touchLocation = touch.location(in: sceneView)
    fireBullet(from: touchLocation)
}

2. 核心发射逻辑(朝屏幕射线方向发射)

从相机位置出发,将屏幕点击点转换为3D空间的射线方向,创建子弹并赋予移动动力:

func fireBullet(from touchLocation: CGPoint) {
    guard let pointOfView = sceneView.pointOfView else { return }
    
    // 获取相机位置
    let cameraPosition = pointOfView.position
    
    // 将屏幕点击点转换为3D射线方向
    let ray = sceneView.unprojectPoint(SCNVector3(touchLocation.x, touchLocation.y, 1))
    let direction = SCNVector3Normalize(SCNVector3(ray.x - cameraPosition.x, ray.y - cameraPosition.y, ray.z - cameraPosition.z))
    
    // 创建子弹节点(示例用小球,可替换为自定义模型)
    let bullet = SCNNode(geometry: SCNSphere(radius: 0.02))
    bullet.geometry?.firstMaterial?.diffuse.contents = UIColor.red
    bullet.position = cameraPosition // 从相机位置发射
    
    // 添加物理体实现移动
    bullet.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: bullet.geometry!, options: nil))
    bullet.physicsBody?.isAffectedByGravity = false // 不需要重力可关闭
    bullet.physicsBody?.applyForce(direction * 10, asImpulse: true) // 施加瞬时力
    
    sceneView.scene.rootNode.addChildNode(bullet)
    
    // 可选:5秒后移除子弹,避免内存堆积
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        bullet.removeFromParentNode()
    }
}

3. 可选:点击场景平面/物体发射

如果需求是点击场景中的平面或实体目标,朝该点发射,可保留射线检测逻辑,调整方向计算:

// 替换核心逻辑中的方向计算部分
let estimatedPlane: ARRaycastQuery.Target = .existingPlaneInfinite
let alignment: ARRaycastQuery.TargetAlignment = .any
guard let query = sceneView.raycastQuery(from: touchLocation, allowing: estimatedPlane, alignment: alignment),
      let result = sceneView.session.raycast(query).first else { return }

// 获取目标点位置
let targetPosition = SCNVector3(result.worldTransform.columns.3.x, 
                                result.worldTransform.columns.3.y, 
                                result.worldTransform.columns.3.z)
// 计算朝向目标的方向
let direction = SCNVector3Normalize(SCNVector3(targetPosition.x - cameraPosition.x, 
                                               targetPosition.y - cameraPosition.y, 
                                               targetPosition.z - cameraPosition.z))

注意事项

  • 确保你的ARSCNView已初始化物理世界:sceneView.scene.physicsWorld.gravity = SCNVector3(0, -9.8, 0)(需要重力时开启)
  • 子弹模型可替换为自定义的SCNGeometry或外部导入的模型

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:03:30