Marek Winiarski

Unity3d QuickTip #44 – Zaznaczanie obiektów myszką

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

Dzisiejszy odcinek: Zaznaczanie obiektów myszką

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

Sprawa w sumie dość prosta. W każdej strategii mamy jakieś swoje jednostki. Żeby wydać im rozkaz, trzeba je zaznaczyć. W momencie zaznaczania obiektu, fajnie gdyby sam obiekt, został w jakiś sposób oznaczony. Najczęściej jest to zielone kółko pod obiektem.

Klikanie w obiekt

Pierwsza sprawa jaką musimy ogarnąć, to napisać sobie kod odpowiedzialny za wykrycie czy, a jeśli tak, to w jaki obiekt kliknęliśmy myszą. Tworzymy sobie nowy skrypt, który ja nazwałem “CameraController.cs”. Skrypt dodajemy do obiektu kamery. W jego funkcji Update wstawiamy coś takiego:

if (Input.GetMouseButtonDown(0)){ 
	Ray ray = gameObject.GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
	RaycastHit hit;
	if (Physics.Raycast(ray, out hit)) {
		if (hit.transform.gameObject.tag == "Player") {
			Transform selected = hit.transform;
			gc.unselectAll ();
			selected.SendMessage ("selectPlayer");
		}
	}
}

Jeśli gracz naciśnie przycisk, to generujemy sobie promień z wykorzystaniem funkcji ScreenPointToRay, co to robi? Tworzy promień z miejsca, gdzie znajduje się kursor i przelicza go na punkt świata gry.

Mając taki promień rzucamy go sobie, a wynik zbieramy do zmienne hit.

Jeśli trafimy na obiekt oznaczony tagiem Player, to pobieramy go sobie, następnie odznaczamy inne obiekty (tym zaraz się zajmiemy), a na koniec wysyłamy do trafionego obiektu prośbę o wykonanie akcji “selectPlayer”.

No dobra, ale czym jest gc? Najpierw, tą zmienną musimy sobie zadeklarować w skrypcie, oraz przypisać jej wartość w funkcji Start.

private GameController gc;

void Start()
{
	gc = GameObject.Find ("GameController").GetComponent<GameController>();
}

Zmienna gc to GameController, czyli kolejny obiekt, który teraz przygotujemy.

Na początek tworzymy pusty GameObject (CTRL+SHIF+N) – Nazywamy go GameController. Jeśli wybierzemy inną nazwę, to musimy uwzględnić to w funkcji Find w skrypcie. Tworzymy teraz nowy skrypt GameController.cs i dodajemy do pustego GameObjectu. Teraz wchodzimy w edycję GameController.cs i przechodzimy do pisania kodu.

Na początek deklarujemy zmienną:

private GameObject[] mercenaries;

Wewnątrz tej tablicy, będziemy trzymać wszystkie jednostki, które można zaznaczyć.

Na starcie wypełniamy tablicę:

void Start () {
	mercenaries = GameObject.FindGameObjectsWithTag("Player");
}

Jak się można domyślić, funkcja FindGameObjectsWithTag znajduje wszystkie obiekty posiadające pewien tag.

Aby umożliwić jej działanie, możesz teraz przejść do Unity i utworzyć ze 2 obiekty i dać im tagi Player.

Ustawiamy tag Player
Ustawiamy tag Player

No dobra, ale w kodzie wołamy funkcję “unselectAll”. Wypadałoby ją napisać:

public void unselectAll()	{
	foreach (GameObject player in mercenaries) {
		player.GetComponent<PlayerController> ().unselectPlayer ();
	}
}

Sprawa bardzo prosta. Przelatujemy funkcją całą naszą tablicę postaci i na każdej wywołujemy unselectPlayer, odwołując się do komponentu PlayerController. Ten napiszemy teraz.

Tworzymy sobie nowy skrypt “PlayerController.cs”. Przypisujemy go do obiektów graczy (tych oznaczonych tagiem Player). Jeśli korzystamy z prefabów, wystarczy skrypt dodać do prefaba.

Przejdźmy do treści skryptu, na początek dwie zmienne:

private Transform playerSelection;
private bool isSelected;

Obie od razu ustawiamy:

void Start () {
	playerSelection = transform.Find ("PlayerSelection");
	isSelected = false;
}

Pierwsza z nich to pierścień, który będzie się pojawiał pod postacią po zaznaczeniu, a druga to tylko flaga, która informuje nas w skrypcie, że dana postać jest akurat zaznaczona. Teraz czas napisać funkcję unselectPlayer i selectPlayer, które wykorzystujemy wcześniej:

public void selectPlayer()
{
	isSelected = true;
	playerSelection.gameObject.SetActive (true);
}

public void unselectPlayer()
{
	isSelected = false;
	playerSelection.gameObject.SetActive (false);
}

Zestawiam je od razu razem, bo są tylko swoimi przeciwieństwami. Czyli wyłączają bądź włączają znacznik i flagę.

Może się tu pojawić pytanie, po co tyle tych klas i znajdowania ich? Znajdowanie ogarniamy wewnątrz funkcji Start, dzięki czemu za bardzo nie obciążamy procesora, bo robimy to raz na początku. W przypadku rozbicia: klasa przypisana do postaci, musi się martwić tylko stanem postaci i jest niezależna od innych. Dzięki czemu zawsze będzie ładnie działać, bo musi obsługiwać tylko siebie.

Klasa kontrolera gry, zbiera nam obiekty, dzięki czemu można na nich pracować zbiorowo. Mamy dynamiczny dostęp do każdego z nich. Gdybyśmy jej nie mieli, to odznaczanie wszystkich postaci, byłoby potwornie zasobożerne. Dodatkowo możemy w nim trzymać inne ogólne dane. Np. obecnie trwającą turę rozgrywki, czas gry etc.

CameraController odpowiada za ruch kamery, więc umieszczenie tu obsługi klikania wydaje się dość intuicyjne. Tutaj też można stworzyć sterowanie kamerą, które opisywałem w innym poradniku.

Teraz zaznaczmy ten obiekt!

Oznaczenie obiektu

Sprawa mogłaby się wydawać skomplikowana ale jest banalnie prosta. Takie kółko to nic innego jak ułożony pod postacią plane z odpowiednią teksturą. Żeby wszystko wyglądało dobrze, tekstura najlepiej żeby była kwadratowa i miała na sobie nasz okrąg z przeźroczystym tle. Obrazek musimy zapisać w formacie PNG. Przykładowy okrąg umieszczam tutaj:

Okrąg do postaci

Obrazek jest dość duży, bo skalowanie w dół nie zmniejszy nam jego jakości. W przypadku optymalizacji, warto spróbować wstawić mniejszy okrąg.

Tworzymy sobie teraz pustego plane’a [Create -> Object 3D -> Plane] i przypisujemy go jako child naszej postaci gracza. Dodatkowo nazywamy go “PlayerSelection”. Takiego obiektu szukamy, więc przy innej nazwie, nie będzie to działać. Hierarchy powinno wyglądać tak:

Panel Hierarchy dla obiektu postaci

Teraz ustawiamy go równolegle do podłoża, nieco nad ziemią, ale pod postacią.

Umieszczamy plane w dobrym miejscu

Na nasz obiekt nakładamy teksturę (wystarczy obrazek tekstury przeciągnąć na plane) i zmieniamy sposób wyświetlania tekstury, tak żeby przeźroczystość była uwzględniona (Unlit / Transparent).

Ustawiamy dobry tryb tekstury

Jednak to może nie wystarczyć, bo trzeba jeszcze zmienić nieco samą teksturę. Wybieramy ją w panelu project:

Ustawienia tekstury

 

Przy takich ustawieniach, wszystko powinno pięknie działać.

Na koniec wyłączamy obiekt PlayerSelection. W końcu na początku gry, nie chcemy mieć zaznaczonej postaci:

Wyłączamy oznaczenie

Podsumowanie

Ten prosty kod, sprawia, że możemy za pomocą kliknięcia myszą w obiekt zaznaczyć go. Przy okazji, wszystkie inne obiekty się odznaczają. Co teraz można zrobić? Dodać sterowanie za pomocą myszki i przygotować całkiem fajnego RTSa, albo inną grę turową czy strategiczną.

Exit mobile version