Reputation: 65
I'm trying to point to an object when it's off-screen. The objects are static.
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;
}
}
}
This works fine when the screen size is 1920x1080 (the reference size for my canvas). However at lower sizes, the objects sit awawy from the edges, and in larger sizes they sit outside of the edges.
Upvotes: 1
Views: 1271
Reputation: 65
Figured it out.
WorldToScreenPoint was returning a value based on the reference resolution (1920x1080) so different resolutions ended up mismatched. I think that's what was going wrong, regardless, I've got the solution.
I found this method to convert a world position to canvas position.
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;
}
I'd also changed the rest of the code a bit while trying to fix this before finding that solution (and coincidentally was using the canvas size) so here's the full script:
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;
}
}
Upvotes: 1