This repository has been archived on 2025-04-28. You can view files and clone it, but cannot push or open issues or pull requests.
ARPlusSystem/ARPlusSystem-250418/Assets/ARLocation/Mapbox Routes/Scripts/DefaultOnScreenTargetIndica...

204 lines
6.4 KiB
C#
Raw Permalink Normal View History

using UnityEngine;
using UnityEngine.UI;
namespace ARLocation.MapboxRoutes
{
public class DefaultOnScreenTargetIndicator : AbstractOnScreenTargetIndicator
{
public enum TargetVisibilityState
{
None,
Visible,
OffUp,
OffDown,
OffLeft,
OffRight
}
public enum ArrowDir
{
Left,
Right
}
public Sprite ArrowSprite;
public ArrowDir NeutralArrowDirection;
public float Margin = 20;
private RectTransform indicator;
private Canvas canvas;
private Camera cam;
private Transform camTransform;
private Renderer targetRenderer;
private TargetVisibilityState targetVisibility;
private bool initialized;
public TargetVisibilityState TargetVisibility => targetVisibility;
public override void Init(MapboxRoute route)
{
if (!initialized)
{
var canvasGo = new GameObject("[OnScreenTargetIndicatorCanvas]");
var canvas = canvasGo.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
var indicatorGo = new GameObject("[OnScreenTargetIndicatorImage]");
indicatorGo.transform.parent = canvasGo.transform;
var indicatorImage = indicatorGo.AddComponent<Image>();
indicatorImage.sprite = ArrowSprite;
indicator = indicatorGo.GetComponent<RectTransform>();
cam = Camera.main;
camTransform = cam.transform;
initialized = true;
}
}
bool isLeftOfCamera(Vector3 targetPos)
{
var camForward = camTransform.forward;
var camPos = camTransform.position;
return Vector3.Dot(Vector3.Cross(camForward, targetPos - camPos), (new Vector3(0, 1, 0))) < 0;
}
bool isBehindCamera(Vector3 targetPos)
{
var camForward = camTransform.forward;
var relative = targetPos - camTransform.position;
return Vector3.Dot(camForward, relative) < 0;
}
bool isVisible(Vector3 targetPos)
{
if (isBehindCamera(targetPos))
{
return false;
}
if (targetRenderer != null)
{
return GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(Camera.main), targetRenderer.bounds);
}
else
{
var p = cam.WorldToScreenPoint(targetPos);
return (p.x >= 0 && p.x <= Screen.width) && (p.y >= 0 && p.y <= Screen.height);
}
}
public override void OnRouteUpdate(SignPostEventArgs args)
{
bool isLeft = isLeftOfCamera(args.TargetPos);
bool isBehind = isBehindCamera(args.TargetPos);
bool isFront = !isBehind;
bool isRight = !isLeft;
if (isVisible(args.TargetPos))
{
this.indicator.gameObject.SetActive(false);
targetVisibility = TargetVisibilityState.Visible;
return;
}
else
{
this.indicator.gameObject.SetActive(true);
}
var p = cam.WorldToScreenPoint(args.TargetPos);
if (p.x < 0)
{
targetVisibility = TargetVisibilityState.OffLeft;
}
else if (p.x >= Screen.width)
{
targetVisibility = TargetVisibilityState.OffRight;
}
else if (p.y < 0)
{
targetVisibility = isBehind ? TargetVisibilityState.OffUp : TargetVisibilityState.OffDown;
}
else
{
targetVisibility = isBehind ? TargetVisibilityState.OffDown : TargetVisibilityState.OffUp;
}
p.x = Mathf.Clamp(p.x, Margin, Screen.width - Margin);
p.y = Mathf.Clamp(p.y, Margin, Screen.height - Margin);
if (isBehind)
{
p.y = Screen.height - p.y;
if (isLeft)
{
p.x = Margin;
targetVisibility = TargetVisibilityState.OffLeft;
}
else
{
p.x = Screen.width - Margin;
targetVisibility = TargetVisibilityState.OffRight;
}
}
indicator.position = p;
switch (targetVisibility)
{
case TargetVisibilityState.OffLeft:
if (NeutralArrowDirection == ArrowDir.Right)
{
indicator.rotation = Quaternion.AngleAxis(180, Vector3.forward);
}
else
{
indicator.rotation = Quaternion.identity;
}
break;
case TargetVisibilityState.OffRight:
if (NeutralArrowDirection == ArrowDir.Right)
{
indicator.rotation = Quaternion.identity;
}
else
{
indicator.rotation = Quaternion.AngleAxis(180, Vector3.forward);
}
break;
case TargetVisibilityState.OffUp:
if (NeutralArrowDirection == ArrowDir.Right)
{
indicator.rotation = Quaternion.AngleAxis(90, Vector3.forward);
}
else
{
indicator.rotation = Quaternion.AngleAxis(-90, Vector3.forward);
}
break;
case TargetVisibilityState.OffDown:
if (NeutralArrowDirection == ArrowDir.Right)
{
indicator.rotation = Quaternion.AngleAxis(-90, Vector3.forward);
}
else
{
indicator.rotation = Quaternion.AngleAxis(90, Vector3.forward);
}
break;
default:
indicator.rotation = Quaternion.identity;
break;
}
}
}
}