# Unity 2D Point-and-Click System Below is a summary of the Unity 2D point-and-click system I created, including all scripts and setup instructions. This system features a score system, a limited inventory with sprites, mouse-based pickups, sound effects, and save/load functionality using `PlayerPrefs`. ## Summary of the Unity 2D Point-and-Click System This is a 2D point-and-click game built in Unity 6 where players: - Click to pick up **Point Items** (e.g., coins) to increase a score. - Click to collect **Collectable Items** (e.g., keys) into a limited inventory (5 slots) with sprite visuals. - Hear sound effects on pickup (`pointPickup.wav` and `collectablePickup.wav`). - See the score and inventory displayed via UI (TextMeshPro for score, sprite slots for inventory). - Persist score and inventory between sessions using `PlayerPrefs`. ### Scripts Overview 1. **GameManager.cs** - Manages the score, persists it with `PlayerPrefs`, and provides a singleton for global access. - *Key Methods*: `AddScore`, `GetScore`, `SaveScore`, `LoadScore`. 2. **Item.cs** - A serializable class to store an item’s name and sprite for the inventory. 3. **Inventory.cs** - Manages a list of `Item` objects with a 5-slot limit, saves/loads via `PlayerPrefs`, and uses `Resources.Load` for sprites. - *Key Methods*: `AddItem`, `GetItems`, `SaveInventory`, `LoadInventory`. 4. **ScoreUI.cs** - Updates a TextMeshPro UI element to display the current score. - *Key Method*: Updates `scoreText.text` in `Update`. 5. **PointItem.cs** - Attached to point-giving items; adds points and plays a sound on click, then destroys itself. - *Key Method*: `OnMouseDown`. 6. **CollectableItem.cs** - Attached to collectable items; adds to inventory with its sprite, plays a sound, updates UI, and destroys itself. - *Key Method*: `OnMouseDown`. 7. **InventoryUI.cs** - Displays inventory items as sprites in 5 UI Image slots, updating when items are added or loaded. - *Key Method*: `UpdateInventoryUI`. 8. **AudioManager.cs** - Plays sound effects for pickups using an `AudioSource` and two `AudioClip`s. - *Key Methods*: `PlayPointPickup`, `PlayCollectablePickup`. --- ## All Scripts ### GameManager.cs ```csharp using UnityEngine; public class GameManager : MonoBehaviour { public static GameManager Instance; private int score = 0; void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); LoadScore(); } else { Destroy(gameObject); } } public void AddScore(int points) { score += points; SaveScore(); Debug.Log("Score: " + score); } public int GetScore() { return score; } void SaveScore() { PlayerPrefs.SetInt("PlayerScore", score); PlayerPrefs.Save(); } void LoadScore() { score = PlayerPrefs.GetInt("PlayerScore", 0); } } ``` --- ### Item.cs ```csharp using UnityEngine; [System.Serializable] public class Item { public string itemName; public Sprite itemSprite; public Item(string name, Sprite sprite) { itemName = name; itemSprite = sprite; } } ``` --- ### Inventory.cs ```csharp using UnityEngine; using System.Collections.Generic; public class Inventory : MonoBehaviour { public static Inventory Instance; public int maxSlots = 5; private List<Item> items = new List<Item>(); void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); LoadInventory(); } else { Destroy(gameObject); } } public bool AddItem(string itemName, Sprite itemSprite) { if (items.Count < maxSlots) { items.Add(new Item(itemName, itemSprite)); SaveInventory(); Debug.Log("Collected: " + itemName + " | Inventory: " + items.Count + "/" + maxSlots); return true; } else { Debug.Log("Inventory full!"); return false; } } public List<Item> GetItems() { return items; } void SaveInventory() { PlayerPrefs.SetInt("InventoryCount", items.Count); for (int i = 0; i < items.Count; i++) { PlayerPrefs.SetString("ItemName" + i, items[i].itemName); } PlayerPrefs.Save(); } void LoadInventory() { items.Clear(); int count = PlayerPrefs.GetInt("InventoryCount", 0); for (int i = 0; i < count; i++) { string itemName = PlayerPrefs.GetString("ItemName" + i, ""); Sprite itemSprite = Resources.Load<Sprite>("Items/" + itemName); if (itemSprite != null) items.Add(new Item(itemName, itemSprite)); } InventoryUI inventoryUI = FindObjectOfType<InventoryUI>(); if (inventoryUI != null) inventoryUI.UpdateInventoryUI(); } } ``` --- ### ScoreUI.cs ```csharp using UnityEngine; using TMPro; public class ScoreUI : MonoBehaviour { public TextMeshProUGUI scoreText; void Update() { scoreText.text = "Score: " + GameManager.Instance.GetScore(); } } ``` --- ### PointItem.cs ```csharp using UnityEngine; public class PointItem : MonoBehaviour { public int pointsValue = 10; void OnMouseDown() { GameManager.Instance.AddScore(pointsValue); AudioManager.Instance.PlayPointPickup(); Destroy(gameObject); } } ``` --- ### CollectableItem.cs ```csharp using UnityEngine; public class CollectableItem : MonoBehaviour { public string itemName = "Key"; public Sprite itemSprite; void Awake() { if (itemSprite == null && GetComponent<SpriteRenderer>() != null) itemSprite = GetComponent<SpriteRenderer>().sprite; } void OnMouseDown() { if (Inventory.Instance.AddItem(itemName, itemSprite)) { AudioManager.Instance.PlayCollectablePickup(); InventoryUI inventoryUI = FindObjectOfType<InventoryUI>(); if (inventoryUI != null) inventoryUI.UpdateInventoryUI(); Destroy(gameObject); } } } ``` --- ### InventoryUI.cs ```csharp using UnityEngine; using UnityEngine.UI; public class InventoryUI : MonoBehaviour { public Image[] inventorySlots; void Start() { if (inventorySlots.Length != Inventory.Instance.maxSlots) { Debug.LogError("Inventory slots in UI (" + inventorySlots.Length + ") must match maxSlots (" + Inventory.Instance.maxSlots + ")!"); } UpdateInventoryUI(); } public void UpdateInventoryUI() { var items = Inventory.Instance.GetItems(); for (int i = 0; i < inventorySlots.Length; i++) { if (i < items.Count) { inventorySlots[i].sprite = items[i].itemSprite; inventorySlots[i].color = Color.white; } else { inventorySlots[i].sprite = null; inventorySlots[i].color = new Color(1, 1, 1, 0); } } } } ``` --- ### AudioManager.cs ```csharp using UnityEngine; public class AudioManager : MonoBehaviour { public static AudioManager Instance; public AudioSource audioSource; public AudioClip pointPickupSound; public AudioClip collectablePickupSound; void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } audioSource = GetComponent<AudioSource>(); } public void PlayPointPickup() { if (pointPickupSound != null) audioSource.PlayOneShot(pointPickupSound); } public void PlayCollectablePickup() { if (collectablePickupSound != null) audioSource.PlayOneShot(collectablePickupSound); } } ``` --- ## Directions for Setting Up in a Unity Scene ### Scene Setup 1. **Create Managers**: - Create an empty GameObject named "GameManager". - Attach `GameManager.cs` and `Inventory.cs`. - Create an empty GameObject named "AudioManager". - Attach `AudioManager.cs`. - Add an `AudioSource` component. - Assign `pointPickupSound` and `collectablePickupSound` (e.g., "Assets/Sounds/pointPickup.wav" and "Assets/Sounds/collectablePickup.wav"). - see [[Creating Audio (Tools)]] about how to create custom audio. 2. **Set Up UI**: - **Score UI**: - Go to **GameObject > UI > Text - TextMeshPro**. Name it "ScoreTextTMP". - Position it (e.g., top-left). - Attach `ScoreUI.cs` and assign the `TextMeshProUGUI` component to `scoreText`. - **Inventory UI**: - Go to **GameObject > UI > Panel**. Name it "InventoryPanel". - Position it (e.g., bottom of screen, Height: 100). - Inside "InventoryPanel", create 5 **GameObject > UI > Image** objects (e.g., "Slot1" to "Slot5"). - Size each slot (e.g., 64x64) and arrange horizontally. - Attach `InventoryUI.cs` to "InventoryPanel" and drag the 5 Image objects into the `inventorySlots` array. 3. **Create Item Prefabs**: - **Point Item**: - Create a 2D sprite (e.g., a coin) in the scene. - Add a `BoxCollider2D` (or similar 2D collider). - Attach `PointItem.cs` and set `pointsValue` (e.g., 10). - Drag to "Assets/Prefabs" to make a prefab. - **Collectable Item**: - Create a 2D sprite (e.g., a key). - Add a `BoxCollider2D`. - Attach `CollectableItem.cs`, set `itemName` (e.g., "Key"), and optionally assign `itemSprite` (or it auto-grabs from SpriteRenderer). - Drag to "Assets/Prefabs". - Place sprites in "Assets/Resources/Items/" (e.g., "Key.png") for `PlayerPrefs` loading. 4. **Add Items to Scene**: - Drag instances of the Point Item and Collectable Item prefabs into your scene. 5. **Camera Setup**: - Ensure the Main Camera is Orthographic (default for 2D) and covers the play area. ### Testing - **Run the Game**: - Click a Point Item: Score increases, sound plays, item disappears. - Click a Collectable Item: Adds to inventory (sprite appears in UI), sound plays, item disappears (stops at 5 items). - Quit and restart: Score and inventory persist via `PlayerPrefs`.