Unity3d QuickTip – czyli szybkie porady, rozwiązania częstych problemów i sztuczki w Unity3d!

Dzisiejszy odcinek: Jak zrobić zbieranie przedmiotów?

Uwaga! Jest to poradnik typu QuickTip. Zatem skupia się on na osiągnięciu założonego celu. Zatem zakładamy że użytkownik zna na tyle program Unity3d, aby samodzielnie wykonać najprostsze czynności, jak np. dodanie modelu kostki do sceny czy dodanie modelowi jakiegoś komponentu. Jeżeli brakuje Ci tej podstawowej wiedzy, zapraszam do tutoriala:
Unity Tutorial – Podstawy

Teoria

Teoria jest bardzo prosta. W każdej grze, czy to platformowej, czy RPG czy w dowolnym innym gatunku, trafiamy na coś takiego jak zbieranie przedmiotów. Może się to sprowadzać do kolekcjonowania znajdziek w RPG, monet w platformówce, czy np. boostów na trasie wyścigu. Nie omówimy tutaj tworzenia ekwipunku do gry cRPG, bo to bardziej złożona i skomplikowana kwestia.

Wykonanie

Pierwsze co nam potrzeba, to nasza postać i jakiś obiekt do zbierania. Dlatego na scenie ustawiam:

  • First Person Controller z pakietu Character Controller
  • Obiekt Sphere, który sobie pomniejszyłem i dodałem teksturę żółtego koloru by upodobnić ją do monety.

Przygotowanie monety

Najpierw należy monecie dodać Collider (który powinien być domyślnie dodany dla obiektu Sphere) i ustawić mu parametr isTrigger. Następnie możemy go powiększyć, tak aby postać którą sterujemy mogła łatwiej na niego wejść.
[stextbox id=”info” defcaption=”true”]Jest to powszechnie stosowany trik w grach. Obiekty “pozytywne” dla gracza, mają collider znacznie większy od samych siebie. Tak żeby było nam łatwo złapać się drabinki, zebrać amunicję itp. Gdybyśmy musieli 30 razy przebiegać po amunicji, żeby trafić sobie w mały collider mogłoby być irytujące. Natomiast collidery dla rzeczy “negatywnych” są mniejsze. Dlatego w platformówkach typu Bride, faktyczny collider wrogów, jest nieco mniejszy od nich samych, aby dać graczowi ten dodatkowy ułamek sekundy na reakcję.[/stextbox]
Ostatecznie, nasz moneta powinna wyglądać tak:

Wygląd Collidera Monety
Wygląd Collidera Monety

Teraz tworzymy i dodajemy naszej monecie nowy skrypt. Ja stworzyłem skrypt Coin.cs i dodałem go do monety przeciągając skrypt na monetę w panelu hierachy. Nasz skrypt jest bardzo prosty i jeśli wykonywałeś wcześniej Unity3d QuickTip #1, o wyświetlaniu podpowiedzi, prawdopodobnie domyślasz się jak będzie wyglądał:

using UnityEngine;
using System.Collections;

public class Coin : MonoBehaviour 
{

    void OnTriggerEnter(Collider other) 
    {
        if(other.tag == "Player") {
            other.SendMessage("collectCoin");
            Destroy(gameObject); 
        }
    }
}

Oczywiście OnTriggerEnter wykona się gdy znajdziemy się w zasięgu collidera monety. Następnie sprawdzamy czy obiekt, który wszedł w interakcję to obiekt gracza (o tym później). Other.SendMessage, nakazuje obiektowi, który wszedł w interakcję z monetą wykonać jego funkcję collectCoin. Destroy(gameObject) usuwa ze sceny obiekt. gameObject jest odwołaniem się do samego siebie, więc w tym przypadku, usuniemy samą monetę.

Postać

Z naszą postacią będzie prościej, ponieważ do obiektu gracza stworzymy przypiszemy sobie tylko jeden skrypt. Ja stworzyłem plik CollectCoins.cs i przypisałem go do mojego First Person Controllera.

Nasz skrypt i tym razem wygląda banalnie:

using UnityEngine;
using System.Collections;

public class CollectCoins : MonoBehaviour {

	public static int coins = 0;

	void collectCoin() {
		coins++;
	}
}

Mamy tylko publiczną, statyczną zmienną z liczbą zebranych monet – nie jest to rozwiązanie optymalne, ale dla przykładu wystarczające – na starcie ustawiamy ich liczbę na 0. Dodatkowo mamy funkcję collectCoin, która jest wywoływana przez skrypt monety, a jej zadaniem jest zwiększenie zmiennej trzymającej liczbę monet o 1.

Kolejną rzeczą jest ustawienie jej tagu. Aby ustawić tag, zaznaczamy wybrany obiekt, u samej góry w panelu Inspektor, będziemy mieli widoczny dropdown zatytułowany tag, który powinien wskazywać na untagged. Klikamy na niego i wybieramy z listy “Add Tag” Znajdujące się u samego dołu. Panel inspektor zmieni się ukazując menu, dostępne z poziomu: [Edit -> Project Settings -> Tags & Layers]. Rozszerzamy panel Tags, klikając w niego,  i wpisujemy w pole Element0 wartość Player. Powinno wyglądać to tak:

QuickTip_06_01
Panel Tags & Layers

Teraz wracamy do obiektu gracza, klikając na niego, a następnie rozwijamy znów listę tagów i wybieramy nasz nowo utworzony Player.

Jak to wykorzystać?

W grze platformowej, czasami jest tak, że wymaga się zebrania pewnej liczby monet by otworzyć jakieś drzwi.

Dodajmy sobie do sceny kopię jeszcze 2 naszych monet, oraz dodatkowy cube, który nazwiemy door. Jego collider, jak w przypadku monet, ustawmy na IsTrigger, oraz powiększmy go trochę. U mnie wygląda on następująco:

QuickTip_06_03
Wygląd komponentów transform i collider dla drzwi

Stworzymy i dodamy naszym drzwiom również skrypt. U mnie nazywa się Door.cs.

using UnityEngine;
using System.Collections;

public class Door : MonoBehaviour {

	void OnTriggerEnter(Collider other) 
	{
		if(other.tag == "Player") {
			if(CollectCoins.coins == 3) {
				Destroy(gameObject); 
			}
		}
	}
}

I ten skrypt również jest prosty. Wykrywamy wejście w Collider, sprawdzamy czy obiekt z którym się zderzyliśmy ma tag Player, jeśli tak, sprawdzamy czy zmienna coins  w skrypcie CollectCoins jest równa 3. Jest to możliwe, ponieważ zmienna coins jest zmienną publiczną i statyczną. Jeśli jest równa 3, co oznacza, że gracz zebrał 3 monety, niszczy nasz obiekt drzwi, symulując ich otwarcie.

13 thoughts

  1. Wszystko fajnie, tylko że jeśli np zginiesz to u mnie w restarcie mam że restartuje level ale wartości w skrypcie zdobytych monet zostają, dlatego później gdy zdobędziesz monet za dużo to drzwi się w żaden sposób nie otworzą, jak temu zapobiec?

    1. Jeżeli restartujesz cały level przez LoadLevel, to wszystkie skrypty powinny zostać utworzone od nowa. Ale… Ogólnie można to rozwiązać na kilka sposobów:
      – Przy przegranej gracza, wyzeruj sobie zmienną
      – Przy starcie sceny ustaw liczbę punktów na 0. Czyli zeruj licznik monet w funkcji Start albo Awake. (Zadziała, jeśli poziom jest przeładowywany w całości)

  2. Samo zbieranie monety działa w moim przypadku, lecz jak dodam na scenie więcej niż jedną monetę to nieważne, która zostanie zebrana reszta automatycznie się usuwa. Przykładowo: mam prefabrykant monety, rozstawiam sobie monety na scenie, każda nazywa się moneta (x), gdzie x jest numerem skopiowanej monety i gdy dochodzi do uruchomienia skryptu ( gdy postać wejdzie na collider ) usuwana jest ta moneta, którą gracz zbiera i wszystkie inne rozmieszczone na scenie. Nie wiem, czy nie jest to być może spowodowane kopiowaniem prefabrykantu i linijką Destroy(GameObject); Jak mogę rozwiązać ten problem?

    1. Jeżeli podałeś GameObject, zamiast gameObject, może tak być. Ponieważ gameObject (z małej) odnosi się do obiektu w którym jest skrypt. A GameObject (z dużej) to ogólnie klasa.

    2. Sprawdziłem to i jednak mam wspisane Destroy(gameObject); po prostu źle wpisałem u góry, ale pomimo dobrej wielkości litery nadal to nie działa. W tej samej sekundzie przy zebraniu jednej monety znikają wszystkie. Mogę dołączyć jakieś screeny lub skrypt, chociaż nie wiem czy coś to da, ponieważ skrypt jest ten sam co napisał Pan wyżej. Może jakieś inne pomysły?

  3. A jak zrobić aby podnosiło się klawiszem?
    Nie chcę mieć zbierania przedmiotów podczas wchodzenia na nie, z powodu że gracz może chcieć tylko po nich przejść bo taka droga jest krótsza :)
    Zapewne będzie if input ale nie wiem jak sprawdzić czy wciśnięto klawisz na colliderze “miecz” czy byle gdzie na ziemi

    1. W prostym wariancie możesz zostawić Collider. Gdy gracz w niego wejdzie, wyświetlasz mu informację jaki przycisk ma nacisnąć żeby podnieść obiekt. Jeśli naciśnie przycisk, to wtedy go podnosisz. Coś takiego:

      void OnTriggerEnter(Collider other)
      {
      if(other.tag == “Player”) {
      // Tutaj wświetlasz informację

      if(Input.GetButtonDown(“JakisButton”)) {
      // Zbierasz przedmiot
      }
      }
      }
      Wada jest taka, że informacja wyświetli się, nawet gdy gracz nie patrzy na przedmiot. Aby osiągnąć taki wariant musisz się pobawić z RayCastem.

    2. Czyli prosta opcja zbierania na “Metin2” wszystko co jest wokół nieważne czy za mną czy przede mną :)
      Przyda się takowa informacja

    3. Przyda się funkcja:
      Camera.main.ScreenPointToRay (Input.mousePosition);
      Dzięki temu otrzymasz obiekt typu Ray, wystrzelony z pozycji myszki. Potem zostaje sprawdzić czy promień na coś trafił.

      Raycasting omówiłem w tutorialu dotyczącym strzelania, więc możesz się na nim wzorować.

  4. Hookup Women Uses Totally free Matters? An Incredible Side to side Gain!

    Free hookup women chat on the internet is the perfect solution if you’re tired of gonna cafes and organizations simply to be prevented, or even a whole lot worse, laughed at.
    I am aware what it’s like because I’ve been there. I had been individual and desperate in the day — I required a fresh partner — but
    I continued attempting because I needed no other decision. If you’re just one man who wishes to hookup with alluring girls without planning to those places where the women are
    alone, this report may just alter your lifestyle.
    It will explain why internet dating on the web is the ideal alternative if you’re
    a masculine who is shy to approach a beautiful lady inside
    a club or club.

Leave a Reply

Your email address will not be published. Required fields are marked *