152 lines
4.9 KiB
C#
152 lines
4.9 KiB
C#
using UnityEngine;
|
|
using TMPro;
|
|
|
|
public class RayCastSystem : MonoBehaviour
|
|
{
|
|
[Header("Layer Settings")]
|
|
public LayerMask interactableLayers;
|
|
|
|
[Header("Highlight Settings")]
|
|
public Color highlightColor = new Color(1f, 1f, 0f, 0.35f);
|
|
public float padding = 1.02f;
|
|
|
|
private Camera mainCamera;
|
|
private GameObject currentSelection;
|
|
private GameObject outlineObject;
|
|
private MeshFilter outlineFilter;
|
|
private MeshRenderer outlineRenderer;
|
|
private Rigidbody currentPickedRB = null;
|
|
|
|
[Header("UI Elements")]
|
|
public TMP_Text itemCountText;
|
|
|
|
void Start()
|
|
{
|
|
mainCamera = Camera.main;
|
|
CreateOutlineObject();
|
|
if(itemCountText) itemCountText.gameObject.SetActive(false);
|
|
}
|
|
|
|
void CreateOutlineObject()
|
|
{
|
|
outlineObject = new GameObject("SelectionHighlight");
|
|
outlineFilter = outlineObject.AddComponent<MeshFilter>();
|
|
outlineRenderer = outlineObject.AddComponent<MeshRenderer>();
|
|
|
|
Material ghostMat = new Material(Shader.Find("Standard"));
|
|
|
|
// Optimize Material: Enable GPU Instancing
|
|
ghostMat.enableInstancing = true;
|
|
ghostMat.SetFloat("_Mode", 3); // Transparent
|
|
ghostMat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
|
|
ghostMat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
ghostMat.SetInt("_ZWrite", 0);
|
|
ghostMat.DisableKeyword("_ALPHATEST_ON");
|
|
ghostMat.EnableKeyword("_ALPHABLEND_ON");
|
|
ghostMat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
|
ghostMat.renderQueue = 3000;
|
|
|
|
ghostMat.color = highlightColor;
|
|
ghostMat.EnableKeyword("_EMISSION");
|
|
ghostMat.SetColor("_EmissionColor", highlightColor * 0.5f);
|
|
|
|
outlineRenderer.material = ghostMat;
|
|
outlineObject.SetActive(false);
|
|
|
|
// OPTIMIZATION: Do not parent to the player.
|
|
// Keeping it in the root ensures Scale calculations are always 1:1 with the target.
|
|
outlineObject.transform.SetParent(null);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
RaycastHit hit;
|
|
// Perform Raycast
|
|
if (Physics.Raycast(mainCamera.transform.position, mainCamera.transform.forward, out hit, 100f, interactableLayers))
|
|
{
|
|
GameObject hitObject = hit.collider.gameObject;
|
|
|
|
// Only run expensive logic if the selection ACTUALLY changed
|
|
if (currentSelection != hitObject)
|
|
{
|
|
currentSelection = hitObject;
|
|
UpdateOutline(currentSelection);
|
|
UpdateUI(currentSelection); // Separated UI logic for cleanliness
|
|
}
|
|
|
|
// Keep outline snapped
|
|
if (currentSelection != null && outlineObject.activeSelf)
|
|
{
|
|
FollowTarget(currentSelection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (currentSelection != null) ClearSelection();
|
|
}
|
|
}
|
|
|
|
void UpdateUI(GameObject target)
|
|
{
|
|
if (itemCountText == null) return;
|
|
|
|
Shelf shelf = target.GetComponent<Shelf>();
|
|
|
|
if (shelf != null)
|
|
{
|
|
// PERFORMANCE FIX:
|
|
// Instead of getting a whole dictionary, we just ask for the count directly.
|
|
// You need to add 'public int ItemCount' or similar to your Shelf script.
|
|
itemCountText.text = $"Items: {shelf.GetTotalItemCount()}";
|
|
itemCountText.gameObject.SetActive(true);
|
|
}
|
|
else
|
|
{
|
|
itemCountText.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
void UpdateOutline(GameObject target)
|
|
{
|
|
if(currentPickedRB != null) {
|
|
outlineObject.SetActive(false);
|
|
return;
|
|
}
|
|
|
|
MeshFilter targetMeshFilter = target.GetComponent<MeshFilter>();
|
|
if (targetMeshFilter == null) targetMeshFilter = target.GetComponentInChildren<MeshFilter>();
|
|
|
|
if (targetMeshFilter == null)
|
|
{
|
|
outlineObject.SetActive(false);
|
|
return;
|
|
}
|
|
|
|
// Lightweight: Just swapping the reference, not creating new meshes
|
|
outlineFilter.sharedMesh = targetMeshFilter.sharedMesh;
|
|
|
|
FollowTarget(target);
|
|
outlineObject.SetActive(true);
|
|
}
|
|
|
|
void FollowTarget(GameObject target)
|
|
{
|
|
outlineObject.transform.position = target.transform.position;
|
|
outlineObject.transform.rotation = target.transform.rotation;
|
|
// This math is safer now that outlineObject is not a child of the Player
|
|
outlineObject.transform.localScale = target.transform.localScale * padding;
|
|
}
|
|
|
|
void ClearSelection()
|
|
{
|
|
currentSelection = null;
|
|
outlineObject.SetActive(false);
|
|
if (itemCountText) itemCountText.gameObject.SetActive(false);
|
|
}
|
|
|
|
public void SetCurrentPickedRB(Rigidbody rb)
|
|
{
|
|
currentPickedRB = rb;
|
|
if (currentPickedRB != null) ClearSelection();
|
|
}
|
|
} |