# Fruits Collector *Fruit sprites are sourced* ![[DESIGNS/TOYS/FruitCollector.gif]] ### Observer Manager ```cs public class Observer_V_Manager : MonoBehaviour { private int _pearScore; // internal data (incapsulation principle) private int _bananaScore; private int _grapeScore; private int _orangeScore; public int PearScore => _pearScore; // lambda: access to external data (similar to get; set;) public int BananaScore => _bananaScore; public int GrapeScore => _grapeScore; public int OrangeScore => _orangeScore; public event Action<int> OnPearChange; // the event that happens when the score changes public event Action<int> OnGrapeChange; public event Action<int> OnBananaChange; public event Action<int> OnOrangeChange; public static Observer_V_Manager 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 AddScore(string fruitName, int amount) { //if (amount <= 0) return; // "OnScoreChange" is an event action (int) keeps methods that were subscribed. // That is, these methods receive an update when the score is updated // "?" checks if there's at least one subscriber to the event // "Invoke" alarms all methods that subscribed to this event if (fruitName == "Pear") { _pearScore += amount; OnPearChange?.Invoke(_pearScore); } if (fruitName == "Banana") { _bananaScore += amount; OnBananaChange?.Invoke(_bananaScore); } if (fruitName == "Grape") { _grapeScore += amount; OnGrapeChange?.Invoke(_grapeScore); } if (fruitName == "Orange") { _orangeScore += amount; OnOrangeChange?.Invoke(_orangeScore); } } } ``` ### UI Manager ```cs public class Observer_V_UI : MonoBehaviour { public TMP_Text pearCounter; public TMP_Text bananaCounter; public TMP_Text grapesCounter; public TMP_Text orangeCounter; private void Start() { // Subscribing to the event "OnScoreChange" from the Manager.cs // I.e. it takes score from Manager and uses it in UpdateScore() Observer_V_Manager.Instance.OnPearChange += UpdatePear; Observer_V_Manager.Instance.OnBananaChange += UpdateBanana; Observer_V_Manager.Instance.OnGrapeChange += UpdateGrape; Observer_V_Manager.Instance.OnOrangeChange += UpdateOrange; // The scores are updated for the first time (on Start) // so that it displays 0 UpdatePear(Observer_V_Manager.Instance.PearScore); UpdateBanana(Observer_V_Manager.Instance.BananaScore); UpdateGrape(Observer_V_Manager.Instance.GrapeScore); UpdateOrange(Observer_V_Manager.Instance.OrangeScore); } /// <summary> /// SCORE UPDATERS /// </summary> /// <param name="newScore"></param> private void UpdatePear(int newScore) { pearCounter.text = newScore.ToString(); Debug.Log(newScore); } private void UpdateBanana(int newScore) { bananaCounter.text = newScore.ToString(); } private void UpdateGrape(int newScore) { grapesCounter.text = newScore.ToString(); } private void UpdateOrange(int newScore) { orangeCounter.text = newScore.ToString(); } } ``` ### Fruit Clicker ```cs public class Observer_V_FruitClicker : MonoBehaviour { public GameObject pearPref; public GameObject bananaPref; public GameObject grapePref; public GameObject orangePref; private void OnMouseDown() { if (gameObject.name == "Pear") InstantiateFruits(pearPref); if (gameObject.name == "Banana") InstantiateFruits(bananaPref); if (gameObject.name == "Grape") InstantiateFruits(grapePref); if (gameObject.name == "Orange") InstantiateFruits(orangePref); } private void InstantiateFruits(GameObject fruit) { for (int i = 0; i < 6; i++) { GameObject fruitClone = Instantiate(fruit, gameObject.transform.position, Quaternion.identity); fruitClone.name = fruit.name; Rigidbody2D rbClone = fruitClone.GetComponent<Rigidbody2D>(); rbClone.AddForce(new Vector2(Random.Range(-2,2), Random.Range(0,2)), ForceMode2D.Impulse); } Destroy(gameObject); } } ``` ### Small Fruit Controller ```cs public class Observer_V_SmallsController : MonoBehaviour { private bool falls; private void OnCollisionEnter2D(Collision2D col) { if (col.gameObject.CompareTag("Key")) AttachToFootball(col.gameObject); } private void AttachToFootball(GameObject football) { gameObject.transform.parent = football.gameObject.transform; Rigidbody2D rb = gameObject.GetComponent<Rigidbody2D>(); Destroy(rb); } private void OnTriggerEnter2D(Collider2D col) { if (col.gameObject.CompareTag("Door")) DecideToFall(col.gameObject); } private void DecideToFall(GameObject capsule) { if ((gameObject.name == "Pear" && capsule.name == "Pear_Capsule") || (gameObject.name == "Banana" && capsule.name == "Banana_Capsule") || (gameObject.name == "Grape" && capsule.name == "Grape_Capsule") || (gameObject.name == "Orange" && capsule.name == "Orange_Capsule")) { Fall(); } //Debug.Log("Collided"); } private void Fall() { gameObject.transform.parent = null; if (gameObject.GetComponent<Rigidbody2D>() == null) gameObject.AddComponent<Rigidbody2D>(); if (!falls) Observer_V_Manager.Instance.AddScore(gameObject.name, 1); falls = true; } // Substracts fruits that fell out of bound // Can be remade with the y position value, that will be relative to the capsule, // As a parent object (currently small fruits don't have a parent when they fall into the capsule) private void OutOfBound() { if (gameObject.transform.position.y <= -10f) { falls = false; Observer_V_Manager.Instance.AddScore(gameObject.name, -1); Destroy(gameObject); } } private void Update() { //if (falls) OutOfBound(); } } ``` ### Ball Controller ```cs public class Observer_V_FootballContr : MonoBehaviour { private bool isDragged; private void OnMouseDown() { isDragged = true; } private void OnMouseUp() { isDragged = false; } private void DragObject() { if (isDragged) { Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position; transform.Translate(mousePos); } } private void Update() { DragObject(); } } ``` ### Bottom Bound ```cs public class Observer_V_BottomBound : MonoBehaviour { private void OnCollisionEnter2D(Collision2D fruitCol) { if (fruitCol.gameObject.CompareTag("Fruit")) { Observer_V_Manager.Instance.AddScore(fruitCol.gameObject.name, -1); Destroy(fruitCol.gameObject); } } } ```