Momo-Space-Diner-Code-Repo / FruitSlicerGameManager.cs
FruitSlicerGameManager.cs
Raw
using ML.SDK;
using System.Collections;
using TMPro;
using UnityEngine;

public class FruitSlicerGameManager : MonoBehaviour
{
    public MLClickable StartButton;
    public MLClickable EndButton;
    public GameObject[] fruits;
    public TextMeshPro WaveNumberText;
    public float averageSpeedOfFruit = 5f;
    public int startingNumberOfFruits = 5;
    public TextMeshPro CountDownText;
    public GameObject EnableDisableTextCounter;
    public Transform spawnPoint; // Current spawn point (moves)
    public Transform spawnPointStart; // Start position for spawn point movement
    public Transform spawnPointEnd; // End position for spawn point movement
    public float spawnPointMovementSpeed = 2f; // Speed of spawn point movement
    public Transform fruitTargetPoint; // Point towards which fruits will arc
    public Collider failZone;
    public int maxFruitDropsAllowed = 4;
    public GameObject collisionParticleEffect;
    public GameObject sliceParticleEffect;
    public TextMeshPro ComboCounterText;
    public TextMeshPro ScoreText;
    public GameObject[] Lives;
    public TextMeshPro HighestScore;

    private int currentWave = 1;
    private bool isGameRunning = false;
    private int fruitsPerWave;
    private int fruitDrops = 0;
    private float initialSpeedOfFruit;
    private int initialStartingNumberOfFruits;
    private float comboCounter = 1f;
    private int score = 0;
    private int livesRemaining;
    private int highestScore = 0; // Track the highest score

    const string EVENT_ID_FRUIT_CUT_GAME = "FruitCutGameStart";
    const string EVENT_ID_FRUIT_CUT_GAME_END = "FruitCutGameEnd";
    const string EVENT_ID_ATTACH_FRUITSCRIPT = "AttachFruitScript";
    public Collider KnifeCollider;

    EventToken GameToken;
    EventToken GameTokenEnd;
    EventToken AttachFruitScript_Token;

    void Start()
    {
        StartButton.OnPlayerClick.AddListener(OnStartButtonClick);
        EndButton.OnPlayerClick.AddListener(OnEndButtonClick);

        GameToken = this.AddEventHandler(EVENT_ID_FRUIT_CUT_GAME, OnNetworkFruitCutGameStart);
        GameTokenEnd = this.AddEventHandler(EVENT_ID_FRUIT_CUT_GAME_END, OnNetworkFruitCutGameEnd);
        AttachFruitScript_Token = this.AddEventHandler(EVENT_ID_ATTACH_FRUITSCRIPT, OnNetworkFruitCreated);

        WaveNumberText.text = "Wave: 0";
        CountDownText.gameObject.SetActive(false);

        initialSpeedOfFruit = averageSpeedOfFruit;
        initialStartingNumberOfFruits = startingNumberOfFruits;

        ResetLives();
        UpdateHighestScoreUI(); // Initialize the highest score display
    }

    void Update()
    {
        // Move the spawn point back and forth between the start and end positions
        MoveSpawnPoint();
    }

    void MoveSpawnPoint()
    {
        if (isGameRunning)
        {
            // Interpolate between start and end points using PingPong to create a smooth back-and-forth movement
            float t = Mathf.PingPong(Time.time * spawnPointMovementSpeed, 1f);
            spawnPoint.position = Vector3.Lerp(spawnPointStart.position, spawnPointEnd.position, t);
        }
    }

    void OnStartButtonClick(MLPlayer player)
    {
        this.InvokeNetwork(EVENT_ID_FRUIT_CUT_GAME, EventTarget.All, null);
    }

    void OnEndButtonClick(MLPlayer player)
    {
        this.InvokeNetwork(EVENT_ID_FRUIT_CUT_GAME_END, EventTarget.All, null);
    }

    void OnNetworkFruitCutGameStart(object[] args)
    {
        if (!isGameRunning)
        {
            isGameRunning = true;
            StartCoroutine(StartGame());
        }
    }

    void OnNetworkFruitCutGameEnd(object[] args)
    {
        EndGame();
    }

    IEnumerator StartGame()
    {
        ResetCombo();
        ResetScore();
        ResetLives();

        while (isGameRunning)
        {
            yield return StartCoroutine(CountdownBeforeWave());
            yield return StartCoroutine(SpawnFruits());

            currentWave++;
            fruitsPerWave = initialStartingNumberOfFruits + currentWave;
            averageSpeedOfFruit += 0.5f;

            WaveNumberText.text = "Wave: " + currentWave.ToString();
            yield return new WaitForSeconds(2f);
        }
    }

    IEnumerator CountdownBeforeWave()
    {
        EnableDisableTextCounter.SetActive(true);
        CountDownText.gameObject.SetActive(true);

        int countdown = 3;
        while (countdown > 0)
        {
            CountDownText.text = countdown.ToString();
            yield return new WaitForSeconds(1f);
            countdown--;
        }

        CountDownText.text = "Go!";
        yield return new WaitForSeconds(1f);

        CountDownText.gameObject.SetActive(false);
        EnableDisableTextCounter.SetActive(false);
    }

    IEnumerator SpawnFruits()
    {
      //  if (MassiveLoopClient.IsMasterClient)
      //  {
            for (int i = 0; i < fruitsPerWave; i++)
            {
                SpawnFruit();
                yield return new WaitForSeconds(Random.Range(0.5f, 1.5f));
            }
      //  }
    }

    void SpawnFruit()
    {
        GameObject fruitPrefab = fruits[Random.Range(0, fruits.Length)];
        GameObject fruit = Instantiate(fruitPrefab, spawnPoint.position, Quaternion.identity);

        Rigidbody rb = fruit.GetComponent<Rigidbody>();

        // Calculate direction towards the target
        Vector3 directionToTarget = (fruitTargetPoint.position - fruit.transform.position).normalized;

        // Adjust random force with a greater emphasis on the upward component for a bigger arc
        Vector3 randomForce = new Vector3(
            Random.Range(-1f, 1f),     // Reduce randomness for better control
            Random.Range(20f, 26f),     // Stronger upward force for a higher arc
            Random.Range(-1f, 1f)
        ) * averageSpeedOfFruit;

        // Blend the random force with the target-directed force, but give more weight to the target direction
        Vector3 arcForce = Vector3.Lerp(randomForce, directionToTarget * averageSpeedOfFruit * 2f, 0.7f); // Increased blend factor to 0.7 for more target influence

        // Apply the force to the fruit
        rb.AddForce(arcForce, ForceMode.Impulse);

        // Attach fruit script
        this.InvokeNetwork(EVENT_ID_ATTACH_FRUITSCRIPT, EventTarget.All, null, new object[] { fruit.GetInstanceID() });
       // AttachFruitScript(fruit);
    }


    void AttachFruitScript(GameObject fruit)
    {

        Fruit fruitScript = (Fruit)fruit.AddComponent(typeof(Fruit));
        fruitScript.gameManager = this;
        Debug.Log("Fruit Script attached");
    }

    void OnNetworkFruitCreated(object[] args)
    {
        int fruitInstanceID = (int)args[0];
        GameObject fruit = FindObjectByID(fruitInstanceID);
        Debug.Log("Fruitobject ID found : " + fruitInstanceID);
        if (fruit != null)
        {
            Debug.Log("Fruit object was not null, attempting to attach the fruit script.");
            AttachFruitScript(fruit);
        }
    }

    GameObject FindObjectByID(int instanceID)
    {
        GameObject[] allObjects = GameObject.FindObjectsOfType<GameObject>();
        foreach (GameObject obj in allObjects)
        {
            if (obj.GetInstanceID() == instanceID)
                return obj;
        }
        return null;
    }

    public void OnFruitDropped()
    {
        if (MassiveLoopClient.IsMasterClient)
        {
            fruitDrops++;
            livesRemaining--;
            UpdateLivesUI();

            if (livesRemaining <= 0)
            {
                this.InvokeNetwork(EVENT_ID_FRUIT_CUT_GAME_END, EventTarget.All, null);
            }
            else
            {
                ResetCombo();
            }
        }
    }

    public void OnFruitHit()
    {
        Debug.Log("Fruit hit");
        comboCounter += 0.1f;
        int pointsToAdd = Mathf.RoundToInt(10 * comboCounter); // Example score increment
        score += pointsToAdd;
        UpdateScoreUI();
        UpdateComboCounterUI();
        CheckAndSetHighestScore(); // Check if the new score is a high score
    }




    void EndGame()
    {
        isGameRunning = false;
        StopAllCoroutines();
        ResetGameVariables();
    }

    void ResetGameVariables()
    {
        currentWave = 1;
        averageSpeedOfFruit = initialSpeedOfFruit;
        startingNumberOfFruits = initialStartingNumberOfFruits;
        fruitsPerWave = startingNumberOfFruits;
        fruitDrops = 0;

        WaveNumberText.text = "Wave: 0";
        ResetCombo();
        ResetLives();
        ResetScore();
    }

    void ResetCombo()
    {
        comboCounter = 1f;
        UpdateComboCounterUI();
    }

    void ResetScore()
    {
        score = 0;
        UpdateScoreUI();
    }

    void ResetLives()
    {
        livesRemaining = Lives.Length;
        foreach (GameObject life in Lives)
        {
            life.SetActive(true);
        }
    }

    void UpdateLivesUI()
    {
        for (int i = 0; i < Lives.Length; i++)
        {
            Lives[i].SetActive(i < livesRemaining);
        }
    }

    void UpdateScoreUI()
    {
        ScoreText.text = "Score: " + score.ToString();
    }

    void UpdateComboCounterUI()
    {
        ComboCounterText.text = "Combo: x" + comboCounter.ToString("F1");
    }

    void CheckAndSetHighestScore()
    {
        if (score > highestScore)
        {
            highestScore = score;
            UpdateHighestScoreUI();
        }
    }

    void UpdateHighestScoreUI()
    {
        HighestScore.text = "Highest Score: " + highestScore.ToString();
    }

    public void HealPlayer()
    {
        if (livesRemaining < Lives.Length)
        {
            livesRemaining++;
            UpdateLivesUI();
            Debug.Log("Player healed! Lives remaining: " + livesRemaining);
        }
        else
        {
            Debug.Log("Player already at maximum lives!");
        }
    }


}
public class Fruit : MonoBehaviour
{
    public FruitSlicerGameManager gameManager;

    // The offset to separate the two halves when they are spawned
    public float splitOffset = 0.2f;

    // Range for random spin
    public float minSpin = 75f;
    public float maxSpin = 300f;
    void Start()
    {
        Debug.Log("Testing fruit ninja food script");
    }

    void OnTriggerEnter(Collider other)
    {
        // Debugging to check what object triggered the collision
        // Debug.Log("Collided with: " + other.gameObject.name);

        if (other == gameManager.failZone)
        {
            Debug.Log("Fruit dropped!");
            gameManager.OnFruitDropped();
            Object.Instantiate(gameManager.collisionParticleEffect, gameObject.transform.position, Quaternion.identity);
            Destroy(gameObject);
        }
        else if (other.gameObject.name.Contains("ChoppingKnife"))
        {
            Object.Instantiate(gameManager.sliceParticleEffect, gameObject.transform.position, Quaternion.identity);

            // Get the FoodCut component from the current fruit
            FoodCut foodCutScript = (FoodCut)GetComponent(typeof(FoodCut));

            if (foodCutScript != null && foodCutScript.FoodObject_Chop != null)
            {
                // Calculate two positions for the two halves
                Vector3 leftHalfPosition = gameObject.transform.position + gameObject.transform.right * -splitOffset;
                Vector3 rightHalfPosition = gameObject.transform.position + gameObject.transform.right * splitOffset;

                // Spawn the chopped halves at the calculated positions
                GameObject leftHalf = Object.Instantiate(foodCutScript.FoodObject_Chop, leftHalfPosition, gameObject.transform.rotation);
                GameObject rightHalf = Object.Instantiate(foodCutScript.FoodObject_Chop, rightHalfPosition, gameObject.transform.rotation);

                // Add random spin to both halves
                AddRandomSpin(leftHalf);
                AddRandomSpin(rightHalf);

                Debug.Log("Chopped food spawned from FoodCut script with random spin!");
            }
            else
            {
                Debug.LogWarning("FoodCut script or FoodObject_Chop is missing!");
            }

            if (gameObject.name.Contains("Strawberry"))
            {
                Debug.Log("Strawberry Hit - Healing Player");
                gameManager.HealPlayer();  // Call the healing function when a strawberry is hit
            }

            gameManager.OnFruitHit();  // Regular hit for all fruits

            // Optionally destroy the original fruit after it has been hit
            Destroy(gameObject);
        }
    }

    // Adds a random spin (torque) to the sliced halves
    void AddRandomSpin(GameObject fruitHalf)
    {
        Rigidbody rb = fruitHalf.GetComponent<Rigidbody>();
        if (rb != null)
        {
            // Generate random spin around each axis
            Vector3 randomSpin = new Vector3(
                Random.Range(minSpin, maxSpin),
                Random.Range(minSpin, maxSpin),
                Random.Range(minSpin, maxSpin)
            );

            // Apply the random torque (spin)
            rb.AddTorque(randomSpin);
        }
    }
}