Initial commit
This commit is contained in:
152
Assets/Scripts/RayCastSystem.cs
Normal file
152
Assets/Scripts/RayCastSystem.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user