# 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);
}
}
}
```