using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using BITKit; using BITKit.Entities; using BITKit.Sensors; using BITKit.UX; using UnityEngine; using UnityEngine.UIElements; namespace BITFALL.UX { public class UxPanelSensorTarget : UXBase { private struct MyStruct { public int index; public float weight; public VisualElement visualElement; public Vector3 position; public float exitTime; } [Inject] private ISensorTarget _sensorTarget; [Inject] private IEntityMovement _movement; [SerializeField] private VisualTreeAsset indicatorAsset; [UXBindPath("sensor-container")] private VisualElement indicatorContainer; private readonly ConcurrentDictionary _indicators = new(); private readonly List removeIndex = new(); protected override void Start() { base.Start(); indicatorContainer.Clear(); } protected override void OnPlayerInitialized(Entity obj) { base.OnPlayerInitialized(obj); _sensorTarget.OnDetected += OnDetected; } private void Update() { foreach (var x in _indicators.Values) { Vector3 rhs = x.position - _movement.Position; Vector3 offset = x.visualElement.transform.rotation.eulerAngles; var forward = _movement.Forward; //Convert angle into screen space rhs.y = 0f; rhs.Normalize(); //Get the angle between two positions. float angle = Vector3.Angle(rhs, forward); //Calculate the perpendicular of both vectors //More information about this calculation: https://unity3d.com/es/learn/tutorials/modules/beginner/scripting/vector-maths-dot-cross-products?playlist=17117 Vector3 Perpendicular = Vector3.Cross(forward, rhs); //Calculate magnitude between two vectors float dot = -Vector3.Dot(Perpendicular, Vector3.up); //get the horizontal angle in direction of target / sender. angle = AngleCircumference(dot, angle); //Apply the horizontal rotation to the indicator. offset.z = -angle; x.visualElement.transform.rotation = Quaternion.Euler(offset); x.visualElement[0].style.unityBackgroundImageTintColor = Color.Lerp(Color.gray,Color.white, x.weight); if (Time.time > x.exitTime) { removeIndex.Add(x.index); x.visualElement.RemoveFromHierarchy(); } continue; float AngleCircumference(float dot, float angle) { float ac = angle; float circumference = 360f; ac = angle - 10; if (dot < 0) { ac = circumference - angle; } return ac; } } foreach (var x in removeIndex) { _indicators.TryRemove(x); } removeIndex.Clear(); } private void OnDetected(float weight, ISensor sensor, object root) { _indicators.AddOrUpdate(sensor.Id,Create,UpdateValue); return; MyStruct Create(int id) { var indicator =indicatorContainer.Create(()=>indicatorAsset.CloneTree()[0]); indicator[0].style.unityBackgroundImageTintColor = Color.white; var pos = (root) switch { MonoBehaviour monoBehaviour=>monoBehaviour.transform.position, Transform _t=>_t.position, _ => Vector3.zero }; return new MyStruct() { weight = weight, index = id, visualElement = indicator, position = pos, exitTime = Time.time + 1 }; } MyStruct UpdateValue(int arg1, MyStruct arg2) { arg2.position = (root) switch { MonoBehaviour monoBehaviour=>monoBehaviour.transform.position, Transform _t=>_t.position, _ => Vector3.zero }; arg2.weight = weight; arg2.exitTime = Time.time + 1; return arg2; } } } }