获取鼠标在世界中的位置

本文介绍了在UE4中获取鼠标位置的三种方法:GetHitResultUnderCursorByChannel、GetHitResultUnderCursor和LineTraceSingleByChannel。虽然具体实现不详,但提到了这些方法可能涉及的追踪类型、碰撞反应和坐标转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-获取鼠标位置有很多方法,这里说三种,但只是提供方法,具体并不是很清楚

一、GetHitResultUnderCursorByChannel

FHitResult TraceHitResult;//检测结果
GetHitResultUnderCursorByChannel(TraceTypeQuery1, true, TraceHitResult);    
FVector pos = TraceHitResult.Location;//位置
看一下源码
bool APlayerController::GetHitResultUnderCursorByChannel(ETraceTypeQuery TraceChannel, bool bTraceComplex, FHitResult& HitResult) const
{
    ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);
    bool bHit = false;
    if (LocalPlayer && LocalPlayer->ViewportClient)
    {
        FVector2D MousePosition;
        if (LocalPlayer->ViewportClient->GetMousePosition(MousePosition))
        {
            bHit = GetHitResultAtScreenPosition(MousePosition, TraceChannel, bTraceComplex, HitResult);
        }
    }

    if(!bHit)   //If there was no hit we reset the results. This is redundant but helps Blueprint users
    {
        HitResult = FHitResult();
    }

    return bHit;
}

我推测是根据追踪类型进行定位,不是很清楚

二、GetHitResultUnderCursor

FHitResult bTraceHitResult;
GetHitResultUnderCursor(ECC_Visibility, true, bTraceHitResult);
FVector pos = bTraceHitResult.Location;//位置
看一下源码
bool APlayerController::GetHitResultUnderCursor(ECollisionChannel TraceChannel, bool bTraceComplex, FHitResult& HitResult) const
{
    ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);
    bool bHit = false;
    if (LocalPlayer && LocalPlayer->ViewportClient)
    {
        FVector2D MousePosition;
        if (LocalPlayer->ViewportClient->GetMousePosition(MousePosition))
        {
            bHit = GetHitResultAtScreenPosition(MousePosition, TraceChannel, bTraceComplex, HitResult);
        }
    }

    if(!bHit)   //If there was no hit we reset the results. This is redundant but helps Blueprint users
    {
        HitResult = FHitResult();
    }

    return bHit;
}

和第一种很像,只有一个参数是变化的,推测是根据碰撞类型进行定位,因为在碰撞设置的时候也会设置对于Trace的反应。

三、LineTraceSingleByChannel,之前说过LineTraceSingleForObjects,这里是ByChannel

        FHitResult HitResult,Start, Dir, End, ;
        DeprojectMousePositionToWorld(Start, Dir);//获取初始位置和方向
        End = Start + (Dir*8000.0f);//设置追踪终点
        GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility);
        FVector pos = HitResult.Location;//位置
只看一下DeprojectMousePositionToWorld的源码吧
bool APlayerController::DeprojectMousePositionToWorld(FVector& WorldLocation, FVector& WorldDirection) const
{
    ULocalPlayer* const LocalPlayer = GetLocalPlayer();
    if (LocalPlayer && LocalPlayer->ViewportClient)
    {
        FVector2D ScreenPosition;
        if (LocalPlayer->ViewportClient->GetMousePosition(ScreenPosition))
        {
            return UGameplayStatics::DeprojectScreenToWorld(this, ScreenPosition, WorldLocation, WorldDirection);
        }
    }

    return false;
}


//被调用的方法
bool UGameplayStatics::DeprojectScreenToWorld(APlayerController const* Player, const FVector2D& ScreenPosition, FVector& WorldPosition, FVector& WorldDirection)
{
    ULocalPlayer* const LP = Player ? Player->GetLocalPlayer() : nullptr;
    if (LP && LP->ViewportClient)
    {
        // get the projection data
        FSceneViewProjectionData ProjectionData;
        if (LP->GetProjectionData(LP->ViewportClient->Viewport, eSSP_FULL, /*out*/ ProjectionData))
        {
            FMatrix const InvViewProjMatrix = ProjectionData.ComputeViewProjectionMatrix().InverseFast();
            FSceneView::DeprojectScreenToWorld(ScreenPosition, ProjectionData.GetConstrainedViewRect(), InvViewProjMatrix, /*out*/ WorldPosition, /*out*/ WorldDirection);
            return true;
        }
    }

    // something went wrong, zero things and return false
    WorldPosition = FVector::ZeroVector;
    WorldDirection = FVector::ZeroVector;
    return false;
}
<think>我们正在处理一个关于Unity中获取鼠标在游戏场景中的坐标的问题。根据用户的问题,我们需要提供在Unity中获取鼠标在游戏视图(即游戏场景)中的世界坐标的方法。 根据引用内容,我们可以总结出几种方法: 1. 使用传统的Input类(如引用[1]和引用[4]中提到的): - 通过`Input.mousePosition`获取鼠标在屏幕上的坐标(屏幕坐标,以像素为单位,左下角为原点(0,0),右上角为(Screen.width, Screen.height))。 - 然后,使用`Camera.ScreenToWorldPoint`将屏幕坐标转换为世界坐标。 2. 使用新的Input System(引用[2]): - 通过`UnityEngine.InputSystem.Mouse.current.position.ReadValue()`获取鼠标的屏幕坐标。 - 同样需要转换为世界坐标。 3. 另外,引用[4]中展示了一个示例,其中使用了`Mouse3D.GetMouseWorldPosition()`方法,但这是一个自定义方法,我们需要理解其内部实现。 由于用户要求获取的是游戏场景中的坐标(即世界坐标),我们重点介绍将屏幕坐标转换为世界坐标的方法。 注意:在3D游戏中,我们通常需要将2D的屏幕坐标转换为3D的世界坐标。这里有一个关键点:世界坐标是三维的,而屏幕坐标是二维的,所以我们需要指定一个深度(例如,相机的近裁剪面,或者一个平面)来确定世界坐标的位置。 常用的转换方法有两种: a) 使用`Camera.ScreenToWorldPoint`,并指定一个深度值(即z值,在相机视角下,z表示到相机的距离)。 b) 使用射线(Raycast)从相机发射一条穿过屏幕点的射线,与场景中的物体或平面相交,从而得到世界坐标。 方法b更常用,因为它可以获取鼠标在场景中某个平面(如地面)上的点。 下面我们分别介绍这两种方法: 方法一:使用Camera.ScreenToWorldPoint(适用于已知深度的情况) ```csharp Vector3 mousePositionScreen = Input.mousePosition; // 屏幕坐标 mousePositionScreen.z = 10; // 假设我们想要距离相机10个单位远的平面上的点 Vector3 mousePositionWorld = Camera.main.ScreenToWorldPoint(mousePositionScreen); ``` 方法二:使用射线(更通用,可以获取与碰撞体相交的点) ```csharp Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { Vector3 mousePositionWorld = hit.point; } ``` 注意:方法二需要场景中有碰撞体(Collider)才能检测到交点。如果只是想在某个平面上获取点,可以创建一个平面(比如地面)并添加碰撞体。 另外,引用[4]中的自定义方法`Mouse3D.GetMouseWorldPosition()`可能就是使用射线方法实现的。 根据引用[2]中新的Input System,获取屏幕坐标的方式有所不同,但转换方法相同。例如: ```csharp // 使用新的Input System Vector2 mouseScreenPosition = Mouse.current.position.ReadValue(); // 然后转换为射线 Ray ray = Camera.main.ScreenPointToRay(mouseScreenPosition); // ... 后续相同 ``` 因此,我们可以给出两种不同的实现方式(传统Input和新的Input System)的示例。 由于用户没有指定使用哪种输入系统,我们将分别展示。 步骤: 1. 获取鼠标的屏幕坐标。 2. 将屏幕坐标转换为世界坐标(这里我们使用射线方法,因为它更通用)。 示例代码(传统Input): ```csharp using UnityEngine; public class MousePositionExample : MonoBehaviour { void Update() { // 如果点击鼠标左键 if (Input.GetMouseButtonDown(0)) { // 从主相机发射一条射线 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; // 如果射线与碰撞体相交 if (Physics.Raycast(ray, out hit)) { // 输出世界坐标 Debug.Log("鼠标点击的世界坐标: " + hit.point); } } } } ``` 示例代码(新的Input System): 首先,需要安装Input System包,并设置输入动作。 这里我们直接使用Mouse.current来获取鼠标位置,而不通过输入动作(如果不需要处理输入动作事件,可以直接在Update中查询): ```csharp using UnityEngine; using UnityEngine.InputSystem; public class MousePositionExampleNewInput : MonoBehaviour { void Update() { // 如果点击了鼠标左键(使用新的Input System判断鼠标左键点击) if (Mouse.current.leftButton.wasPressedThisFrame) { // 获取鼠标位置 Vector2 mousePosition = Mouse.current.position.ReadValue(); // 创建射线 Ray ray = Camera.main.ScreenPointToRay(mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { Debug.Log("鼠标点击的世界坐标: " + hit.point); } } } } ``` 注意:使用新的Input System时,需要确保Input System已经启用。另外,以上代码都假设主相机标签为"MainCamera"。 如果用户需要在不与物体碰撞的情况下获取鼠标在场景中的位置(比如在空白处),我们可以使用一个虚拟平面(例如地面平面)来获取点。这可以通过指定一个平面,然后使用射线与平面相交的方法。 例如,假设我们有一个地面在y=0的平面,我们可以这样: ```csharp Plane groundPlane = new Plane(Vector3.up, Vector3.zero); // 地面平面,法向量向上,过原点 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); float distance; if (groundPlane.Raycast(ray, out distance)) { Vector3 hitPoint = ray.GetPoint(distance); Debug.Log("鼠标在地面上的世界坐标: " + hitPoint); } ``` 这样即使没有碰撞体,也能获取鼠标在地面平面上的点。 总结: 获取鼠标在游戏场景中的世界坐标,通常需要将屏幕坐标转换为世界坐标。推荐使用射线方法,因为它可以更灵活地获取与场景中物体或平面的交点。 根据用户的需求,我们提供了两种输入系统的实现方法,并介绍了使用平面获取地面点的方法。 最后,注意:在2D游戏中,可以使用`Camera.ScreenToWorldPoint`直接转换,因为2D游戏通常使用正交相机,且z坐标可以设置为0。 在2D中: ```csharp Vector3 worldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition); worldPosition.z = 0; // 2D游戏通常z为0 ``` 但用户的问题是关于游戏场景(3D)的,所以我们主要关注3D的方法。 请根据实际项目需求选择合适的方法。</think>在Unity中获取鼠标在游戏场景中的世界坐标,核心是通过屏幕坐标到世界坐标的转换。以下是详细方法和代码实现: ### 一、核心方法 1. **获取屏幕坐标** 使用 `Input.mousePosition` 获取鼠标在**屏幕空间**的坐标(像素单位,左下角为原点)。 2. **转换到世界坐标** 通过 `Camera.ScreenPointToRay` 或 `Camera.ScreenToWorldPoint` 将屏幕坐标转换为**世界空间**坐标: - **射线检测法**(推荐):向场景发射射线,与碰撞体交互获取精确坐标 - **直接转换法**:需指定Z轴深度值 --- ### 二、完整代码实现(射线检测法) ```csharp using UnityEngine; public class MouseWorldPosition : MonoBehaviour { [SerializeField] private LayerMask groundLayer; // 地面层级(如Terrain) void Update() { if (Input.GetMouseButtonDown(0)) // 左键点击时 { // 1. 从主摄像机发射射线 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; // 2. 检测与地面的碰撞 if (Physics.Raycast(ray, out hit, Mathf.Infinity, groundLayer)) { Vector3 worldPosition = hit.point; Debug.Log("鼠标世界坐标: " + worldPosition); // 3. 可视化标记(可选) Debug.DrawLine(ray.origin, hit.point, Color.red, 2f); Debug.DrawSphere(hit.point, 0.2f, Color.green, 2f); } } } } ``` --- ### 三、关键配置步骤 1. **设置地面层级** - 在Inspector中为地面物体(如Terrain/Plane)设置Layer(例如新建"Ground"层) - 将脚本的 `groundLayer` 参数设置为该Layer 2. **确保地面有碰撞体** - Terrain:自带Terrain Collider - 其他地面:添加 `Mesh Collider` 或 `Box Collider` 3. **3D/2D场景适配** - 2D场景:使用 `Physics2D.Raycast` 并替换碰撞检测逻辑 ```csharp RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero); if (hit.collider != null) { Vector3 worldPos = hit.point; } ``` --- ### 四、其他方法对比 | 方法 | 代码示例 | 适用场景 | 缺点 | |------|----------|----------|------| | **射线检测** | `Physics.Raycast(ray, out hit)` | 需要精确地面坐标 | 依赖碰撞体 | | **直接转换** | `Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10f))` | UI元素/固定深度对象 | 需手动指定Z值 | | **平面投影** | `Plane.Raycast(ray, out distance)` | 无碰撞体的平面 | 需定义数学平面 | --- ### 五、常见问题解决 1. **坐标Z值为0** - 检查摄像机是否为**透视模式**(Perspective) - 确认射线碰撞到带碰撞体的物体 2. **坐标值异常** - 确保摄像机未使用 `Viewport Point` 相关方法 - 检查摄像机裁剪平面(Clipping Planes)范围是否覆盖目标区域 3. **移动端适配** ```csharp // 替换Input.mousePosition为触摸位置 if (Input.touchCount > 0) { Vector2 touchPos = Input.GetTouch(0).position; Ray ray = Camera.main.ScreenPointToRay(touchPos); } ``` > 提示:使用 `Debug.DrawLine` 和 `Debug.DrawSphere` 可实时可视化检测路径和命中点[^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值