Initial commit
This commit is contained in:
215
Assets/Scripts/Shelf.cs
Normal file
215
Assets/Scripts/Shelf.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[RequireComponent(typeof(BoxCollider))]
|
||||
public class Shelf : MonoBehaviour
|
||||
{
|
||||
[Header("Grid Settings")]
|
||||
[Tooltip("How many items fit horizontally")]
|
||||
public int columns = 5;
|
||||
[Tooltip("How many items fit vertically/deep")]
|
||||
public int rows = 2;
|
||||
|
||||
[Header("Snap Settings")]
|
||||
// Lift item slightly so it sits ON the shelf, not IN it
|
||||
public Vector3 offset = new Vector3(0, 0.1f, 0);
|
||||
|
||||
// Track which object is in which slot. Index 0 = Slot 0.
|
||||
private GameObject[] slotOccupants;
|
||||
private Vector3[] localGridPositions;
|
||||
private BoxCollider shelfCollider;
|
||||
|
||||
void Start()
|
||||
{
|
||||
shelfCollider = GetComponent<BoxCollider>();
|
||||
// Ensure the collider is a trigger so items can pass through to be detected
|
||||
shelfCollider.isTrigger = true;
|
||||
|
||||
CalculateGridPositions();
|
||||
|
||||
// Initialize occupancy array
|
||||
slotOccupants = new GameObject[columns * rows];
|
||||
}
|
||||
|
||||
[ContextMenu("Recalculate Grid")]
|
||||
void CalculateGridPositions()
|
||||
{
|
||||
if(shelfCollider == null) shelfCollider = GetComponent<BoxCollider>();
|
||||
|
||||
int totalSlots = columns * rows;
|
||||
localGridPositions = new Vector3[totalSlots];
|
||||
|
||||
// Get dimensions of the collider
|
||||
float width = shelfCollider.size.x;
|
||||
float depth = shelfCollider.size.z; // Assuming Y is Up, Z is depth
|
||||
|
||||
// Calculate cell size
|
||||
float cellWidth = width / columns;
|
||||
float cellDepth = depth / rows;
|
||||
|
||||
// Calculate starting point (Bottom-Left of the shelf surface)
|
||||
Vector3 startPos = shelfCollider.center - new Vector3(width / 2, -shelfCollider.size.y/2, depth / 2);
|
||||
startPos += new Vector3(cellWidth / 2, 0, cellDepth / 2);
|
||||
|
||||
int index = 0;
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
for (int c = 0; c < columns; c++)
|
||||
{
|
||||
// Calculate local position
|
||||
Vector3 pos = startPos + new Vector3(c * cellWidth, 0, r * cellDepth);
|
||||
localGridPositions[index] = pos;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
// 1. Check if it is an Item
|
||||
// 2. Check if we aren't ALREADY tracking it (prevents glitching)
|
||||
if (other.GetComponent<Item>() != null && !IsItemOnShelf(other.gameObject))
|
||||
{
|
||||
TrySnapItem(other.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (other.GetComponent<Item>() != null)
|
||||
{
|
||||
RemoveItem(other.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void TrySnapItem(GameObject itemObj)
|
||||
{
|
||||
int bestSlotIndex = -1;
|
||||
float closestDistance = float.MaxValue;
|
||||
|
||||
// --- NEW LOGIC: FIND CLOSEST EMPTY SLOT ---
|
||||
// Instead of grabbing the first empty one (which causes teleporting),
|
||||
// we check distance to find the slot closest to where you are holding the item.
|
||||
for (int i = 0; i < localGridPositions.Length; i++)
|
||||
{
|
||||
// Only check EMPTY slots
|
||||
if (slotOccupants[i] == null)
|
||||
{
|
||||
// Convert local grid point to world space to compare distance
|
||||
Vector3 worldSlotPos = transform.TransformPoint(localGridPositions[i]);
|
||||
float dist = Vector3.Distance(itemObj.transform.position, worldSlotPos);
|
||||
|
||||
// If this slot is closer than the last one we found, pick it
|
||||
if (dist < closestDistance)
|
||||
{
|
||||
closestDistance = dist;
|
||||
bestSlotIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If shelf is full, do nothing
|
||||
if (bestSlotIndex == -1) return;
|
||||
|
||||
// --- SNAP LOGIC ---
|
||||
slotOccupants[bestSlotIndex] = itemObj;
|
||||
|
||||
// --- PHYSICS FIX ---
|
||||
Rigidbody rb = itemObj.GetComponent<Rigidbody>();
|
||||
if(rb != null)
|
||||
{
|
||||
// 1. Stop the object FIRST
|
||||
rb.linearVelocity = Vector3.zero;
|
||||
rb.angularVelocity = Vector3.zero;
|
||||
|
||||
// 2. THEN disable physics interactions
|
||||
rb.isKinematic = true;
|
||||
}
|
||||
|
||||
// Move item to the best slot found
|
||||
Vector3 targetPos = transform.TransformPoint(localGridPositions[bestSlotIndex]) + offset;
|
||||
itemObj.transform.position = targetPos;
|
||||
itemObj.transform.rotation = transform.rotation;
|
||||
}
|
||||
|
||||
void RemoveItem(GameObject itemObj)
|
||||
{
|
||||
// Find where this item was and clear the slot
|
||||
for (int i = 0; i < slotOccupants.Length; i++)
|
||||
{
|
||||
if (slotOccupants[i] == itemObj)
|
||||
{
|
||||
slotOccupants[i] = null;
|
||||
|
||||
// Re-enable physics when leaving
|
||||
Rigidbody rb = itemObj.GetComponent<Rigidbody>();
|
||||
if (rb != null) rb.isKinematic = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to check if item is already physically tracked
|
||||
bool IsItemOnShelf(GameObject item)
|
||||
{
|
||||
for (int i = 0; i < slotOccupants.Length; i++)
|
||||
{
|
||||
if (slotOccupants[i] == item) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- INVENTORY LOGIC MERGED ---
|
||||
// This replaces your old Dictionary. It counts the actual physical items.
|
||||
// This is safer because it can never get "out of sync" with what you see.
|
||||
public int GetTotalItemCount()
|
||||
{
|
||||
int count = 0;
|
||||
if (slotOccupants != null)
|
||||
{
|
||||
foreach (var item in slotOccupants)
|
||||
{
|
||||
if (item != null) count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// DRAW THE GRID IN EDITOR SO WE CAN SEE IT
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (shelfCollider == null) shelfCollider = GetComponent<BoxCollider>();
|
||||
|
||||
// Visualize the cached positions if game is running
|
||||
if (Application.isPlaying && localGridPositions != null)
|
||||
{
|
||||
Gizmos.color = Color.green;
|
||||
foreach (Vector3 localPos in localGridPositions)
|
||||
{
|
||||
Vector3 worldPos = transform.TransformPoint(localPos);
|
||||
Gizmos.DrawWireSphere(worldPos, 0.05f);
|
||||
Gizmos.DrawWireCube(worldPos + offset, new Vector3(0.1f, 0.1f, 0.1f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback for Editor Mode (Logic repeated for visual aid before playing)
|
||||
Gizmos.color = Color.yellow;
|
||||
// ... Simple calc for editor preview only ...
|
||||
float w = shelfCollider.size.x;
|
||||
float d = shelfCollider.size.z;
|
||||
float cw = w / columns;
|
||||
float cd = d / rows;
|
||||
Vector3 start = shelfCollider.center - new Vector3(w/2, -shelfCollider.size.y/2, d/2) + new Vector3(cw/2, 0, cd/2);
|
||||
|
||||
for(int r=0; r<rows; r++) {
|
||||
for(int c=0; c<columns; c++) {
|
||||
Vector3 pos = start + new Vector3(c*cw, 0, r*cd);
|
||||
Vector3 worldPos = transform.TransformPoint(pos);
|
||||
Gizmos.DrawWireSphere(worldPos, 0.05f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user