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