Initial commit

This commit is contained in:
2025-12-17 17:34:04 +00:00
commit f5f40a85ee
13029 changed files with 2212323 additions and 0 deletions

215
Assets/Scripts/Shelf.cs Normal file
View 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);
}
}
}
}
}