# Inventory Manager **Technology**: The inventory system is implemented through the Observer pattern **Assets** are sourced ![[DESIGNS/TOYS/InventoryObserver.gif]] ## Code #### Observer Manager ```cs using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arcade_II_Observer : MonoBehaviour { private string _weaponName; public string WeaponName => _weaponName; public Action<string> OnWeaponSelection; public static Arcade_II_Observer Instance; // Similar to singleton void Start() private void Awake() { // Similar to Singleton -- preserves clones if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; } public void DisplayWeapon(string weaponName) { OnWeaponSelection?.Invoke(_weaponName); } } ``` #### Player Controller (1) Inventory panel follows the player when it moves (2) When the weapon is dragged to the player's hands, it moves with him (3) Player movement ```cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arcade_II_Player : MonoBehaviour { [Header ("Movement")] public float moveSpeed = 5f; public float jumpForce = 4f; private Rigidbody2D rb; private bool isGrounded = false; [Header("Inventory")] public GameObject[] invWeapons = new GameObject[3]; public GameObject[] invWeapPositions = new GameObject[3]; public GameObject inventoryPanel; private bool inventoryOpen; [Header("Hands")] public GameObject hands; private int handsTurnValue; // for when the avatar turns left and right private string currentWeaponInHand; [Header("Hands Mockups")] public GameObject m_bomb; public GameObject m_knife; public GameObject m_gun; [Header("UI")] public GameObject gameOverPanel; void Start() { rb = GetComponent<Rigidbody2D>(); // Get the Rigidbody2D component handsTurnValue = -1; Arcade_II_Observer.Instance.OnWeaponSelection += ShowWeapon; } void Update() { MoveAvatar(); FixRotation(); FollowPlayer_Hands(); OpenInventory(); if(inventoryOpen) FollowPlayer_Inventory(); } public void GameOverUI() { gameOverPanel.SetActive(true); } /// <summary> /// INVENTORY /// </summary> private void OpenInventory() { if (Input.GetKeyDown(KeyCode.I)) { if (!inventoryOpen) { inventoryPanel.SetActive(true); inventoryOpen = true; inventoryPanel.transform.parent = null; } else CloseInventory(); } } private void CloseInventory() { inventoryPanel.SetActive(false); inventoryOpen = false; } private void FollowPlayer_Inventory() { Vector3 newPos = new Vector3 (gameObject.transform.position.x, gameObject.transform.position.y + 3.5f, 0); inventoryPanel.transform.position = newPos; } private void FollowPlayer_Hands() { Vector3 newPos = new Vector3 (gameObject.transform.position.x + handsTurnValue, gameObject.transform.position.y, 0); hands.transform.position = newPos; // So that the weapon in hands turns in a related direction hands.transform.localScale = new Vector3( 0.4f * -handsTurnValue, gameObject.transform.localScale.y, gameObject.transform.localScale.z); } private void ShowWeapon(string weaponName) { currentWeaponInHand = weaponName; DeactivateWeapondInHand(); ActivateInventoryIcons(); if (weaponName == "Bomb") m_bomb.gameObject.SetActive(true); if (weaponName == "Knife") m_knife.gameObject.SetActive(true); if (weaponName == "Gun") m_gun.gameObject.SetActive(true); CloseInventory(); } private void DeactivateWeapondInHand() { m_bomb.gameObject.SetActive(false); m_knife.gameObject.SetActive(false); m_gun.gameObject.SetActive(false); } private void ActivateInventoryIcons() { foreach (GameObject weapon in invWeapons) { if (weapon.name != currentWeaponInHand) { weapon.SetActive(true); } } } /// <summary> /// MOVEMENT /// </summary> /// <param name="collision"></param> // Detect ground using collision private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.CompareTag("Ground")) { isGrounded = true; } } private void MoveAvatar() { // Get horizontal movement input float moveInput = Input.GetAxis("Horizontal"); // Move left & right rb.velocity = new Vector2(moveInput * moveSpeed, rb.velocity.y); // Turning left / right if (moveInput < 0) { handsTurnValue = -1; gameObject.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f); } if (moveInput > 0) { handsTurnValue = 1; gameObject.transform.localScale = new Vector3(-0.4f, 0.4f, 0.4f); } // Jump when SPACE is pressed & only if grounded if (Input.GetKeyDown(KeyCode.Space) && isGrounded) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); isGrounded = false; // Prevents double jumping } } private void FixRotation() { gameObject.GetComponent<Transform>().rotation = Quaternion.Euler(0, 0, 0); } } ``` #### Weapon Manager (1) Notifies the observer which weapon is in hands (2) Allows dragging weapons on mouse ```cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arcade_II_Weapon : MonoBehaviour { public Transform avatarTr; public Transform handsTr; public Transform inventoryTr; public GameObject defaultPosObj; private Vector3 defaultPos; private bool isDragged; private bool inHands; private void Start() { defaultPos = defaultPosObj.transform.localPosition; } public void OnMouseDown() { isDragged = true; if (inHands) { gameObject.transform.localPosition = defaultPos; inHands = false; } } public void OnMouseUp() { isDragged = false; gameObject.transform.localPosition = defaultPos; if (inHands) { Arcade_II_Observer.Instance.OnWeaponSelection(gameObject.name); gameObject.SetActive(false); } } private void OnTriggerEnter2D(Collider2D col) { if (col.gameObject.CompareTag("Hands")) { inHands = true; } if (col.gameObject.CompareTag("Key")) { Arcade_II_Weapon weaponScr = col.gameObject.GetComponent<Arcade_II_Weapon>(); weaponScr.inHands = false; weaponScr.OnMouseUp(); } } /// <summary> /// DRAGGING /// </summary> private void DragObject() { if (isDragged) { Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position; transform.Translate(mousePos); } } private void Update() { DragObject(); } } ``` #### Fighting Controller Performs different attacks on F (fire) button ```cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arcade_II_Fighting : MonoBehaviour { public string weaponName; public GameObject hands; // to understand the direction public GameObject detail; public GameObject detailPos; private GameObject newDetail; // for instantiations private void Update() { if (Input.GetKeyDown(KeyCode.F)) Action(); } private void Action() { if (weaponName == "Bomb") BombAction(); if (weaponName == "Knife") KnifeAction(); if (weaponName == "Gun") GunAction(); } private void BombAction() { Arcade_II_Bomb bombScript = gameObject.GetComponent<Arcade_II_Bomb>(); // The argument defines which direction the avatar is facing if (hands.transform.localScale.x > 0) bombScript.ThrowBomb(false); if (hands.transform.localScale.x < 0) bombScript.ThrowBomb(true); } private void KnifeAction() { Animator knifeAnimator = GetComponent<Animator>(); knifeAnimator.SetTrigger("play"); } private void GunAction() { newDetail = Instantiate(detail, detailPos.transform.position, Quaternion.identity); Arcade_II_Bullet newDetailScr = newDetail.GetComponent<Arcade_II_Bullet>(); // Define direction if (hands.transform.localScale.x > 0) newDetailScr.direction = Vector3.left; else if (hands.transform.localScale.x < 0) newDetailScr.direction = Vector3.right; } } ``` ##### Bomb Controls the bomb weapon's explosion ```cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arcade_II_Bomb : MonoBehaviour { public GameObject bombPiece; private GameObject newBombPiece; // for instantiations public GameObject hands; private Vector3 handsPos; private Rigidbody2D rb; private CircleCollider2D cCol; private Vector3 bombForce; public void ThrowBomb(bool facesRight) { gameObject.transform.parent = null; rb = gameObject.AddComponent<Rigidbody2D>(); cCol = gameObject.AddComponent<CircleCollider2D>(); if (facesRight) bombForce = new Vector3(5, 3, 0); if (!facesRight) bombForce = new Vector3(-5, 3, 0); rb.AddForce(bombForce, ForceMode2D.Impulse); } private void OnCollisionEnter2D(Collision2D col) { if (col.gameObject.CompareTag("Ground")) { //gameObject.GetComponent<SpriteRenderer>().enabled = false; for (int i = 0; i < 20; i++) { newBombPiece = Instantiate(bombPiece, gameObject.transform.position, Quaternion.identity); int forceX = Random.Range(-4, 4); int forceY = Random.Range(3, 8); Vector3 forceVec = new Vector3(forceX, forceY, 0); newBombPiece.AddComponent<Rigidbody2D>().AddForce (forceVec, ForceMode2D.Impulse); } gameObject.transform.parent = hands.gameObject.transform; gameObject.transform.position = hands.transform.position; Destroy(rb); Destroy(cCol); } } } ``` #### Enemy Generator ```cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class Arcade_II_EnemyGenerator : MonoBehaviour { public GameObject enemyPref; public float repeatRate = 5; private GameObject enemyInstance; private Vector3 enemyPos; private void Start() { InvokeRepeating("InstantEnemy", 2, repeatRate); } private void InstantEnemy() { int x = Random.Range(-7, 7); enemyPos = new Vector3(x, 6, 0); enemyInstance = Instantiate(enemyPref, enemyPos, Quaternion.identity); } } ```