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

Unity2D视野脚本射线原点未更新问题求助

Unity2D视野射线原点不更新问题排查与修复

我参考YouTube上CodeMonkey的视野(FOV)脚本教程编写了Unity2D项目代码,但射线检测原点无法随玩家位置更新——射线方向正常,但位置始终停留在(0,0)。即使将FieldOfView脚本挂载到玩家控制器上,视野网格可随玩家移动,但射线原点问题仍存在。通过调试打印origin的值,显示它确实随玩家坐标变化,但射线碰撞计算依旧异常:玩家移动后,射线检测的碰撞结果未更新,仿佛碰撞物体仍在原地。

相关脚本

FieldOfView脚本

public class FieldOfView : MonoBehaviour
{
    [SerializeField] private LayerMask layerMask;

    private Mesh mesh;
    //create mesh
    private float fov;
    private Vector3 origin;
    private float startingAngle;
    private void Start()
    {
        mesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;
        fov = 90f;
        origin = Vector3.zero;
    }

    private void LateUpdate()
    {
        Vector3 origin = Vector3.zero;
        int rayCount = 100;
        float angle = startingAngle;
        float angleIncrease = fov / rayCount;
        float viewDistance = 10f;

        Vector3[] vertices = new Vector3[rayCount + 1 + 1];
        Vector2[] uv = new Vector2[vertices.Length];
        int[] triangles = new int[rayCount * 3];

        vertices[0] = origin;

        int vertexIndex = 1;
        int triangleIndex = 0;
        for (int i = 0; i <= rayCount; i++)
        {
            Vector3 vertex = origin + GetVectorFromAngle(angle) * viewDistance;
            RaycastHit2D raycastHit2D = Physics2D.Raycast(origin, GetVectorFromAngle(angle), viewDistance, layerMask);
            if (raycastHit2D.collider == null)
            {
                // did not hit
                vertex = origin + GetVectorFromAngle(angle) * viewDistance;
            }
            else
            {
                // object hit
                vertex = raycastHit2D.point;
            }
            vertices[vertexIndex] = vertex;

            if (i > 0)
            {
                triangles[triangleIndex + 0] = 0;
                triangles[triangleIndex + 1] = vertexIndex - 1;
                triangles[triangleIndex + 2] = vertexIndex;

                triangleIndex += 3;
            }

            vertexIndex++;
            angle -= angleIncrease;
        }

        mesh.vertices = vertices;
        mesh.uv = uv;
        mesh.triangles = triangles;
    }

    public void SetOrigin(Vector3 origin)
    {
        this.origin = origin;
    }

    public void SetAimDirection(Vector3 aimDirection)
    {
        startingAngle = GetAngleFromVectorFloat(aimDirection) + fov / 2f;
    }

    public static Vector3 GetVectorFromAngle(float angle)
    {
        float angleRad = angle * (Mathf.PI / 180f);
        return new Vector3(Mathf.Cos(angleRad), Mathf.Sin(angleRad));
    }

    public static float GetAngleFromVectorFloat(Vector3 dir)
    {
        dir = dir.normalized;
        float n = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        if (n < 0) n += 360;

        return n;
    }
}

PlayerAim脚本

public class PlayerAim : MonoBehaviour
{
    [SerializeField] private FieldOfView fieldOfView;

    void Update()
    {
        Vector3 targetPosition = GetMouseWorldPosition();
        Vector3 aimDir = (targetPosition - transform.position).normalized;
        fieldOfView.SetAimDirection(aimDir);
        fieldOfView.SetOrigin(transform.position);
    }

    public static Vector3 GetMouseWorldPosition()
    {
        Vector3 vec = GetMouseWorldPositionWithZ(Input.mousePosition, Camera.main);
        vec.z = 0f;
        return vec;
    }

    public static Vector3 GetMouseWorldPositionWithZ()
    {
        return GetMouseWorldPositionWithZ(Input.mousePosition, Camera.main);
    }

    public static Vector3 GetMouseWorldPositionWithZ(Camera worldCamera)
    {
        return GetMouseWorldPositionWithZ(Input.mousePosition, worldCamera);
    }

    public static Vector3 GetMouseWorldPositionWithZ(Vector3 screenPosition, Camera worldCamera)
    {
        Vector3 worldPosition = worldCamera.ScreenToWorldPoint(screenPosition);
        return worldPosition;
    }

    public static Vector3 GetDirToMouse(Vector3 fromPosition)
    {
        Vector3 mouseWorldPosition = GetMouseWorldPosition();
        return (mouseWorldPosition - fromPosition).normalized;
    }
}

问题原因与修复方案

问题核心

FieldOfView的LateUpdate方法中,你重新定义了一个局部变量Vector3 origin = Vector3.zero;,这会覆盖类的成员变量origin。尽管SetOrigin方法正确更新了类的成员变量,但LateUpdate里的射线检测、顶点计算全用的是这个固定为(0,0)的局部变量,导致射线始终从原点发射,碰撞结果自然不会随玩家位置更新。

修复步骤

删除LateUpdate开头的Vector3 origin = Vector3.zero;这一行,直接使用类的成员变量origin即可。

修改后的LateUpdate方法:

private void LateUpdate()
{
    int rayCount = 100;
    float angle = startingAngle;
    float angleIncrease = fov / rayCount;
    float viewDistance = 10f;

    Vector3[] vertices = new Vector3[rayCount + 1 + 1];
    Vector2[] uv = new Vector2[vertices.Length];
    int[] triangles = new int[rayCount * 3];

    vertices[0] = origin;

    int vertexIndex = 1;
    int triangleIndex = 0;
    for (int i = 0; i <= rayCount; i++)
    {
        Vector3 vertex = origin + GetVectorFromAngle(angle) * viewDistance;
        RaycastHit2D raycastHit2D = Physics2D.Raycast(origin, GetVectorFromAngle(angle), viewDistance, layerMask);
        if (raycastHit2D.collider == null)
        {
            vertex = origin + GetVectorFromAngle(angle) * viewDistance;
        }
        else
        {
            vertex = raycastHit2D.point;
        }
        vertices[vertexIndex] = vertex;

        if (i > 0)
        {
            triangles[triangleIndex + 0] = 0;
            triangles[triangleIndex + 1] = vertexIndex - 1;
            triangles[triangleIndex + 2] = vertexIndex;

            triangleIndex += 3;
        }

        vertexIndex++;
        angle -= angleIncrease;
    }

    mesh.vertices = vertices;
    mesh.uv = uv;
    mesh.triangles = triangles;
}

额外说明

调试时打印的origin是类的成员变量,所以显示的是正确的玩家位置,但实际计算用了局部变量,这就是出现“打印值正确但逻辑异常”矛盾现象的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:14:55