1. 总体层次设计
- 放在HUD下
- Compass脚本:
using System.Collections.Generic;
using Unity.FPS.Game;//用于使用Transform m_PlayerTransform;
using Unity.FPS.Gameplay;
using UnityEngine;
namespace Unity.FPS.UI
{
public class Compass : MonoBehaviour
{
public RectTransform CompasRect;
public float VisibilityAngle = 180f;
public float HeightDifferenceMultiplier = 2f;
public float MinScale = 0.5f;
public float DistanceMinScale = 50f;
public float CompasMarginRatio = 0.8f;
public GameObject MarkerDirectionPrefab;
Transform m_PlayerTransform;
Dictionary<Transform, CompassMarker> m_ElementsDictionnary = new Dictionary<Transform, CompassMarker>();
float m_WidthMultiplier;
float m_HeightOffset;
void Awake()
{
PlayerCharacterController playerCharacterController = FindObjectOfType<PlayerCharacterController>();
DebugUtility.HandleErrorIfNullFindObject<PlayerCharacterController, Compass>(playerCharacterController,
this);
m_PlayerTransform = playerCharacterController.transform;
m_WidthMultiplier = CompasRect.rect.width / VisibilityAngle;
m_HeightOffset = -CompasRect.rect.height / 2;
}
void Update()
{
// this is all very WIP, and needs to be reworked
foreach (var element in m_ElementsDictionnary)
{
float distanceRatio = 1;
float heightDifference = 0;
float angle;
if (element.Value.IsDirection)
{
angle = Vector3.SignedAngle(m_PlayerTransform.forward,
element.Key.transform.localPosition.normalized, Vector3.up);
}
else
{
Vector3 targetDir = (element.Key.transform.position - m_PlayerTransform.position).normalized;
targetDir = Vector3.ProjectOnPlane(targetDir, Vector3.up);
Vector3 playerForward = Vector3.ProjectOnPlane(m_PlayerTransform.forward, Vector3.up);
angle = Vector3.SignedAngle(playerForward, targetDir, Vector3.up);
Vector3 directionVector = element.Key.transform.position - m_PlayerTransform.position;
heightDifference = (directionVector.y) * HeightDifferenceMultiplier;
heightDifference = Mathf.Clamp(heightDifference, -CompasRect.rect.height / 2 * CompasMarginRatio,
CompasRect.rect.height / 2 * CompasMarginRatio);
distanceRatio = directionVector.magnitude / DistanceMinScale;
distanceRatio = Mathf.Clamp01(distanceRatio);
}
if (angle > -VisibilityAngle / 2 && angle < VisibilityAngle / 2)
{
element.Value.CanvasGroup.alpha = 1;
element.Value.CanvasGroup.transform.localPosition = new Vector2(m_WidthMultiplier * angle,
heightDifference + m_HeightOffset);
element.Value.CanvasGroup.transform.localScale =
Vector3.one * Mathf.Lerp(1, MinScale, distanceRatio);
}
else
{
element.Value.CanvasGroup.alpha = 0;
}
}
}
public void RegisterCompassElement(Transform element, CompassMarker marker)
{
marker.transform.SetParent(CompasRect);
m_ElementsDictionnary.Add(element, marker);
}
public void UnregisterCompassElement(Transform element)
{
if (m_ElementsDictionnary.TryGetValue(element, out CompassMarker marker) && marker.CanvasGroup != null)
Destroy(marker.CanvasGroup.gameObject);
m_ElementsDictionnary.Remove(element);
}
}
}
- CompassBackGround组件
设置一个透明度为26的白色背景板,子物体挂载一个Image作为白线。(就是一个白色的图片被拉成一条细线) - Direction
放置一个Rect作为大方向指示,再放置八个方位,每个方位挂上Compass Element脚本。其中东南西北四个大方位要分别写上N、S、W、E。
方位 | 坐标 |
---|---|
N | (1,0,0) |
S | (-1,0,0) |
W | (0,0,1) |
E | (0,0,-1) |
NE | (1,0,-1) |
SE | (-1,0,-1) |
SW | (-1,0,1) |
NW | (1,0,1) |
敌人身上也要挂载CompassElement脚本
- CompassMarkeDirection
是个prefab,放置的TMPro文字是N,看看能不能直接导入使用。
using Unity.FPS.AI;
using UnityEngine;
using UnityEngine.UI;
namespace Unity.FPS.UI
{
public class CompassMarker : MonoBehaviour
{
[Tooltip("Main marker image")] public Image MainImage;
[Tooltip("Canvas group for the marker")]
public CanvasGroup CanvasGroup;
[Header("Enemy element")] [Tooltip("Default color for the marker")]
public Color DefaultColor;
[Tooltip("Alternative color for the marker")]
public Color AltColor;
[Header("Direction element")] [Tooltip("Use this marker as a magnetic direction")]
public bool IsDirection;
[Tooltip("Text content for the direction")]
public TMPro.TextMeshProUGUI TextContent;
EnemyController m_EnemyController;//这里用了unity.FPS.AI的命名空间
public void Initialize(CompassElement compassElement, string textDirection)
{
if (IsDirection && TextContent)
{
TextContent.text = textDirection;
}
else
{
m_EnemyController = compassElement.transform.GetComponent<EnemyController>();
if (m_EnemyController)
{
m_EnemyController.onDetectedTarget += DetectTarget;
m_EnemyController.onLostTarget += LostTarget;
LostTarget();
}
}
}
public void DetectTarget()
{
MainImage.color = AltColor;
}
public void LostTarget()
{
MainImage.color = DefaultColor;
}
}
}
- CompassEnemy:指示敌人位置,会生成一个小红点
子物体挂上image
using Unity.FPS.Game;
using UnityEngine;
namespace Unity.FPS.UI
{
public class CompassElement : MonoBehaviour
{
[Tooltip("The marker on the compass for this element")]
public CompassMarker CompassMarkerPrefab;
[Tooltip("Text override for the marker, if it's a direction")]
public string TextDirection;
Compass m_Compass;
void Awake()
{
m_Compass = FindObjectOfType<Compass>();
DebugUtility.HandleErrorIfNullFindObject<Compass, CompassElement>(m_Compass, this);
var markerInstance = Instantiate(CompassMarkerPrefab);
markerInstance.Initialize(this, TextDirection);
m_Compass.RegisterCompassElement(transform, markerInstance);
}
void OnDestroy()
{
m_Compass.UnregisterCompassElement(transform);
}
}
}
共用了两个预制体,CompassMarkerDirection,CompassMarkerEnemy。
一共三个脚本,Compass,CompassMaker,CompassElement。