-
Notifications
You must be signed in to change notification settings - Fork 0
Add Unity 2D mansion quest gameplay scripts #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| using UnityEngine; | ||
|
|
||
| [RequireComponent(typeof(Collider2D))] | ||
| public class DoorTeleporter : MonoBehaviour | ||
| { | ||
| [SerializeField] private Transform destinationPoint; | ||
| [SerializeField] private KeyCode interactKey = KeyCode.E; | ||
|
|
||
| private bool playerInside; | ||
| private Transform player; | ||
|
|
||
| private void Reset() | ||
| { | ||
| var col = GetComponent<Collider2D>(); | ||
| col.isTrigger = true; | ||
| } | ||
|
|
||
| private void Update() | ||
| { | ||
| if (playerInside && destinationPoint != null && Input.GetKeyDown(interactKey)) | ||
| { | ||
| player.position = destinationPoint.position; | ||
| } | ||
| } | ||
|
|
||
| private void OnTriggerEnter2D(Collider2D other) | ||
| { | ||
| if (!other.CompareTag("Player")) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| playerInside = true; | ||
| player = other.transform; | ||
| } | ||
|
|
||
| private void OnTriggerExit2D(Collider2D other) | ||
| { | ||
| if (!other.CompareTag("Player")) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| playerInside = false; | ||
| player = null; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| using System.Collections.Generic; | ||
| using UnityEngine; | ||
|
|
||
| public class Inventory2D : MonoBehaviour | ||
| { | ||
| [SerializeField] private int maxItems = 10; | ||
|
|
||
| private readonly List<ItemType> items = new List<ItemType>(); | ||
|
|
||
| public bool AddItem(ItemType item) | ||
| { | ||
| if (item == ItemType.None || items.Count >= maxItems) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| items.Add(item); | ||
| return true; | ||
| } | ||
|
|
||
| public bool HasItem(ItemType item) | ||
| { | ||
| return items.Contains(item); | ||
| } | ||
|
|
||
| public bool RemoveItem(ItemType item) | ||
| { | ||
| return items.Remove(item); | ||
| } | ||
|
|
||
| public IReadOnlyList<ItemType> Items | ||
| { | ||
| get { return items; } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| using UnityEngine; | ||
|
|
||
| [RequireComponent(typeof(Collider2D))] | ||
| public class ItemPickup : MonoBehaviour | ||
| { | ||
| [SerializeField] private ItemType itemType; | ||
|
|
||
| public void Configure(ItemType type) | ||
| { | ||
| itemType = type; | ||
| } | ||
|
|
||
| private void Reset() | ||
| { | ||
| var col = GetComponent<Collider2D>(); | ||
| col.isTrigger = true; | ||
| } | ||
|
|
||
| private void OnTriggerEnter2D(Collider2D other) | ||
| { | ||
| var inventory = other.GetComponent<Inventory2D>(); | ||
| if (inventory == null) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| if (inventory.AddItem(itemType)) | ||
| { | ||
| Destroy(gameObject); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| public enum ItemType | ||
| { | ||
| None = 0, | ||
| Key, | ||
| Book, | ||
| Candle, | ||
| Potion, | ||
| Gem, | ||
| Scroll | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| using System.Collections.Generic; | ||
| using UnityEngine; | ||
| using UnityEngine.Events; | ||
|
|
||
| public class MansionQuestManager : MonoBehaviour | ||
| { | ||
| [SerializeField] private List<NPCRequester> npcs = new List<NPCRequester>(); | ||
| [SerializeField] private List<ItemType> possibleRequests = new List<ItemType>(); | ||
| [SerializeField] private bool uniqueRequests = true; | ||
| [SerializeField] private UnityEvent onAllNPCsSatisfied; | ||
|
|
||
| private void Start() | ||
| { | ||
| AssignRequests(); | ||
| } | ||
|
|
||
| public void AssignRequests() | ||
| { | ||
| if (npcs.Count == 0 || possibleRequests.Count == 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| List<ItemType> pool = new List<ItemType>(possibleRequests); | ||
|
|
||
| for (int i = 0; i < npcs.Count; i++) | ||
| { | ||
| if (npcs[i] == null) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| if (pool.Count == 0) | ||
| { | ||
| pool = new List<ItemType>(possibleRequests); | ||
| } | ||
|
|
||
| int index = Random.Range(0, pool.Count); | ||
| ItemType selected = pool[index]; | ||
| npcs[i].SetRequest(selected); | ||
|
|
||
| if (uniqueRequests) | ||
| { | ||
| pool.RemoveAt(index); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public void CheckQuestState() | ||
| { | ||
| for (int i = 0; i < npcs.Count; i++) | ||
| { | ||
| if (npcs[i] != null && !npcs[i].IsSatisfied) | ||
| { | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| onAllNPCsSatisfied?.Invoke(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| using UnityEngine; | ||
| using UnityEngine.Events; | ||
|
|
||
| [RequireComponent(typeof(Collider2D))] | ||
| public class NPCRequester : MonoBehaviour | ||
| { | ||
| [Header("Pedido")] | ||
| [SerializeField] private ItemType requestedItem = ItemType.None; | ||
| [SerializeField] private bool consumeItemOnDelivery = true; | ||
| [SerializeField] private MansionQuestManager questManager; | ||
|
|
||
| [Header("Eventos")] | ||
| [SerializeField] private UnityEvent onCorrectItemDelivered; | ||
| [SerializeField] private UnityEvent onWrongItemOrMissing; | ||
|
|
||
| public ItemType RequestedItem => requestedItem; | ||
| public bool IsSatisfied { get; private set; } | ||
|
|
||
| private void Reset() | ||
| { | ||
| var col = GetComponent<Collider2D>(); | ||
| col.isTrigger = true; | ||
| } | ||
|
|
||
| public void SetRequest(ItemType item) | ||
| { | ||
| requestedItem = item; | ||
| IsSatisfied = false; | ||
| } | ||
|
|
||
| private void OnTriggerStay2D(Collider2D other) | ||
| { | ||
| if (IsSatisfied) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| if (!other.CompareTag("Player") || !Input.GetKeyDown(KeyCode.E)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The NPC hand-in gate uses Useful? React with 👍 / 👎. |
||
| { | ||
| return; | ||
| } | ||
|
|
||
| var inventory = other.GetComponent<Inventory2D>(); | ||
| if (inventory == null) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| if (requestedItem != ItemType.None && inventory.HasItem(requestedItem)) | ||
| { | ||
| if (consumeItemOnDelivery) | ||
| { | ||
| inventory.RemoveItem(requestedItem); | ||
| } | ||
|
|
||
| IsSatisfied = true; | ||
| onCorrectItemDelivered?.Invoke(); | ||
| questManager?.CheckQuestState(); | ||
| return; | ||
| } | ||
|
|
||
| onWrongItemOrMissing?.Invoke(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| using System.Collections.Generic; | ||
| using UnityEngine; | ||
|
|
||
| public class RandomItemSpawner : MonoBehaviour | ||
| { | ||
| [System.Serializable] | ||
| public struct SpawnEntry | ||
| { | ||
| public ItemType itemType; | ||
| public GameObject prefab; | ||
| } | ||
|
|
||
| [SerializeField] private List<SpawnEntry> itemPrefabs = new List<SpawnEntry>(); | ||
| [SerializeField] private List<Transform> spawnPoints = new List<Transform>(); | ||
| [SerializeField] private int spawnCount = 8; | ||
|
|
||
| private readonly List<GameObject> spawnedItems = new List<GameObject>(); | ||
|
|
||
| private void Start() | ||
| { | ||
| SpawnItems(); | ||
| } | ||
|
|
||
| public void SpawnItems() | ||
| { | ||
| ClearItems(); | ||
|
|
||
| if (itemPrefabs.Count == 0 || spawnPoints.Count == 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| int max = Mathf.Min(spawnCount, spawnPoints.Count); | ||
| List<Transform> shuffledPoints = new List<Transform>(spawnPoints); | ||
| Shuffle(shuffledPoints); | ||
|
|
||
| for (int i = 0; i < max; i++) | ||
| { | ||
| SpawnEntry entry = itemPrefabs[Random.Range(0, itemPrefabs.Count)]; | ||
| if (entry.prefab == null) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| GameObject instance = Instantiate(entry.prefab, shuffledPoints[i].position, Quaternion.identity); | ||
| ItemPickup pickup = instance.GetComponent<ItemPickup>(); | ||
| if (pickup == null) | ||
| { | ||
| pickup = instance.AddComponent<ItemPickup>(); | ||
| } | ||
|
|
||
| pickup.Configure(entry.itemType); | ||
| spawnedItems.Add(instance); | ||
| } | ||
| } | ||
|
|
||
| public void ClearItems() | ||
| { | ||
| for (int i = 0; i < spawnedItems.Count; i++) | ||
| { | ||
| if (spawnedItems[i] != null) | ||
| { | ||
| Destroy(spawnedItems[i]); | ||
| } | ||
| } | ||
|
|
||
| spawnedItems.Clear(); | ||
| } | ||
|
|
||
| private static void Shuffle<T>(List<T> list) | ||
| { | ||
| for (int i = 0; i < list.Count; i++) | ||
| { | ||
| int randomIndex = Random.Range(i, list.Count); | ||
| T temp = list[i]; | ||
| list[i] = list[randomIndex]; | ||
| list[randomIndex] = temp; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Sistema de missão para mansão 2D (Unity) | ||
|
|
||
| Este repositório inclui scripts base para o cenário pedido: | ||
|
|
||
| - 3 NPCs pedindo itens específicos. | ||
| - NPC aceita **somente** o item correto. | ||
| - Itens com spawn aleatório nas salas da mansão. | ||
| - Portas para transitar entre salas. | ||
|
|
||
| ## Scripts | ||
|
|
||
| - `ItemType.cs`: enum com os tipos de item. | ||
| - `Inventory2D.cs`: inventário simples do jogador. | ||
| - `ItemPickup.cs`: coleta itens ao encostar no jogador. | ||
| - `NPCRequester.cs`: valida entrega de item no NPC ao pressionar `E`. | ||
| - `RandomItemSpawner.cs`: sorteia e instancia itens em pontos de spawn. | ||
| - `DoorTeleporter.cs`: teleporta jogador para outra sala ao interagir com porta. | ||
| - `MansionQuestManager.cs`: distribui pedidos aos NPCs e detecta conclusão. | ||
|
|
||
| ## Configuração rápida | ||
|
|
||
| 1. Adicione `Inventory2D` no objeto Player (com tag `Player`). | ||
| 2. Crie prefabs de item com `Collider2D` trigger + `ItemPickup`. | ||
| 3. Em cada NPC, adicione `Collider2D` trigger + `NPCRequester`. | ||
| 4. Crie um objeto `GameManager` com `MansionQuestManager` e referencie os 3 NPCs. | ||
| 5. Configure `possibleRequests` com os tipos de item permitidos. | ||
| 6. Crie um objeto `RandomItemSpawner`, informe `spawnPoints` e os prefabs dos itens. | ||
| 7. Em cada porta, adicione `DoorTeleporter` e informe o `destinationPoint` da próxima sala. | ||
|
|
||
| ## Fluxo de jogo | ||
|
|
||
| - Jogador explora salas da mansão. | ||
| - Coleta itens sorteados nos pontos de spawn. | ||
| - Entra em portas para acessar novas salas. | ||
| - Entrega cada item no NPC correto usando `E`. | ||
| - Quando os 3 NPCs estiverem satisfeitos, `onAllNPCsSatisfied` é disparado. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quest completion is only checked through
questManager?.CheckQuestState()inNPCRequester, butMansionQuestManager.AssignRequests()currently configures only the requested item and never injects itself into the NPCs. In scenes where designers only populate the manager's NPC list (as the quick setup suggests), each NPC'squestManagerstays null andonAllNPCsSatisfiedwill never be evaluated after deliveries.Useful? React with 👍 / 👎.