序章
ゲームでは、特にマルチプレイヤー オンライン ゲーム (Overwatch、Rainbow Six、Apex Heroes など) で、プレイヤーがターゲット位置をすばやく見つけるのを容易にする、オフスクリーン マーカー表示の機能を実装する必要があることがよくあります。
実装
現在 Unity を使用して実装していますが、実際には非常に複雑になる可能性があります. ここでは単純かつ直接的でなければなりません. コア機能は Unity の Unity - Scripting API: Camera.WorldToScreenPoint (unity3d.com ) https://docs.unity3d.com /ScriptReference/ Camera.WorldToScreenPoint.html
この API は、画面上の特定のオブジェクトの相対座標を直接出力できます。これは非常に優れています。
イメージを Unity Canvas に追加し、矢印をサブセットに入れるだけです。回転軸として親として空のオブジェクトが必要になる場合があります。次に、次のスクリプトを Canvas コンポーネントに追加し、Unity で各変数を指定します。部分的な解析はコード コメント内にあり、最適なソリューションであるとは限りませんが、機能します。
using UnityEngine;
/*
* 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 TargetToScreen : MonoBehaviour
{
[Header("Assign below variables in the inspector:")]
[SerializeField] Transform TargetTransform;
[SerializeField] Vector3 TargetPositionOffset = new Vector3(0, 1, 0);
[SerializeField] float screenBoundOffset = 0.1f;
[SerializeField] RectTransform TargetImage, TargetImageArrow;
[SerializeField] TMPro.TextMeshProUGUI TargetText;
[Header("Below is for Debug use:")]
[SerializeField] Vector3 screenPosition, screenBound;
[SerializeField] Vector2 Arrowdirection;
private void LateUpdate()
{
TargetToScreenPosition();
}
/// <summary>
/// This function is to convert the world position of the target to the screen position, and then update the position of the target image and the arrow image.
/// </summary>
public void TargetToScreenPosition()
{
screenPosition = Camera.main.WorldToScreenPoint(TargetTransform.position + TargetPositionOffset);// simple way to get the screen position of the target
(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;
if (screenPosition.y > screenBound.y / 2)//this is to avoid small probablity that the target is behind the camera and the screen position is flipped, but the y position is still in the screen
{
screenPosition.y = screenBound.y;
}
else screenPosition.y = 0;
}
//clamp the screen position to the screen bound
TargetImage.transform.position = new Vector2(
Mathf.Clamp(screenPosition.x, screenBound.y * screenBoundOffset, screenBound.x - screenBound.y * screenBoundOffset),
Mathf.Clamp(screenPosition.y, screenBound.y * screenBoundOffset, screenBound.y - 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.1)
{
//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;
}
//optional, update the distance text
TargetText.text = Vector3.Distance(TargetTransform.position, Camera.main.transform.position).ToString("F1") + "m";
}
}