Files
project-reset/Assets/Scripts/Core/LockOnManager.cs
2025-07-03 14:31:59 -04:00

158 lines
6.0 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using Sirenix.OdinInspector;
using Unity.Cinemachine;
using UnityEngine;
using UnityEngine.UIElements;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
public class LockOnManager : MonoBehaviour{
[ShowInInspector]
public UIDocument lockOnDocument;
public GameObject lockOnTarget;
public CinemachineTargetGroup targetGroup;
public CinemachineOrbitalFollow cmOrbitalFollow;
public float lockOnRange;
[Space(5)]
public List<GameObject> lockOnTargets = new List<GameObject>();
private Label elementLabelName;
private VisualElement elementRoot;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
if (lockOnTarget && lockOnTarget.GetComponent<ILockOnTarget>() == null) {
Debug.LogError($"Game Object {lockOnTarget.name} does not implement the ILockOnTarget interface. Not processing lock-on actions!");
}
elementRoot = lockOnDocument.rootVisualElement.Query<VisualElement>("LockOnGroup");
elementLabelName = lockOnDocument.rootVisualElement.Query<Label>("LockOnName").First();
// Add all nearby game objects to lock-on eligible list
GameObject[] allGameObjects = GameObject.FindObjectsByType<GameObject>(0, 0);
foreach (GameObject thisObject in allGameObjects)
{
if (Vector3.Distance(transform.position, thisObject.transform.position) < lockOnRange) {
if (thisObject.GetComponent<ILockOnTarget>() != null) {
lockOnTargets.Add(thisObject);
}
}
}
}
void Update(){
if (targetGroup.Targets.Count > 1){
targetGroup.Targets[1].Weight = Mathf.Lerp(targetGroup.Targets[1].Weight, .15f, 5f * Time.deltaTime);
}
for (int i = 2; i < targetGroup.Targets.Count; i++) {
if (targetGroup.Targets[i].Weight < 0.001f) {
StartCoroutine(RemoveFromTargetAtFrameEnd(targetGroup.Targets[i]));
continue;
}
targetGroup.Targets[i].Weight = Mathf.Lerp(targetGroup.Targets[i].Weight, 0f, 8f * Time.deltaTime);
}
}
IEnumerator RemoveFromTargetAtFrameEnd(CinemachineTargetGroup.Target indexOf){
yield return new WaitForEndOfFrame();
targetGroup.Targets.Remove(indexOf);
}
public void ChangeLockOnTarget(){
if (!lockOnTarget) {
// If there is no target, simply find the closest to the center of the camera
GameObject mostForwardGameObject = null;
float mostForwardAngle = Mathf.Infinity;
foreach (GameObject target in lockOnTargets) {
// Skip targets behind walls
if (!Physics.Raycast(Camera.main.transform.position, Camera.main.transform.position - target.transform.position)) {
continue;
}
Vector3 dirToTarget = target.transform.position - Camera.main.transform.position;
float angleToTarget = Vector3.Angle(Camera.main.transform.forward, dirToTarget);
// Set the new target to closest to screen
if (angleToTarget < mostForwardAngle) {
mostForwardAngle = angleToTarget;
mostForwardGameObject = target;
}
}
// Set the winner to the new target
lockOnTarget = mostForwardGameObject;
targetGroup.Targets.Insert(1, new CinemachineTargetGroup.Target{
Object = mostForwardGameObject.transform,
Radius = 1f,
Weight = 0f
});
} else {
// Set it to either the next in the list or the first, if there already is a target
int desiredIndex;
if (lockOnTargets.IndexOf(lockOnTarget) == lockOnTargets.Count - 1) {
desiredIndex = 0;
} else {
desiredIndex = lockOnTargets.IndexOf(lockOnTarget) + 1;
}
lockOnTarget = lockOnTargets[desiredIndex];
targetGroup.Targets.Insert(1, new CinemachineTargetGroup.Target{
Object = lockOnTargets[desiredIndex].transform,
Radius = 1f,
Weight = 0f
});
}
}
public void RemoveLockOnTarget(){
lockOnTarget = null;
cmOrbitalFollow.HorizontalAxis.Center = transform.rotation.eulerAngles.y;
cmOrbitalFollow.HorizontalAxis.TriggerRecentering();
}
void UpdateLockOnUI(){
}
void LateUpdate(){
if (lockOnTarget) {
if (lockOnTarget.GetComponent<ILockOnTarget>() != null) {
// This is just test logic to get an image above a lock on.
// TODO: Replace with something less silly
Vector2 screenPos = RuntimePanelUtils.CameraTransformWorldToPanel(
lockOnDocument.rootVisualElement.panel,
lockOnTarget.GetComponent<ILockOnTarget>().GetReticlePosition(),
Camera.main.GetComponent<Camera>()
);
// Set name
elementLabelName.text = lockOnTarget.name;
// Set position (add the width/height of the element)
elementRoot.style.top = new StyleLength(screenPos.y - elementRoot.resolvedStyle.height * .7f);
elementRoot.style.left = new StyleLength(screenPos.x - elementRoot.resolvedStyle.width / 2f);
// Set enabled
elementRoot.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.Flex);
} else {
elementRoot.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
} else {
elementRoot.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
}
}