Fruit Ninja

Gra polega na cięciu owoców pojawiających się na ekranie poprzez szybkie przeciągnięcia palcem lub myszą. Owoce są wyrzucane w powietrze, a zadaniem gracza jest ich pokrojenie. Punkty są naliczane za każde udane cięcie. Gracz musi unikać bomb, których przecięcie kończy grę, oraz dbać o to, by owoce nie spadły z ekranu bez pokrojenia.

Written By Coder Matthew

Last updated 6 months ago


1) Grafiki użyte w Fruit Ninja

W samym grze nie ma za dużo grafik, gra bazuje na gotowych obiekt a dokładniej ich prefabach oraz na zmianie ich modelów.

Prefabs:

Zdjęcie przedstawia prefaby obiektów
  • 1. Apple, Kiwi, Lemon, Orange, Watermelon

    • Prefaby reprezentujące różne typy owoców.

    • Każdy z nich ma przypięty skrypt Fruit (definiujący punkty i logikę cięcia), a także używa modeli Fruit_Whole i Fruit_Sliced oraz unikalnych Materiałów nadających im kolor i wygląd. Są losowane i wyrzucane przez Spawner.

  • 2. Bomb

    • Prefab reprezentujący niebezpieczną przeszkodę.

    • Ma przypięty skrypt Bomb, który wywołuje funkcję GameManager.Explode() po kontakcie z ostrzem gracza. Jest generowany losowo z małym prawdopodobieństwem (bombChance).

  • 3. Fruit_Base

    • Model bazowy (prefab) dla owoców.

    • Jest to baza, z której dziedziczą pozostałe owoce. Może służyć do szybkiego tworzenia nowych typów owoców.


Materials:

Zdjęcie przedstwawi stworzone gotowe materiały
  • 1. Materiały Fruit_Inside np. Watermelon_Inside

    • Zasoby określające kolor i teksturę wewnętrzną dla każdego owocu.

    • Materiały te są aplikowane do geometrycznych modeli Fruit_Sliced w celu nadania im wizualnej tożsamości (np. Watermelonpo przecięciu będzie miał widoczny w środku czerwony miąższ).

  • 2. Materiały Fruit_Outside np. Watermelon_Outside

    • Zasoby określające kolor i teksturę zewnętrzną dla każdego owocu.

    • Materiały te są aplikowane do geometrycznych modeli Fruit_Whole i Fruit_Sliced w celu nadania im wizualnej tożsamości (np. czerwony kolor dla Apple, zielony dla Watermelon).

  • 3. Materiał Bomb

    • Zasób określający wygląd wizualny bomby.

    • Nadaje bombie czarny kolor i teksturę, aby wizualnie odróżnić ją od owoców.


      Models:

      Dwa modele jakie są użyte
  • 1. Fruit_Sliced

    • Model 3D reprezentujący pokrojony (dwuczęściowy) owoc.

    • Służy jako geometryczny wzorzec dla wszystkich pokrojonych połówek owoców (np. Apple, Kiwi, Lemon). Jest aktywowany (widoczny) przez skrypt Fruit w momencie udanego cięcia.

  • 2. Fruit_Whole

    • Model 3D reprezentujący cały, niepokrojony owoc.

    • Służy jako geometryczny wzorzec dla wszystkich całych owoców. Jest widoczny na scenie w momencie wyrzutu i dezaktywowany przez skrypt Fruit po cięciu.


Graphics:

Jedyna pełnoprawna grafika w grze
  • 1. Wood

    • Tekstura imitująca drewnianą powierzchnię.

    • Jest używana jako tekstura tła sceny.


2) Hierarchia w Unity

  • 1. Game Manager

    • Reprezentuje fizyczny obiekt kontrolujący globalny stan gry, jej parametry i interfejs. Utrzymuje wzorzec Singleton (GameManager.Instance), umożliwiając wszystkim innym skryptom łatwy dostęp do centralnej logiki gry.

    • Jest to obiekt, do którego przypięty jest skrypt GameManager. Kontroluje stan gry (np. NewGame(), Explode()), punkty oraz zarządza sekwencjami wizualnymi (np. zaciemnianie ekranu).

  • 2. Main Camera

    • Odpowiada za perspektywę gracza, definiując obszar, który jest widoczny na ekranie. Ustawia pole widzenia i sposób renderowania sceny.

    • Skrypt Blade wykorzystuje kamerę do konwersji pozycji kursora myszy na współrzędne w świecie gry, umożliwiając precyzyjne cięcie.

  • 3. Directional Light

    • Źródło światła, które symuluje światło słoneczne (światło padające z jednego kierunku). Oświetla całą scenę, rzucając cienie i nadając owocom oraz bombom realistyczny wygląd 3D.

    • Jest kluczowe dla wizualizacji grafiki 3D (Modele i Prefaby), dodając głębi i realizmu modelom owoców i ich kawałkom.

  • 4. Background

    • Obiekt wizualny, który stanowi tło dla akcji. Jest to prosta płaszczyzna z teksturą drewna(Wood), która zakrywa przestrzeń za owocami.

    • Zapewnia kontekst wizualny dla sceny. Owoce są wyrzucane z tego obszaru i latają przed nim.

  • 5. Spawner

    • Reprezentuje obszar i logikę generowania owoców i bomb. Jest to obiekt, do którego przypięty jest skrypt Spawner, zarządzający losowaniem obiektów i ich wyrzutem.

    • Obiekt ten posiada komponent Collider, który jest używany przez skrypt do zdefiniowania granic strefy wyrzutu (spawnArea), zapewniając, że obiekty pojawiają się w losowej pozycji wzdłuż tej strefy.

  • 6. Blade

    • Reprezentuje wirtualne ostrze gracza, które jest śledzone przez mysz. Jest to obiekt z komponentem Collider, który fizycznie wykrywa kolizje z owocami i bombami.

    • Do tego obiektu przypięty jest skrypt Blade. Śledzi on ruch kursora i aktywuje kolider oraz ślad cięcia (Trail) tylko wtedy, gdy prędkość pociągnięcia jest wystarczająco duża.

  • 7. Trail (wewnątrz Blade)

    • Wizualny element, który tworzy ślad (ogon) za ruchem ostrza.

    • Jest to komponent TrailRenderer, który jest aktywowany i czyszczony przez skrypt Blade w momencie rozpoczęcia i zakończenia cięcia, dając wizualny efekt ruchu ostrza.

  • 8. Canvas (Kontener UI)

    • Jest kontenerem nadrzędnym dla wszystkich elementów interfejsu użytkownika (UI). Zarządza skalowaniem i rozmieszczeniem elementów UI na ekranie.

    • Wymagany przez Unity, aby hostować obiekty 2D, takie jak tekst i obrazy, które muszą pozostać na stałym miejscu na ekranie.

  • 9. Score Text (wewnątrz Canvas)

    • Element tekstowy, który wyświetla aktualną liczbę punktów gracza.

    • Skrypt GameManager odwołuje się do niego (scoreText) i aktualizuje jego zawartość w metodzie IncreaseScore().

  • 10. Fade Image (wewnątrz Canvas)

    • Element typu Obraz (Image), który służy do tworzenia efektu zaciemnienia/rozjaśnienia ekranu.

    • Jest używany przez kurtynę ExplodeSequence() w skrypcie GameManager do płynnego przejścia (fade-out do białego i fade-in z powrotem) po eksplozji bomby.


3) Skrypty użyte w Fruit Ninja

Tak właśnie wyglądają gotowe skrypty w unity
  • 1. GameManager

    • Centralna jednostka kontrolna całej gry, zarządzająca stanem, punktacją i efektem końcowym.

    • Utrzymuje wzorzec Singleton (GameManager.Instance) i przechowuje aktualny wynik.

    • Kontroluje sekwencje stanu gry: NewGame() (czyszczenie sceny, reset wyniku) i Explode() (zatrzymanie gry, wysyłka wyniku, uruchomienie sekwencji wizualnej ExplodeSequence()).

    • Odpowiada za wyświetlanie wyniku oraz zapisywanie najlepszego rekordu (High Score) za pomocą PlayerPrefs.

  • 2. Blade

    • Skrypt odpowiedzialny za reprezentowanie i śledzenie wirtualnego ostrza gracza na scenie. Zarządza logiką Start/Stop/Continue cięcia, aktywując kolider i wizualny ślad (TrailRenderer).

    • Przekształca pozycję kursora na pozycję w świecie gry, jednocześnie obliczając kierunek i prędkość cięcia.

    • Aktywuje kolider tylko wtedy, gdy prędkość ruchu jest wystarczająca, aby uniknąć przypadkowych kolizji (filtr minSliceVelocity).

  • 3. Fruit

    • Skrypt zarządzający logiką pojedynczego owocu, w tym jego pokrojeniem i punktacją. Odpowiada za wizualną transformację obiektu z całego na pokrojony oraz za nadanie fizycznego impulsu rozrzuconym kawałkom.

    • Wykrywa kolizję z ostrzem i w odpowiedzi wywołuje metodę Slice(), która: zwiększa wynik w GameManager, dezaktywuje cały model, aktywuje model pokrojony (z efektem soku) i rozrzuca jego fragmenty.

  • 4. Bomb

    • Skrypt definiujący niebezpieczną przeszkodę, której przecięcie kończy grę.

    • Służy wyłącznie do wykrywania kolizji z ostrzem gracza.

    • W momencie kolizji z ostrzem (oznaczonym tagiem "Player"), natychmiast wywołuje metodę GameManager.Explode(), co uruchamia sekwencję zakończenia gry.

  • 5. Spawner

    • Skrypt odpowiedzialny za losowe i cykliczne wyrzucanie owoców i bomb w powietrze.

    • Określa strefę generowania (spawnArea), w której losowo dobiera pozycję, a następnie nadaje obiektowi losową siłę i kąt wyrzutu (AddForce), inicjując fizykę jego lotu.

    • Odpowiada za losowanie, czy ma zostać wyrzucony owoc, czy bomba, na podstawie ustalonego prawdopodobieństwa (bombChance).


4) Całe skrypty

Tutaj znajdziesz całe skrypty bez owijania w bawełne 😊, każdy blok kodu jest starannie zakomentowany tak żebyś w miarę mógł ogarnąć o co chodzi nawet jak nie znasz unity i C#.

Example
using System.Collections; using UnityEngine; using UnityEngine.UI; using UnityEngine.Networking; [DefaultExecutionOrder(-1)] public class GameManager : MonoBehaviour { // --- Singleton i Odniesienia --- public static GameManager Instance { get; private set; } [SerializeField] private Blade blade; // Odniesienie do skryptu ostrza. [SerializeField] private Spawner spawner; // Odniesienie do generatora obiektów. [SerializeField] private Text scoreText; // Pole tekstowe do wyświetlania wyniku. [SerializeField] private Image fadeImage; // Obraz UI do efektu zaciemnienia/rozjaśnienia. public int score { get; private set; } = 0; // Aktualny wynik. // --- Inicjalizacja Singletonu --- private void Awake() { // [BLOK KOMENTARZY: Zarządzanie Instancją] // Zapewnienie, że istnieje tylko jeden GameManager (Singleton). if (Instance != null) { DestroyImmediate(gameObject); } else { Instance = this; } } private void OnDestroy() { if (Instance == this) { Instance = null; } } private void Start() { // Rozpoczęcie nowej gry natychmiast po załadowaniu sceny. NewGame(); } // --- Kontrola Stanu Gry: Nowa Gra --- private void NewGame() { // [BLOK KOMENTARZY: Resetowanie Gry] // 1. Ustawia skalę czasu na 1 (normalna prędkość). Time.timeScale = 1f; // 2. Czyści scenę ze wszystkich pozostałych owoców i bomb. ClearScene(); // 3. Aktywuje ostrze i generator. blade.enabled = true; spawner.enabled = true; // 4. Resetuje wynik i aktualizuje tekst UI. score = 0; scoreText.text = score.ToString(); } private void ClearScene() { // [BLOK KOMENTARZY: Czyszczenie Sceny] // Wyszukuje wszystkie obiekty (owoce i bomby) i je niszczy. Fruit[] fruits = FindObjectsOfType<Fruit>(); foreach (Fruit fruit in fruits) { Destroy(fruit.gameObject); } Bomb[] bombs = FindObjectsOfType<Bomb>(); foreach (Bomb bomb in bombs) { Destroy(bomb.gameObject); } } // --- Logika Punktacji --- public void IncreaseScore(int points) { // [BLOK KOMENTARZY: Aktualizacja Wyniku i Rekordu] // 1. Zwiększa wynik i aktualizuje tekst na ekranie. score += points; scoreText.text = score.ToString(); // 2. Sprawdza, czy obecny wynik jest nowym rekordem (High Score), // i jeśli tak, zapisuje go za pomocą PlayerPrefs. float hiscore = PlayerPrefs.GetFloat("hiscore", 0); if (score > hiscore) { hiscore = score; PlayerPrefs.SetFloat("hiscore", hiscore); } } // --- Koniec Gry: Eksplozja --- public void Explode() { // [BLOK KOMENTARZY: Zatrzymanie Gry po Eksplozji] // Wyłącza ostrze i generator (koniec interakcji i spawnowania). blade.enabled = false; spawner.enabled = false; // Rozpoczyna wysyłanie wyniku do zewnętrznego serwera. StartCoroutine( SendScore( 18, // id gry score // wynik ) ); // Rozpoczyna sekwencję wizualną Eksplozji (fade-out). StartCoroutine(ExplodeSequence()); } private IEnumerator ExplodeSequence() { float elapsed = 0f; float duration = 0.5f; // [BLOK KOMENTARZY: Efekt Wizualny Eksplozji (Fade-out)] // Stopniowe zmienianie koloru obiektu 'fadeImage' z przezroczystego na biały. while (elapsed < duration) { float t = Mathf.Clamp01(elapsed / duration); fadeImage.color = Color.Lerp(Color.clear, Color.white, t); // Stopniowe spowalnianie gry (spowalnianie czasu) do zera. Time.timeScale = 1f - t; elapsed += Time.unscaledDeltaTime; yield return null; } // Krótka pauza. yield return new WaitForSecondsRealtime(1f); // Rozpoczęcie nowej gry. NewGame(); elapsed = 0f; // [BLOK KOMENTARZY: Efekt Wizualny Powrotu (Fade-in)] // Stopniowe zmienianie koloru 'fadeImage' z powrotem na przezroczysty. while (elapsed < duration) { float t = Mathf.Clamp01(elapsed / duration); fadeImage.color = Color.Lerp(Color.white, Color.clear, t); elapsed += Time.unscaledDeltaTime; yield return null; } } // --- Komunikacja Sieciowa (Wysyłanie Wyniku) --- // [BLOK KOMENTARZY: Procedura HTTP] // Korutyna wysyłająca wynik do serwisu internetowego, używając stałego ID gry // i tokenu zabezpieczającego opartego na bieżącej minucie. public IEnumerator SendScore(int gameId, int score) { string url = "https://bit.elita.fun/execs/api/set_score.php?game_id=" + gameId + "&score=" + score; WWWForm f = new WWWForm(); f.AddField("pass", System.DateTime.Now.ToString("mm") + "EcS9YcvMtWNnW0N8yi1mVK"); using (UnityWebRequest r = UnityWebRequest.Post(url, f)) { yield return r.SendWebRequest(); Debug.Log(r.result == UnityWebRequest.Result.Success ? r.downloadHandler.text : "ERR: " + r.error); } } }