0

我试图在屏幕外指向一个对象。对象是静态的。

public class SpawnIndicator : MonoBehaviour
{
public Camera UIcamera;
public GameObject point;
public Canvas canvas;

// Start is called before the first frame update
void Start()
{
    
}

// Update is called once per frame
void Update()
{
    if (point.GetComponent<Renderer>().isVisible)
    {
        gameObject.GetComponent<SpriteRenderer>().color = Color.clear;
    }

    else
    {
        gameObject.GetComponent<SpriteRenderer>().color = Color.white;

        //POSITION
        Vector3 pointPos = UIcamera.WorldToScreenPoint(point.transform.position);

        pointPos.z = 0;
        pointPos.x = Mathf.Clamp(pointPos.x, (Screen.width * 0.01f), (Screen.width * 0.99f));
        pointPos.y = Mathf.Clamp(pointPos.y, (Screen.height * 0.01f), (Screen.height * 0.99f));
        pointPos -= new Vector3((Screen.width/2), (Screen.height/2), 0);

        gameObject.transform.localPosition = pointPos;

        
        //ROTATION
        gameObject.GetComponent<SpriteRenderer>().color = Color.white;
        Vector3 vectorToTarget = point.transform.position - gameObject.transform.position;
        float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
        angle -= 90;
        Quaternion newRotation = Quaternion.AngleAxis(angle, Vector3.forward);
        gameObject.transform.rotation = newRotation; 
    }
    
}
}

当屏幕尺寸为 1920x1080(我的画布的参考尺寸)时,这可以正常工作。然而,在较小尺寸时,对象远离边缘,而在较大尺寸时,它们位于边缘之外。

帆布

4

1 回答 1

1

弄清楚了。

WorldToScreenPoint 返回一个基于参考分辨率 (1920x1080) 的值,因此不同的分辨率最终不匹配。我认为这就是问题所在,无论如何,我已经找到了解决方案。

我发现这种方法可以将世界位置转换为画布位置。

 public static Vector3 WorldToScreenSpace(Vector3 worldPos, Camera cam, RectTransform area)
{
    Vector3 screenPoint = cam.WorldToScreenPoint(worldPos);
    screenPoint.z = 0;

    Vector2 screenPos;
    if (RectTransformUtility.ScreenPointToLocalPointInRectangle(area, screenPoint, cam, out screenPos))
    {
        return screenPos;
    }

    return screenPoint;
}

在找到该解决方案之前尝试修复此问题时,我还稍微更改了其余代码(巧合的是使用画布大小)所以这里是完整的脚本:

public class SpawnIndicator : MonoBehaviour
{
public Camera UIcamera;
public GameObject point;
public Canvas canvas;

Vector3 pointPos;

// Start is called before the first frame update
void Start()
{
    
}

// Update is called once per frame
void Update()
{
    if (point.GetComponent<Renderer>().isVisible)
    {
        gameObject.GetComponent<SpriteRenderer>().color = Color.clear;
    }
    else
    {


        gameObject.GetComponent<SpriteRenderer>().color = Color.white;

        Vector3[] canvasPoints = new Vector3[4];
        canvas.GetComponent<RectTransform>().GetLocalCorners(canvasPoints);

        Vector3 pointPos = WorldToScreenSpace(point.transform.position, UIcamera, canvas.GetComponent<RectTransform>());

        float xMin = canvasPoints[0].x * 0.98f;
        float xMax = canvasPoints[2].x * 0.98f;
        float yMin = canvasPoints[0].y * 0.8f;
        float yMax = canvasPoints[2].y * 0.98f;

        //POSITION
        if (pointPos.x <= xMin) pointPos.x = xMin;
        if (pointPos.x >= xMax) pointPos.x = xMax;
        if (pointPos.y <= yMin) pointPos.y = yMin;
        if (pointPos.y >= yMax) pointPos.y = yMax;

        pointPos.z = 0f;
        gameObject.transform.localPosition = pointPos;

        //ROTATION
        gameObject.GetComponent<SpriteRenderer>().color = Color.white;
        Vector3 vectorToTarget = point.transform.position - gameObject.transform.position;
        float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
        angle -= 90;
        Quaternion newRotation = Quaternion.AngleAxis(angle, Vector3.forward);
        gameObject.transform.rotation = newRotation;

    }
}

public static Vector3 WorldToScreenSpace(Vector3 worldPos, Camera cam, RectTransform area)
{
    Vector3 screenPoint = cam.WorldToScreenPoint(worldPos);
    screenPoint.z = 0;

    Vector2 screenPos;
    if (RectTransformUtility.ScreenPointToLocalPointInRectangle(area, screenPoint, cam, out screenPos))
    {
        return screenPos;
    }

    return screenPoint;
}

}

于 2021-03-08T20:46:17.160 回答