Unity 抬头显示 超出屏幕外跟踪标记
游戏中经常会需要实现屏幕外标记指示的功能,这样能方便玩家快速定位目标方位,尤其在多人网络游戏中出现(守望先锋,彩虹六号,Apex英雄等等),现在用Unity快速实现
·
简介
游戏中经常会需要实现屏幕外标记指示的功能,这样能方便玩家快速定位目标方位,尤其在多人网络游戏中出现(守望先锋,彩虹六号,Apex英雄等等):
|
|
![]() |
具体实现
现在使用Unity实现,其实要复杂可以很复杂,这里肯定用简单直接点的,核心功能是Unity的Unity - Scripting API: Camera.WorldToScreenPoint (unity3d.com)https://docs.unity3d.com/ScriptReference/Camera.WorldToScreenPoint.html
这个API可以直接将特定物体在屏幕上的相对坐标输出出来,真是非常Nice!
在Unity Canvas中加入一个Image便可,箭头的话放入子集,可能需要一个空物体做parent来当作旋转轴心,然后在Canvas组件中加入如下脚本,然后在Unity中指定每个变量。部分解析在代码注释中,不保证是最佳解决方法,但是确实能用。注意你可能需要移除ModifyScale方法,除非你使用DOTWEEN
using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
/*
* Copyright (c) [2023] [Lizhneghe.Chen https://github.com/Lizhenghe-Chen]
* https://blog.csdn.net/DUYIJIU/article/details/98366918
* https://indienova.com/indie-game-development/unity-off-screen-objective-marker/
*/
public class ScreenUIBase : MonoBehaviour
{
public Transform user;
[SerializeField] protected Vector3 screenPosition;
[SerializeField] protected Vector3 screenBound;
[SerializeField] protected Vector2 arrowDirection;
[SerializeField] protected RectTransform targetImageArrow;
private readonly Vector3 _headUIPositionOffset = new(0, 2, 0);
private UnityEngine.Camera _camera;
private float _screenBoundOffset;
public virtual void Start()
{
_camera = UnityEngine.Camera.main;
_screenBoundOffset = GetComponent<RectTransform>().sizeDelta.x / 1.5f;
MouseHoverEffect();
}
public virtual void Pop()
{
gameObject.SetActive(true);
}
public virtual void Hide()
{
Debug.Log("Hide");
gameObject.SetActive(false);
}
public virtual void LateUpdate()
{
if (!user) return;
UpdatePositionOnScreen();
// ModifyScale();
}
private void MouseHoverEffect()
{
//add mouse hover event to scale the UI
EventTrigger eventTrigger = gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry entry = new EventTrigger.Entry { eventID = EventTriggerType.PointerEnter };
entry.callback.AddListener((data) => { ModifyScale(true); });
eventTrigger.triggers.Add(entry);
entry = new EventTrigger.Entry { eventID = EventTriggerType.PointerExit };
entry.callback.AddListener((data) => { ModifyScale(false); });
eventTrigger.triggers.Add(entry);
}
private void UpdatePositionOnScreen()
{
screenPosition =
_camera.WorldToScreenPoint(user.position + _headUIPositionOffset);
(screenBound.x, screenBound.y) = (Screen.width, Screen.height); //get the screen size
if (screenPosition.z < 0) //if the target is behind the camera, flip the screen position
{
screenPosition = -screenPosition;
//this is to avoid small probability that the target is behind the camera and the screen position is flipped, but the y position is still in the screen
screenPosition.y = screenPosition.y > screenBound.y / 2 ? screenBound.y : 0;
}
//clamp the screen position to the screen bound
transform.position = new Vector2(
Mathf.Clamp(screenPosition.x, _screenBoundOffset, screenBound.x - _screenBoundOffset),
Mathf.Clamp(screenPosition.y, _screenBoundOffset, screenBound.y - _screenBoundOffset));
//optional, rotate the arrow to point to the target:
arrowDirection =
targetImageArrow.transform.position -
screenPosition; //get the direction of the arrow by subtracting the screen position of the target from the screen position of the arrow
// Debug.Log(Arrowdirection.magnitude);
if (Mathf.Abs(arrowDirection.x + arrowDirection.y) < 0.1f)
{
//disable the arrow when the target is too close to the center of the screen
targetImageArrow.gameObject.SetActive(false);
//TargetImageArrow.transform.up = Vector2.zero;
}
else
{
targetImageArrow.gameObject.SetActive(true);
targetImageArrow.transform.up = arrowDirection;
}
}
private void ModifyScale(bool larger)
{
// //use DOTWEEN to animate the icon
//Do Scale to 1.5f or 1 and keep
transform.DOScale(larger ? Vector3.one * 3f : Vector3.one, 0.2f);
}
}

更多推荐
所有评论(0)