You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Godot引擎3D游戏中检测对象的点击/触摸输入?

解决Godot 3D对象鼠标点击检测与屏幕位置获取问题

嘿,我来帮你搞定这个问题!首先得先掰扯清楚:Control节点是给2D UI组件用的,比如按钮、文本框这些,和3D场景里的对象点击完全不搭边,别在这上面浪费精力啦😉

下面分两部分给你讲清楚怎么实现需求:

一、3D对象的鼠标点击检测

要检测3D对象的点击,核心是利用Godot的碰撞检测系统,常用的有两种方法,按需选就行:

方法1:全局射线检测(适合批量检测多个对象)

这种方法是从相机向鼠标点击的方向发射一条“射线”,看这条射线撞到了哪个3D对象。适合需要在全局统一处理所有点击事件的场景:

extends Node3D  # 可以挂在主场景根节点上

func _input(event: InputEvent) -> void:
    # 只处理鼠标左键按下的事件
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
        # 获取当前场景的相机(这里假设你相机节点叫"Camera3D",按需修改)
        var camera = get_node_or_null("Camera3D")
        if not camera:
            camera = get_tree().root.get_camera()
        
        # 计算射线的起点和终点:从相机位置出发,沿着鼠标方向延伸足够远
        var ray_origin = camera.project_ray_origin(event.position)
        var ray_direction = camera.project_ray_normal(event.position)
        var ray_end = ray_origin + ray_direction * 1000.0  # 1000是射线长度,根据你的游戏场景调整
        
        # 执行射线碰撞检测
        var space_state = get_world_3d().direct_space_state
        var hit_result = space_state.intersect_ray(RayCastParameters.create(ray_origin, ray_end))
        
        # 如果检测到碰撞对象
        if hit_result:
            var target_obj = hit_result["collider"]
            # 判断是不是你要的特定对象:可以通过节点名称、分组或者自定义脚本判断
            if target_obj.name == "Player" or target_obj.is_in_group("InteractiveObjects"):
                print(f"成功点击到目标:{target_obj.name}")
                # 这里可以触发你的逻辑,比如打开交互面板、播放动画等

方法2:节点自带的_input_event函数(适合单个对象单独处理)

如果你的3D对象需要自己处理点击事件,可以直接在对象的脚本里重写_input_event函数,前提是对象必须有碰撞体组件(比如CollisionShape3D):

extends MeshInstance3D  # 假设你的对象是MeshInstance3D,其他3D节点同理

func _ready():
    # 确保对象可以被点击检测(默认是开启的,这里可以手动确认)
    input_pickable = true

func _input_event(viewport: Viewport, event: InputEvent, shape_idx: int) -> void:
    # 检测左键点击
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
        print("我被点击啦!")
        # 这里直接写当前对象的点击逻辑就行

二、获取3D对象在屏幕上的位置

不管用哪种点击检测方法,要获取对象的屏幕位置都很简单,用相机的unproject_position方法,把对象的全局坐标转换成屏幕像素坐标:

# 假设已经拿到了目标对象target_obj和相机camera
var screen_position = camera.unproject_position(target_obj.global_position)
print(f"对象在屏幕上的位置:X={screen_position.x}, Y={screen_position.y}")

划重点:unproject_position返回的Vector2中,x是屏幕横向像素,y是纵向像素,Godot的屏幕原点是左上角哦。

必看注意事项

  • 所有要被点击的3D对象,必须添加碰撞体组件(CollisionShape3D/CollisionPolygon3D),并且碰撞形状要和模型匹配,否则射线检测不到。
  • 如果用_input_event,要确保节点的input_pickable属性是true(默认开启,要是没反应可以检查这个)。
  • 如果你的场景有多个相机,记得获取当前正在渲染的相机(用get_tree().root.get_camera()可以自动拿到当前激活的相机)。

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

火山引擎 最新活动