BITFALL/Assets/Artists/Scripts/UX/UXSensorTarget.cs

142 lines
3.6 KiB
C#

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<int,MyStruct> _indicators = new();
private readonly List<int> 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<VisualElement>(()=>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;
}
}
}
}