├── lab_00 ├── konfiguracja_git.md └── readme.md ├── lab_01 ├── c_sharp_wer2_0.pdf ├── full_interface.png ├── move_tool.png ├── readme.md ├── rect_tool.png ├── rotate_tool.png ├── scale_tool.png └── transform_tool.png ├── lab_02 ├── cube_components.png ├── prefab_overrides.png ├── pyramid.png └── readme.md ├── lab_03 └── readme.md ├── lab_04 ├── character_inspector.png ├── fps_camera_placement.png └── readme.md ├── lab_05 ├── box_components.png ├── elevator_one.png ├── physic_material.png └── readme.md ├── lab_06 ├── assets │ ├── Troll2.png │ ├── Troll2 │ │ ├── troll_0000_feet2left (2).png │ │ ├── troll_0000_right-hand.png │ │ ├── troll_0001_feet2right (2).png │ │ ├── troll_0001_left-arm.png │ │ ├── troll_0002_left-sholder.png │ │ ├── troll_0003_right-brow.png │ │ ├── troll_0004_left-brow.png │ │ ├── troll_0005_scull.png │ │ ├── troll_0006_left-ear.png │ │ ├── troll_0007_head.png │ │ ├── troll_0008_right-ear.png │ │ ├── troll_0009_torso.png │ │ ├── troll_0010_left-feet.png │ │ ├── troll_0011_left-hip.png │ │ ├── troll_0012_left-leg.png │ │ ├── troll_0013_pelvis.png │ │ ├── troll_0014_left-feet.png │ │ ├── troll_0015_left-hip.png │ │ ├── troll_0016_left-leg.png │ │ ├── troll_0017_left-hand.png │ │ ├── troll_0018_weapon.png │ │ ├── troll_0019_left-arm.png │ │ └── troll_0020_left-sholder.png │ ├── craftpix-062999-2d-fantasy-orc-free-sprite-sheets.zip │ ├── freetileset.zip │ ├── mountain_landscape.png │ └── orc_1_separated.png ├── import_inspector.png └── readme.md ├── lab_07 ├── ground_settings.png ├── movement_script_settings.png ├── platform.png ├── player_components.png ├── player_rigidbody_settings.png └── readme.md ├── lab_08 ├── assets │ ├── craftpix-net-484869-free-minotaur-tiny-style-2d-sprites.zip │ └── craftpix-net-563568-free-wraith-tiny-style-2d-sprites.zip ├── lab_8_starter_light_2022.zip └── readme.md ├── lab_09 └── readme.md └── readme.md /lab_00/konfiguracja_git.md: -------------------------------------------------------------------------------- 1 | # Kilka wksazówek jak pracować z systemem kontroli wersji Git 2 | 3 | ## 1. Wstępna konfiguracja 4 | 5 | Nowe repozytorium inicjalizujemy komendą: 6 | ```console 7 | git init 8 | ``` 9 | W folderze, w którym polecenie zostało uruchomione pojawi się ukryty folder o nazwie `.git`, w którym znajdują się informacje o naszym repozytorium. Zostanie również utworzona gałąź (ang. branch) `master`. 10 | W przypadku pracu wielu osób na tym samym koncie systemu operacyjnego należy skonfigurować jeszcze parametry `user.name` oraz `user.email`, które będą się pojawiały w commitach, które w trakcie pracy będą wykonywane. 11 | ```console 12 | git config --local user.name akowalski 13 | git config --local user.email akowalski@gmail.com 14 | ``` 15 | 16 | W przypadku, gdy chcemy ustawić takie dane dla każdego repozytorium, które będzie tworzone na tym koncie możemy zamienić `--local` na `--global` lub `--system`. Należy wtedy pamiętać, że wciąż lokalnie dla konkretnego repozytorium możemy te wartości nadpisać. 17 | 18 | Kolejną rzeczą, którą należy wykonać jest wyłączenie domyślnej integracji Visual Studio Code z windowsowym menedżerem poświadczeń, który będzie przechowywał dane logowania do serwisu GitHub innych użytkowników utrudniając pracę kolejnym, którzy będą chcieli wypychać zmiany do swojego zdalnego repozytorium. 19 | Możemy to zrobić poleceniem: 20 | ```console 21 | git config --system --unset credential.helper 22 | ``` 23 | Warto również sprawdzić czy nie ma takiego ustawienia w innych zakresach konfiguracji. 24 | ```console 25 | git config --global -l 26 | git config --local -l 27 | ``` 28 | 29 | Jeżeli tak to tutaj również usuwamy ten parametr. 30 | 31 | ## 2. Podstawowe komendy systemu Git 32 | 33 | Po podstaowej konfiguracji narzędzia Git możemy teraz dodać coś do naszego repozytorium. 34 | ```console 35 | git add plik.py 36 | ``` 37 | Powyższe polecenie dodaje plik `plik.py` do poczekalni (ang. stage area) i w Visual Studio Code będzie on oznaczony literą `A` (added czyli dodany). 38 | Możemy również dodać wszystkie pliki w bieżącej lokalizacji: 39 | ```console 40 | git add * 41 | ``` 42 | Należy jednak pamiętać, że różne narzędzia dodają 'coś od siebie' i mogą po pierwsze pojawić się pliki konfiguracyjne, które raczej nie będą potrzebne kiedy będziemy chcieli udostępnić repozytorium dla innych użytkowników, którzy mogą chcieć korzystać z innego narzędzia niż nasze i będą musieli samodzielnie nieco 'posprzątać' to repozytorium. Dlatego zalecanym krokiem przed dodaniem czegokolwiek do repozytorium jest przygotowanie pliku `.gitignore` zawierającego reguły (wyrażenia regularne), które spowodują, że spełaniające je zasoby będą przez narzędzie Git ignorowane przy sledzeniu zmian. Jednak należy pamiętać, że w przypadku modyfikacji `.gitignore` powinniśmy usunąć śledzenie zasobów, najwygodniej po prostu: 43 | ```console 44 | git rm * 45 | ``` 46 | i ponownie 47 | ```console 48 | git add * 49 | ``` 50 | aby Git dodał wszystko ignorując te zawarte w `.gitignore`. 51 | 52 | Jeżeli zasoby, które chcemy śledzić są już dodane możemy wykonać ich zatwierdzenie. 53 | ```console 54 | git commit -m "pierwszy commit" 55 | ``` 56 | spowoduje stworzenie nowej migawki zasobów znajdujących się w folderze roboczym (czyli wszystkiego tego co jest aktualnie widoczne w eksplorerze projektu) czyli z poczekalni. Każdy commit ma swój unikalny hashcode. 57 | 58 | ### __Podpięcie lokalnego repozytorium do nowego zdalnego repozytorium__ 59 | 60 | __Krok 1__ 61 | 62 | Tworzymy nowe repozytorium zdalne, w trakcie zajęć korzystamy z serwisu GitHub. Po jego utworzeniu wyświetlona zostanie strona z komendami, które powinny nam pomóc przy procesie synchronizacji. Komendy włączając pierwszy commit można pominąć, gdyż zostało to już zrobione w nieco inny sposób. 63 | Dla lokalnego repozytorium wskazujemy zdalne repozytorum, do którego będziemy chcieli kod wypychać. 64 | ```console 65 | git remote add origin https://github.com/user/repo.git 66 | ``` 67 | Powyższe polecenie jest właściwe jeżeli nie korzystamy z klucza SSH (lepsze rozwiązanie, jeżeli tylko my korzystamy z danego konta w systemie operacyjnym), gdyż nie wymaga każdorazowego podawania poświadczeń przy wypychaniu zmian. Dodajemy informację o nowym zdalnym repozytorium o aliasie origin i podanym url-u. 68 | 69 | Jeżeli chcemy sprawdzić jaki jest adres zdalnego repozytorium to 70 | ```console 71 | git remote get-url origin 72 | ``` 73 | a jeżeli trzeba go zmienić 74 | ```console 75 | git remote set-url origin https://nowy.adres.repo 76 | ``` 77 | 78 | __Krok 2__ 79 | 80 | Polecenie 81 | ```console 82 | git push -u origin master 83 | ``` 84 | próbuje wysłać aktualną gałąź (i jej stan z wykonanego nostatnio commitu) do zdalnego repozytorium z adresu przypisanego do aliasu (origin) do zdalnej gałęzi master. 85 | Tutaj może się pojawić kilka problemów (błędów), które mogą tę operację uniemożliwić. 86 | Jeżeli otrzymamy komunikat, mówiący, że wypchanie nie jest możliwe, bo użytkownik o nazwie xxx nie posiada uprawnień oznacza to, że w `menedżerze poświadczeń` są zapisane poświadczenia do serwisu GitHub innego użytkownika (mogą pochodzić z innego narzędzia). Należy usunąć wszystkie poświadczenia, które odwołują się do serwisu GitHub i ponowić próbę wypchania zmian. Można ponowić operację wypchania zmian. 87 | 88 | Może się tutaj również pojawić problem jeżeli w zdalnym repozytorium znajdują się jakieś zasoby, których lokalnie nie ma (np. dodany domyślny plik `readme.md`). Wtedy możemy wykonać polecenie push z dodatkowym parametrem, wymuszającym wypchanie (force): 89 | ```console 90 | git push -f origin master 91 | ``` 92 | 93 | ### __Pobranie repozytorium w inne miejsce/komputer__ 94 | 95 | Jeżeli chemy kontynuować pracę z zawartością repozytorium na innym komputerze, narzędziu to wystarczy przejść do folderu, w którym chcemy umieścić repozytorium, np. folder z innymi projektami i wykonać polecenie: 96 | ```console 97 | git clone http://link.do.repo 98 | ``` 99 | To polecenie __UTWORZY__ nowy folder o nazwie takiej jak nazwa zdalnego repozytorium i umieści tam już informacje o jego stanie (folder .git) oraz informacji o remote (ten sam, z którego został sklonowany). Teraz wystarczy skonfigurować `user.name` oraz `user.email` w przestrzeni `--local`, jeżeli nie ma poprawnych ustawień globalnych (pracujemy na tym samym koncie co inni użytkownicy) i można dalej pracować, zatwierdzać zmiany i wypychać je ponownie do zdalnego repozytorium. 100 | 101 | ### __Więcej ?__ 102 | 103 | Polecam [git-scm.com/book/pl/v2](https://git-scm.com/book/pl/v2). -------------------------------------------------------------------------------- /lab_00/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 00 - Instalacja i konfiguracja środowiska UNITY 2 | 3 | ## 0. Wstęp. 4 | 5 | Unity występuje w kilku wersjach (więcej pod adresem https://unity.com/faq) w zależności od wielkości organizacji i przychodów, które osiąga w danym roku. Wersja, która będzie wykorzystywana w trakcie zajęć to edycja Personal. Tabelka porównująca poszczególne plany dostępna jest pod adresem: https://unity.com/compare-plans. 6 | 7 | W ostatnim czasie pojawiły się informacje od kierownictwa Unity o chęci zmiany cennika, które odbiły sie szerokim echem wśród społeczności i ostatecznie skloniły firmę do daleko idących ustępstw. UPDATE 2024 - plany zostały jednak porzucone. Więcej można przeczytać w liscie otwartym: https://blog.unity.com/news/open-letter-on-runtime-fee. 8 | 9 | ## 1. Instalacja UNITY 10 | 11 | Możliwa jest instalacja wielu wersji UNITY na jednym koncie użytkownika systemu operacyjnego i dlatego zarządzanie wersjami oraz projektami UNITY odbywa się poprzez dodatkowe oprogramowanie - **Unity Hub**. 12 | 13 | Aby korzystać w pełni z oprogramowania Unity należy założyć konto na portalu unity.com i uzyskać tzw. **Unity ID**. 14 | 15 | Po instalcja Unity Hub i jego uruchomieniu możemy wybrać jedną z czterech kategorii: 16 | * Projects 17 | * Learn 18 | * Community 19 | * Installs 20 | 21 | Opcje dostępne w **Projects** pozwalają przeglądać istniejące projekty, dodawać nowe lub zmienić wersję środowiska UNITY istniejącego projektu (tutaj nie zawsze wszystko musi pójść zgodnie z planem). 22 | 23 | Część **Learn** pozwala na dodanie istniejących projektów gier, stworzonych w celach edukacyjnych. Wystarczy wybrać projekt i opcję "DOWNLOAD PROJECT". Warto zwrócić uwagę na wersję Unity, dla której projekt został stworzony, będzie to gwarancja kompatybilności. 24 | 25 | **Community** to zbiór przydatnych linków do materiałów dla i od społeczności zgromadzonej wokół Unity. 26 | 27 | Ostatnia, ale nie najmniej ważna opcja, to **Installs** gdzie możemy pobrać i zainstalować kolejne wersje środowiska, odinstalować istniejące lub zarządzać modułami dla konkretnej zainstalowanej wersji. 28 | 29 | W trakcie zajęć wykorzystywana będzie wersja **2022.3.48f1 LTS**. Jest to wersja o długim wsparciu technicznym. Pobranie i instalacja wymaga sporo czasu (dużo zależy od szybkości łącza internetowego) więc należy wybrać miejsce z wystarczająco dużą ilością wolnego miejsca. Moduły, które wybieramy na początku to: 30 | * **Windows Build support** lub **Linux build support** lub **Mac build support** w zależności od używanego systemeu operacyjnego, 31 | * **Microsoft Visual Studio 2022 Community** lub **Visual Studio Code**, 32 | * **Documentation** (opcjonalnie) - jeżeli ktoś planuje pracę w trybie offline i nie będzie miał dostępu do dokumentacji dostępnej w Internecie. 33 | 34 | Kod w śorodiwsku UNITY piszemy w języku C# i można wybrać inny edytor niż **Visual Studio 2022 Community**, ale to rozwiązanie ze względu na oficjalne wsparcie wydaje się dobrym połączeniem na start i będzie wykorzystywane w trakcie zajęć. Używanie Visual Studio Code nie powinno powodować większych problemów. 35 | 36 | 37 | ## 2. Konfiguracja systemu Git dla projektu Unity. 38 | 39 | Jeżeli nie pracowałeś/-ał wcześniej z systemem Git, możesz zapoznać się z informacjami i konfiguracji oraz podstawowych poleceniach przedstawionych w dokumencie [konfiguracja_git](konfiguracja_git.md). 40 | 41 | Korzystanie z systemów kontroli wersji jest w dzisiejszych czasach absolutnym standardem. Unity w trkacie naszej pracy nad projektem "produkuje" wiele plików tymczasowych, plików binarnych, których ani nie będziemy potrzebować w gotowej już grze, ani nie chcemy marnować czasu na ich synchronizację ze zdalnym repozytorium. Dlatego w naszych projektach (mimo, że docelowo może nie pojawić się wiele dużych plików) wykorzystamy wersję Git LFS (Large File Storage), która została stworzona specjalnie dla takich sytuacji. Wersję dla systemy Windows i krótką instrukcję instalacji znajdziemy pod adresem [https://git-lfs.github.com/](https://git-lfs.github.com/). 42 | 43 | W celu wydajniejszego zarządzania plikami binarnymi (assety) zalecane jest pobranie i instalacja Git LFS, czyli modułu, który usprawnia pracę GIT-a właśnie a tego rodzaju zasobami. 44 | Dla projektów o objętości liczonej w gigabajtach warto rozważyć repozytorium hostowane w usłudze Azure DevOps. Dla zespołu do 5 użytkowników nie jest pobierana opłata wstępna (możliwe są opłaty za przekroczenie dostepnego miejsca - do samodzielnego sprawdzenia). 45 | 46 | Przydatne wskazówki znajdziemy również w artykule pod adresem: https://www.anchorpoint.app/blog/github-and-unity -------------------------------------------------------------------------------- /lab_01/c_sharp_wer2_0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/c_sharp_wer2_0.pdf -------------------------------------------------------------------------------- /lab_01/full_interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/full_interface.png -------------------------------------------------------------------------------- /lab_01/move_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/move_tool.png -------------------------------------------------------------------------------- /lab_01/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 1 - Podstawy obsługi środowiska UnityEditor 2 | 3 | ## *Interfejs UnityEditor* 4 | 5 | ![Interfejs](full_interface.png) 6 | 7 | ### **1. SceneView** 8 | 9 | Ten widok to nasza przestrzeń robocza z widokiem na aktualnie aktywną scenę (gra może ich posiadać wiele). Tutaj możemy dodać, edytować, usuwać obiekty gry (GameObject). Tymi obiektami mogą być modele 2D i 3D, kamery, oświetlenie itp.. W momencie kiedy uruchomimy grę (na razie w UnityEditor) możemy również w czasie rzeczywistym dokonywać pewnych zmian na scenie i podglądać zmiany w grze w czasie rzeczywistym. Po zatrzymaniu gry widok sceny wróci do punktu początkowego a wprowadzone zmiany nie zostaną zapisane (można jednak temu zaradzić). 10 | 11 | ### **2. Inspector Window** 12 | 13 | Jest to okno, które prezentuje wszystkie cechy zaznaczonego obiektu gry oraz komponenty, które zostały do niego podpięte. Tutaj możemy modyfikować widoczne parametry komponentów (również gdy wciśniemy "Play"), dodawać lub usuwać komponenty do obiektu. 14 | 15 | ### **3. Project Window** 16 | 17 | Jest to widok, który prezentuje zawartość projektu. Możemy tutaj dodawać nowe foldery i organizować elementy gry wokół nich. Z tego miejsca możemy poprzez przeciąganie dodawać obiekty albo bezpośrednio na scenę lub do okna hierarchii. 18 | 19 | Można również przeciągać zasoby spoza UnityEditor do okna Project i w takim przypadku Unity zaimportuje te elementy jako nowe zasoby projektu. 20 | 21 | Mimo, że w oknie Project widzimy odbicie struktury zasobów naszego projektu jak w systemie plików, to Unity zarządza tymi zasobami również poprzez metainformacje, które mogą zostać uszkodzone (niespójność) jeżeli w tej hierachii dokonamy zmian przez system plików a nie okno Project. Nie należy tego robić. 22 | 23 | ### **4. Hierarchy window** 24 | 25 | To onko prezentuje wszystkie obiekty jakie są aktualnie umieszczone w naszej grze. Nazwa okna nawiązuje również do sposobu w jaki ta lista jest zaprezentowana - możemy zobaczyć które obiekty są obiektami nadrzędnymi i podrzędnymi. 26 | 27 | ### **5. Widok kamery** 28 | 29 | Na powyższym zrzucie ekranu aktywnym obiektem jest domyślnie umieszczana kamera w każdej nowej scenie. Zmiana parametrów kamery będzie wpływała na to co w tym oknie widać, co pozwala na ustawienie optymalnej pozycji. Podobnie będzie wyglądał również widok z podglądem na okno gry. 30 | 31 | ### **6. Toolbar** 32 | 33 | Jest to pasek narzędziowy, który pozwala na proste przekształcenia obiektów widocznych na scenie. 34 | 35 | #### **6.1 Hand tool** 36 | 37 | To narzędzie ma kilka trybów działania. Po wybraniu narzędzia i przytrzymaniu **lewego klawisza** myszy możemy zmieniać perspektywę widoku sceny. 38 | 39 | Wciśnięcie i przytrzymanie prawego klawisza pozwala na wykonywanie obrotu widoku wokół aktualnego punktu w każdej płaszczyźnie. 40 | 41 | Klawiszami, które pozwalają na zmianę trybu pracy tego narzędzia są również **Ctrl** oraz **Alt**. Sprawdź ich działanie w połączeniu z wciśniętym lewym lub prawym klawiszem myszy. 42 | Sprawdź również działanie wciśniętego prawego klawisza myszy oraz klawiszy **"WASD"**. 43 | Jeżeli prędkość przesuwania widoku sceny nas nie zadowala możemy to przyspieszyć trzymając wciśnięty klawisz **Shift**. 44 | 45 | Istnieje też możliwość przywołania narzędzia Hand "na chwilę" poprzez wciśnięcie i przytrzymanie kółka myszy, możemy przesunąć widok a po zwolnieniu przycisku powrócimy do wcześniej aktywnego narzędzia. 46 | 47 | `` 48 | Skrót, którym przywołamy narzędzie Hand to "Q". 49 | `` 50 | 51 | #### **6.2 Move tool (wcześniej Translate tool)** 52 | 53 | ![Move tool](move_tool.png) 54 | 55 | To narzędzie pozwala nam na przemieszczanie obiektów na scenie za pomocą myszy i klawiatury. Takie przesunięcia możemy wykonywać w jednej z trzech płaszczyzn (nawet jeżeli pracujemy nad grą 2D). 56 | 57 | Oś x to czerwona strzałka, oś y to zielona a oś z to strzałka niebieska. Powinnismy to zapamiętać, gdyż zdarza się pracować z obiektami w różnych perspektywach, ale kolory dla osi są stałe co zapobiega "pogubieniu" się w przestrzeni, co na początku przygody z projektowaniem w 3D nie jest wcale takie trudne. 58 | 59 | W języku UNITY zbiór tych trzech strzałek (ale nie tylko ich) nosi nazwę **gizmo**, który można przetłumaczyć na język polski jako gadżet, ale jednak oryginalna nazwa używana jest częściej. Gizmo to trójwymiarowy obiekt lub tekstura, która dostarcza informacji o jakimś elemencie typu GameObject - przydaje się szczególnie, jeżeli mamy w naszym projekcie niewidzialne obiekty, ale chcemy w trakcie projektowania gry widzieć gdzie się znajdują (np. znaczniki zakresu poruszania się platform, stworzeń, przeszkód itp.) 60 | 61 | Przytrzymując wciśniętą strzałkę możemy przemieszczać obiekt w wybranej płaszczyźnie. Jeżeli klikniemy na kolorową płaszczyznę widoczną u zbiegu strzałek, możemy przemieszczać obiekt w dwóch wybranych płaszczyznach. Do bardziej precycyjnego pozycjonowania obiektów przyda się jednak okno inspektora. 62 | 63 | `` 64 | Skrót, którym przywołamy narzędzie Move to "W". 65 | `` 66 | 67 | #### **6.3 Rotate tool** 68 | 69 | ![Rotate tool](rotate_tool.png) 70 | 71 | Jak sama nazwa wskazuje narzędzie to służy do obracania obiektów w przestrzeni lub wybranej płaszczyźnie. Przytrzymanie wciśniętego lewego klawisza myszy pozwala na obrót wokół punktu obrotu w wybranej płaszczyźnie (x, y lub z) a chwycenie obszaru obiektu między tymi liniami pozwala na obrót w przestrzeni trójwymiarowej. 72 | 73 | W przypadku zaznaczenia kilku obiektów jednocześnie możemy za pomocą kontrolek znajdujących się po prawej stronie toolbara zmieniać sposób przekształcania obiektów. Wybranie opcji **pivot** pozwala na przekształcenie każdego obiektu indywidualnie a **center** umieszcza gizmo centralnie między zaznaczonymi obiektami i obraca je jakby stanowiły połączoną całość. 74 | 75 | Tryb **global** pozwala na manipulowanie obiektem względem globalnych współrzędnych świata bez względu na to jak aktualnie wygląda perspektywa, z której obiekt obserwujemy. Tryb **local** dokonuje tych przekształceń względem aktualnej pozycji i obrotu obiektu. Zwróć uwagę na zmianę wartości dla każdej osi przy przemieszczaniu obiektu w obu trybach. 76 | 77 | `` 78 | Skrót, którym przywołamy narzędzie Rotate to "E". 79 | `` 80 | 81 | #### **6.4 Scale tool** 82 | 83 | ![Scale tool](scale_tool.png) 84 | 85 | Narzędzie to służy do skalowania obiektu. Zamiast grotów strzałki jak w przypadku narzędzia Move każda linia osi zakończona jest sześcianem. Zasada działania i kolory są takie jak w przypadku narzędzia move. Uchwycenie centralnego sześcianu zmienia rozmiar całego obiektu. 86 | 87 | `` 88 | Skrót, którym przywołamy narzędzie Scale to "R". 89 | `` 90 | 91 | #### **6.5 Rect tool** 92 | 93 | ![Rect tool](rect_tool.png) 94 | 95 | Narzędzie to służy głównie to obracania obiektów 2D, ale nadaje się również dla obiektów trójwymiarowych. Pozwala ono na przemieszczanie, skalowanie i obracanie obiektów oraz na resetowanie ich punktu obrotu (pivot point). 96 | 97 | `` 98 | Skrót, którym przywołamy narzędzie Rect to "T". 99 | `` 100 | 101 | #### **6.6 Transform tool** 102 | 103 | ![Transform tool](transform_tool.png) 104 | 105 | Narzędzie to łączy w jednym narzędzia Move, Rotate i Scale. 106 | 107 | 108 | `` 109 | Skrót, którym przywołamy narzędzie Rect to "Y". 110 | `` 111 | 112 | Mimo, że angielskie nazwy narzędzi, a przynajmniej ich pierwsze litery, mogą kojarzyć się z innymi skrótami niż te, które są do nich przypisane to wystarczy spojrzeć na kolejność narzędzi na pasku i liter na klawiaturze i wszystko staje się jasne. 113 | 114 | #### **6.7 Available custom editor tools** 115 | 116 | Tutaj mogą pojawić się narzędzia specyficzne dla komponentów zaznaczonego GameObject, np. edytora obiektu BoxCollider. 117 | 118 | ### **7. Play buttons** 119 | 120 | Te trzy przyciski pozwalają na przejście z trybu edit mode do play mode. Przejście w tryb play pozwala na uruchomienie gry z pozycji startowej aktualnej sceny i podczas tego trybu możemy testować grę lub nawet dokonywać zmian w obiektach. Te zmiany będą propagowane na widoczny ekran gry, ale **nie zostaną zapisane w stanie obiektów** i po wyjściu z trybu play wszystko wraca do stanu poprzedniego. 121 | 122 | Trybu pauzy nie trzeba chyba tłumaczyć. Ostatni przycisk służy do przechodzenia przez stan gry klatka po klatce co pozwala na łatwiejsze wychwycenie momentu, w którym występuje jakiś problem, który trudno zidentyfikować lub do bardzo precyzyjnego ustawienia obiektów. 123 | 124 | ---- 125 | ## Zadania do samodzielnego wykonania 126 | 127 | 1. Przeczytaj treść pliku [readme](../lab_00/readme.md) (możesz się też wspomóc plikiem [konfiguracja Git](../lab_00/konfiguracja_git.md)) z folderu lab_00 i zainstaluj niezbędne oprogramowanie. 128 | 2. Utwórz projekt testowy Unity i skonfiguruj narzędzie Git do pracy z tym projektem. Stwórz zdalne repozytorium (GitHub, Bitbucket, Azure DevOps) i wypchnij do niego lokalne repozytorium. Pamiętaj o przygotowaniu odpowiedniego pliku .gitignore. 129 | 3. Aby bliżej zapoznać się z dostępnymi modelami stwórz z dostępnych brył model, który będzie przypominał Stonehenge. Nie musisz używać żadnych tekstur ani dokładnych modeli - tylko to co można zrobić w edytorze Unity. Podziel się efektem swojej pracy w postaci screenu na kanale spotkania. 130 | 4. Uruchom lokalny manual (jeżeli opcja instalacji dokumentacji została zaznaczona) z menu Help -> Unity manual i przeanalizuj sekcję "Working in Unity". 131 | 5. Zastanów się nad tematyką gry, którą chciałbyś stworzyć w ramach projektu zaliczeniowego. Na kolejnych zajęciach zostanie sporządzona lista projektów zaliczeniowych. 132 | 6. Jeżeli uważasz, że wiedza z zakresu znajomości języka C# wymaga odświeżenia to może warto zacząć od [Wstęp do programowania w C#](c_sharp_wer2_0.pdf). W trakcie zajeć będzie prezentowany kod w języku C#, jednak omawianie samego języka nie zostało przewidziane w programie przedmiotu. -------------------------------------------------------------------------------- /lab_01/rect_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/rect_tool.png -------------------------------------------------------------------------------- /lab_01/rotate_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/rotate_tool.png -------------------------------------------------------------------------------- /lab_01/scale_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/scale_tool.png -------------------------------------------------------------------------------- /lab_01/transform_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_01/transform_tool.png -------------------------------------------------------------------------------- /lab_02/cube_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_02/cube_components.png -------------------------------------------------------------------------------- /lab_02/prefab_overrides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_02/prefab_overrides.png -------------------------------------------------------------------------------- /lab_02/pyramid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_02/pyramid.png -------------------------------------------------------------------------------- /lab_02/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 2 - Obiekty gry, komponenty i prefabrykaty. 2 | 3 | ## 1. Obiekty gry i komponenty. 4 | 5 | Obiekt gry (GameObject) to każdy obiekt, który pojawia się w grze, również taki, który nie jest widoczny, np. kamera, niewidzialna przeszkoda, dźwięki. Obiekty gry same w sobie nie posiadają jakiegoś zachowania i dopiero poprzez 'podpinanie' komponentów możemy nadać im pewne cechy i zachowania. 6 | 7 | Unity posiada spory zbiór obiektów, które posiadają już dołączone komponenty, ale możemy zmieniać konfigurację zarówno samych komponentów jak i ich kombinacji. 8 | 9 | Poniżej zaprezentowane są komponenty, które domyślnie posiada obiekt typu Cube. 10 | 11 | ![Komponenty obiektu Cube](cube_components.png) 12 | 13 | 14 | ### **Komponent Transform** 15 | 16 | Podstawowym komponentem obiektu jest komponent **Transform**, który przechowuje i pozwala na modyfikację położenia, rotacji i skali danego obiektu. Każdy `GameObject` posiada komponent `Transform` i nie można go z obiektu usunąć. Można się o tym przekonać choćby wstawiając pusty obiekt na scenę. 17 | 18 | Obiekt `Transform` przechowuje również informacje o wszystkich obiektach potomnych oraz o swoim rodzicu. Kiedy w obiekcie rodzica zostaną zmienione jakieś cechy komponentu Transform, zmianie ulegną również obiekty potomne. 19 | 20 | Właściwości komponentu `Transform` obiektów potomnych są podawane względem obiektu rodzica. Wartości te określa się jako lokalne współrzędne. Czasami potrzeba jednak określić w jakiej pozycji globalnej znajduje się obiekt podrzędny i dlatego API Unity pozwala na konwersję lokalnych koordynatów na koordynaty globalne. 21 | 22 | Istnieją sytuacje, w których skalowanie niejednolite (wartości dla wszystkich osi nie są równe) obiektu nadrzędnego może mieć niespodziewane konsekwencje. Więcej przeczytasz pod adresem [Non-uniform transform](https://docs.unity3d.com/2022.3/Documentation/Manual/class-Transform.html) w podrozdziale "Limitations with Non-Uniform Scaling". 23 | 24 | Dobrą praktyką jest ustawienie obiektu rodzica w pozycji (0,0,0) przed dodaniem potomków co spowoduje ustawianie pozycji potomków również na wartość (0,0,0) - pamiętajmy, że jako lokalne koordynaty. 25 | 26 | ### **Komponent Mesh Filter** 27 | 28 | Jest to komponent, który pobiera siatkę z zasobów (ang. assets) i przekazuje do komponentu Mesh Renderer. 29 | 30 | ### **Komponent Mesh Renderer** 31 | 32 | Ten komponent odpowiada za wyświetlenie przekazanej przez Mesh Filter siatki i wyświetla obiekt w pozycji określownej przez komponent `Transform`. Ten komponent pozwala na wybór materiału, którym ma być pokryta siatka, tego czy przedmiot rzuca cień, czy na obiekt może padać cień oraz kilka innych ustawień związanych z oświetleniem (więcej: [Mesh Renderer](https://docs.unity3d.com/2022.3/Documentation/Manual/class-MeshRenderer.html*)). 33 | 34 | ### **Komponent Box Collider** 35 | 36 | Ten komponent jest komponentem używanym przez system fizyki silnika Unity i odpowiada za określenie kształt kolidera (ang. collider) dla danego obiektu. 37 | Dzięki temu komponentowi możliwe jest wykrywanie kolizji obiektów oraz wyzwalanie (ang. trigger) zdarzeń po wykryciu kolizji. 38 | 39 | ## Zadania 40 | 41 | 1. Dodaj obiekt typu Cube na scenę i dodaj do niego komponent Rigidbody. Uruchom tryb play i sprawdź zachowanie sześcianu, zwłaszcza pozycji w osi Y. 42 | 2. Dodaj platformę do sceny, na którą może "spaść" sześcian (platforma również musi posiadać odpowiednie komponenty, aby "zderzać" się z innymi obiektami). Zmodyfikuj wielkość kolidera sześcianu tak aby nie pokrywał się z bryłą sześcianu. Sprawdź zachowanie w trybie play. 43 | 3. Dodaj więcej sześcianów z komponentem Rigidbody tak, żeby po uruchomieniu trybu play swobodnie spadały na platformę. 44 | 4. Wykorzystując elementy Cube oraz narzędzia do przemieszczania oraz przyciąganie do siatki zbuduj piramidę jak na poniższym zrzucie ekranu. 45 | 46 | ![Piramida](pyramid.png) 47 | 48 | 49 | Więcej możesz przeczytać w oficjalnej dokumentacji Unity: [GameObjects](https://docs.unity3d.com/Manual/GameObjects.html) 50 | 51 | ## 2. Prefabrykaty. 52 | 53 | 54 | Standardowe obiekty umieszczone na scenie są dostępne tylko na tej scenie i można je traktować jako pojedyncze instancje, chociaż możemy utworzyć i umieścić wiele kopii tych samych obiektów. Jednak kiedy zainstnieje potrzeba dokonania zmian we wszystkich kopiach możemy natrafić na pewne trudności w zarządzaniu obiektami. Powielanie ich na inne sceny również jest niewygodne przy takim podejściu. 55 | Dużo lepszym pomysłem jest stworzenie prefabrykatu (szablonu), który zostanie umieszczony w zasobach projektu i możliwe jest jego wielokrotne wykorzystanie oraz edycja w jednym miejscu. Dodatkowo każda instancja prefabrykatu jest edytowalna niezależnie umożliwiając również nadpisanie zmienionej cechy na prefabrykat jeżeli taka będzie nasza wola. 56 | 57 | Aby utworzyć prefabrykat dodajemy obiekt gry na scenę - i może to być dowolny obiekt. Jeżeli ma to być bryła składająca się z wielu obiektów to niezłym pomysłem jest rozpoczęcie od pustego obiektu gry (Empty GameObject), a następnie dodanie kolejnych obiektów-składowych jako potomków. Następnie przeciągamy taki obiekt do okna "Project", najlepiej do wcześniej przygotowanej struktury folderów dla prefabrykatów, i upuszczamy. Kolor obiektu w panelu `Hierarchy` powinien zmienić się na niebieski. 58 | 59 | Teraz możemy taki prefabrykat wykorzystywać wielokrotnie. Po dodaniu komponentu lub zmianie wartości komponentu w instancji prefabrykatu możemy w oknie `Inspector` wybierając przycisk "Overrides" zdecydować czy chcemy te zmiany propagować na oryginalny prefabrykat czy może przywrócić stan aktualnej instancji do oryginalnej postaci. Możemy też decydować niezależnie dla każdej zmiany, którą wprowadziliśmy. 60 | 61 | ![Prefab override](prefab_overrides.png) 62 | 63 | Opcja "Apply All" zastosuje wszystkie zmiany do bazowego prefabrykatu, "Revert All" przywróci edytowaną instancję do postaci zgodnej z jej prefabrykatem. 64 | 65 | Klikając prawym przyciskiem myszy w panelu `Hierarchy` na wybraną instancję prefabrykatu możemy wybrać opcję "Unpack prefab", która spowoduje wypakowanie całej hierarchii obiektów prefabrykatu i odpięcie prefabrykatu jako rodzica. 66 | 67 | **Zadania** 68 | 69 | 1. Stwórz nową scenę i dodaj do niej obiekt typu Cube. Dodaj kolejny obiekt typu Cube będący potomkiem wcześniej dodanego obiektu. 70 | 2. Zmień skalę obiektu bazowego na 0.5 dla każdej osi. Czy rozmiar potomka się zmienił ? A czy właściwości scale potomka się zmieniły ? Dodaj niezależny obiekt cube o standardowej wielkości i umieść go przylegająco do obiektu potomnego na tej samej płaszczyźnie Y. Przemieść teraz obiekt potomny o 1 jednostkę do góry w osi Y. Czy przesunięcie odbyło się o 1 metr (domyślna wartość dla 1 jednostki) ? Zrozumienie tego konceptu Unity jest istotne. 71 | 3. Dodaj pusty obiekt do sceny, ustaw go w pozycji (0,0,0) a następnie stwórz z niego prefabrykat. Zbuduj model składający się z kilku obiektów. 72 | 4. Dodaj kilka kopii prefabrykatu do sceny. Przejdź do edycji prefabrykatu i zmień układ jego elementów. Jakie zmiany zaszły na scenie ? 73 | 5. Teraz zmień lub dodaj nowy komponent do jednej z instancji prefabrykatu i zastosuj zmiany do prefabrykatu. Sprawdź czy zmiany zostały zastosowane do innych instancjach. 74 | 6. Dodaj kolejną instancję prefabrykatu, dokonaj zmian w modelu np. obrót, skala jednego z jego elementów (ale nie edytując prefabrykatu tylko tę instancję). Czy zmiana pozycji jednego z elementów instancji ma wpływ na inne instancje ? Czy takie zmiany można nadpisać do prefabrykatu? 75 | 7. Przeciągnij zmodyfikowaną instancję do miejsca gdzie zapisany był poprzedni prefabrykat. Okno, które się pojawi da możliwość utworzenia wariantu prefabrykatu (ang. Prefab Variant). Poczytaj więcej pod adresem: https://docs.unity3d.com/Manual/PrefabVariants.html i stwórz nowy wariant prefabrykatu. 76 | 8. Za pomocą narzędzia Pro Builder stwórz model wieży zamkowej na wzór tej spod adresu https://imgur.com/r/lowpoly/X1oBRy8. Zadanie polega na próbie odwzorowania kształtu, a nie materiału i ustawień oświetlenia. 77 | 78 | W celu zglębienia wiedzy z zakresu narzędzia ProBuilder polecam filmy: 79 | * https://www.youtube.com/watch?v=PUSOg5YEflM 80 | * https://www.youtube.com/watch?v=YtzIXCKr8Wo&t 81 | * oraz serię: https://www.youtube.com/watch?v=x8Uw6MwPliY&list=PLhvjMi_0yrQxvy_bDuGqRni8952571Bp3 82 | 83 | __Dodatkowe materiały:__ 84 | Manual narzędzia ProBuilder można znaleźć pod adresem: https://docs.unity3d.com/Packages/com.unity.probuilder@5.2/manual/index.html 85 | 86 | 87 | 88 | Cały rozdział poświęcony prefabrykatom: https://docs.unity3d.com/Manual/Prefabs.html 89 | 90 | Tutorial poświęcony zagnieżdżonym prefabrykatom: https://docs.unity3d.com/Manual/NestedPrefabs.html -------------------------------------------------------------------------------- /lab_03/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 3 - Wybrane elementy API Unity. Dodawanie własnych skryptów do obiektów gry. 2 | 3 | 4 | ## **Wybrane klasy z API Unity.** 5 | 6 | API Unity jest bardzo rozbudowane i nie sposób chociażby pobieżnie omówić wszystkie klasy tam dostępne. Są jednak takie, bez których praktycznie żaden projekt nie może 7 | istnieć. Zostały one wymienione przez autorów dokumentacji w artykule, którym będziemy się posiłkować: https://docs.unity3d.com/2022.3/Documentation/Manual/ScriptingImportantClasses.html 8 | 9 | > **Klasa [GameObject](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/GameObject.html)** 10 | Jest to klasa reprezentująca dowolny element, który można umieścić na scenie. Z poziomu tej klasy możemy pobierać podpięte pod obiekt komponenty, w tym niezrozłączny komponent `Transform`. Komponent `Transform` jest dostępny poprzez właściwość klasy o nazwie `transform`. 11 | 12 | __**Listing 1**__ 13 | ```csharp 14 | public class Ball : MonoBehaviour { 15 | 16 | // metoda Start() wywoływana jest przy inicjalizacji obiektu 17 | void Start() { 18 | // ustawienie obiektu w pozycji (0, 0, 0) 19 | transform.position = new Vector3(0.0f, 0.0f, 0.0f); 20 | } 21 | } 22 | ``` 23 | Do określenia pozycji w przestrzeni 3D możemy wykorzystać klasę [Vector3](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Vector3.html) lub [Vector2](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Vector2.html) dla 2D. 24 | Referencje do pozostałych komponentów uzyskujemy w inny sposób. Możemy to zrobić w jednorazowo (dla każdego obiektu) uruchamianej metodzie `Start()`: 25 | 26 | __**Listing 2**__ 27 | ```csharp 28 | public class Ball : MonoBehaviour { 29 | 30 | public float force = 5.0f; 31 | 32 | void Start() 33 | { 34 | Rigidbody rb = GetComponent(); 35 | rb.AddForce(0, 0, force, ForceMode.Impulse); 36 | } 37 | } 38 | ``` 39 | lub możemy wynieść zmienną do wyższego zakresu i umieścić jako pole komponentu, do którego możemy teraz odwołać się z poziomu innych skryptów lub edytować przez okno inspektora (jeżeli pole posiada modyfikator dostępu `public`): 40 | 41 | __**Listing 3**__ 42 | ```csharp 43 | public class Ball : MonoBehaviour { 44 | 45 | public float force = 10.0f; 46 | public Rigidbody rb; 47 | 48 | void Start() 49 | { 50 | rb.AddForce(Vector3.up * force, ForceMode.Impulse); 51 | } 52 | } 53 | ``` 54 | Oczywiście należy pamiętać, że jeżeli nie przypiszemy obiektu typu `Rigidbody` do zmiennej `rb` w powyższym to otrzymamy stosowny wyjątek: `UnassignedReferenceException: The variable rb of Ball has not been assigned`. Podpięcie instancji komponentu `Rigidbody` pod zmienną `rb` możemy wykonać z poziomu skryptu (jeżeli w oknie inspektora taki komponent do obiektu, który ma również podpięty ten skrypt został dodany) poprzez metodę `GetComponent()` (doc: https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Component.GetComponent.html) lub poprzez przeciągnięcie i upuszczenie komponentu `Rigidbody` w miejsce widocznej w inspektorze zmiennej `rb`, która obiekt tego typu może przechowywać. Jeżeli chcemy aby na dany obiekt gry działały siły fizyczne, to będziemy manipulować dodanym do niego komponentem `Rigidbody` a nie poprzez edycję komponentu `Transform`. 55 | 56 | Jak widać w każdym powyższym fragmencie kodu każda nasza klasa dziedziczy po klasie `MonoBehaviour`. 57 | 58 | > **Klasa [MonoBehaviour](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/MonoBehaviour.html)** 59 | > Jest to klasa, po której dziedziczy każdy nowy skrypt stworzony z poziomu UnityEditor. Ta klasa dostarcza mechanizm pozwalający na podpinanie skryptów pod obiekty gry oraz zapewnia interfejs pozwalający na umieszczenie kodu uruchamianego w określonym momencie pracy silnika lub po wystąpieniu określonego zdarzenia. 60 | 61 | Poniżej przykładowy pusty szablon klasy po dodaniu nowego skryptu: 62 | 63 | __**Listing 4**__ 64 | ```csharp 65 | using System.Collections; 66 | using System.Collections.Generic; 67 | using UnityEngine; 68 | 69 | public class Example : MonoBehaviour 70 | { 71 | // Start is called before the first frame update 72 | void Start() 73 | { 74 | 75 | } 76 | 77 | 78 | // Update is called once per frame 79 | void Update() 80 | { 81 | 82 | } 83 | } 84 | ``` 85 | 86 | Nie wszystkie metody dziedziczone po klasie `MonoBehaviour` są tu widoczne. Metoda `Start()` jest wywoływana wraz z inicjalizacją obiektu czyli w momencie jego tworzenia lub załadowania sceny. Natomiast `Update()` uruchamiana jest raz na każdą klatkę animacji. Jeżeli kod, który zamierzamy dodać będzie manipulował właściwościami fizycznymi obiektu (poprzez Unity physics engine) to należy ten kod umieścić wewnątrz metody `FixedUpdate()`, która uruchamiana jest docelowo ze stałą częstotliwością na sekundę, o ile maszyna zdoła wykonać taka ilość operacji. Domyślnie jest to 50 razy na sekundę, a to ustawienie możemy sprawdzic i zmienić w edytorze w menu `Edit -> Project Settings -> Time -> Fixed Timestep`. 87 | 88 | __**Listing 5**__ 89 | ```csharp 90 | public class Ball : MonoBehaviour { 91 | 92 | public float force = 10.0f; 93 | Rigidbody rb; 94 | 95 | void Start() 96 | { 97 | rb = GetComponent(); 98 | } 99 | 100 | void FixedUpdate() 101 | { 102 | // składowa y wektora prędkości 103 | if(rb.velocity.y == 0) 104 | { 105 | // działamy siłą na ciało A :) 106 | rb.AddForce(Vector3.up * force, ForceMode.Impulse); 107 | } 108 | } 109 | } 110 | ``` 111 | 112 | Klasą bazową dla wszystkich klas API Unity jest klasa [Object](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Object.html). Zachęcam do przeczytania krótkiego opisu pod adresem https://docs.unity3d.com/2022.3/Documentation/Manual/class-Object.html 113 | 114 | > **Klasa [Quaternion](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Quaternion.html)** 115 | > Klasa Quaternion służy do przechowywania informacji o trzech składowych obiektu opisujących jego orientację w przestrzeni trójwymiarowej. Dzięki tej klasie możemy też wyznaczać względne parametry obrotu jaki trzeba wykonać, aby obrócić obiekt do wskazanej orientacji. W panelu inspektora,kąty które widzimy w komponencie Transform podane są jako [kąty Eulera](https://pl.wikipedia.org/wiki/K%C4%85ty_Eulera), ale w skryptach powinniśmy używać metod obiektu Quaternion do manipulacji rotacją obiektów. W przeciwnym wypadku może pojawić się problem nazywany `Gimbal lock` (więcej: http://pananimator.pl/gimbal-lock/). 116 | 117 | Poniższy fragment kodu obróci obiekt przypisany do zmiennej `from` tak, aby jego wartości rotacji (orientacja) pokryły się z wartościami zapisanymi w obiekcie przypisanym do zmiennej `to`. Trzeci parametr funkcji `Quaternion.Slerp()` to procent o jaki mamy zmienić rotację. Wartości zawierają się w przedziale [0, 1]. 118 | 119 | __**Listing 6**__ 120 | ```csharp 121 | using UnityEngine; 122 | 123 | public class QuaternionRotateToPosition : MonoBehaviour 124 | { 125 | public Transform from; 126 | public Transform to; 127 | 128 | // krok rotacji, wyrazony w procentach, o jaki zostanie wykonana rotacja 129 | // w każdej klatce animacji 130 | private float percentage = 0.01f; 131 | 132 | void Update() 133 | { 134 | transform.rotation = Quaternion.Slerp(from.rotation, to.rotation, percentage); 135 | } 136 | } 137 | ``` 138 | 139 | Manual opisujący więcej przykładów dostępny pod linkiem: https://docs.unity3d.com/2022.3/Documentation/Manual/class-Quaternion.html 140 | 141 | 142 | Możemy również wykonywać rotacje obiektów poprzez komponent `Transform` i metody `Transform.Rotate()` oraz `Tranform.RotateAround()`, które również operują na obiektach `Quaternion`. Wartości obrotu podawane są w stopniach. Parametrem, który jeszcze musimy przekazać jest parametr `realtiveTo`,który określa czy obrót będzie odbywał się względem lokalnych czy globalnych koordynatów (`Space.Self, Space.World`). 143 | 144 | __**Listing 7**__ 145 | ```csharp 146 | public void Update { 147 | cube1.transform.Rotate(xAngle, yAngle, zAngle, Space.Self); 148 | cube2.transform.Rotate(xAngle, yAngle, zAngle, Space.World); 149 | } 150 | ``` 151 | > **Klasa [Time](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Time.html)** 152 | > Klasa ta pozwala na pracę z elementami gier związanymi z czasem. Dzięki tej klasie możemy również wyznaczać czas jaki minął od momentu wygenerowania ostatniej klatki animacji. 153 | 154 | Opisane w manualu trzy najważniejsze składowe klasy `Time`: 155 | * `Time.time` - zwraca czas, który minął od momentu uruchomienia projektu (gry). 156 | 157 | * `Time.deltaTime` - zwraca czas w sekundach jaki upłynął od momentu wygenerowania poprzedniej klatki. Wykorzystywany najczęściej aby przekształcenia, które chcemy wykonać dla naszego obiektu (ruch, rotacja) odbywały się proporcjonalnie do upływającego czasu, lub inaczej ujmując, proporcjonalnie do ilości klatek, które są generowane na sekundę. 158 | 159 | * `Time.timeScale` - zawiera informacje o szybkości upływu czasu. Manipulowanie tym parametrem pozwala na tworzenie efektów fast-forward lub slow-motion. 160 | 161 | 162 | Rozpatrzmy poniższy przykład (prosto z manuala Unity): 163 | 164 | __**Listing 8**__ 165 | ```csharp 166 | using UnityEngine; 167 | using System.Collections; 168 | 169 | public class ExampleScript : MonoBehaviour { 170 | public float distancePerFrame; 171 | 172 | void Update() { 173 | transform.Translate(0, 0, distancePerFrame); 174 | } 175 | } 176 | //oraz 177 | using UnityEngine; 178 | using System.Collections; 179 | 180 | public class ExampleScript : MonoBehaviour { 181 | public float distancePerSecond; 182 | 183 | void Update() { 184 | transform.Translate(0, 0, distancePerSecond * Time.deltaTime); 185 | } 186 | } 187 | ``` 188 | 189 | Oba przypadki różnią się znacznie efektem, który osiągniemy. W pierwszym przypadku każde wywołanie metody `Update()` spowoduje przesunięcie obiektu wzdłóż osi `z` o określoną ilość pikseli i ta prędkość (w czasie), będzie bezpośrednio zależała od wartości FPS. Drugi przykład to ruch, który odbywa się ze stałą wielkością przesunięcia na sekundę - co klatkę proporcjonalnie do FPS. 190 | 191 | Aby dodać nieco interakcji do naszego projektu i ćwiczeń poniżej zaprezentowany został przykład poruszania obiektem w płaszczyźnie `x` i `z` za pomocą klawiatury (klawisze WASD). W zależności czy komponent `Rigidbody` będzie posiadał aktywną opcję `useGravity` czy nie, będziemy mogli poruszać się po platformie lub również poza nią, bez uwzględniania sił grawitacji. 192 | 193 | __**Listing 9**__ 194 | ```csharp 195 | using UnityEngine; 196 | 197 | public class MovePlayer : MonoBehaviour 198 | { 199 | public float speed = 2.0f; 200 | Rigidbody rb; 201 | 202 | void Start() 203 | { 204 | rb = GetComponent(); 205 | } 206 | 207 | void Update() 208 | { 209 | 210 | } 211 | void FixedUpdate() 212 | { 213 | // pobranie wartości zmiany pozycji w danej osi 214 | // wartości są z zakresu [-1, 1] 215 | float mH = Input.GetAxis("Horizontal"); 216 | float mV = Input.GetAxis("Vertical"); 217 | 218 | // tworzymy wektor prędkości 219 | Vector3 velocity = new Vector3(mH, 0, mV); 220 | velocity = velocity.normalized * speed * Time.deltaTime; 221 | // wykonujemy przesunięcie Rigidbody z uwzględnieniem sił fizycznych 222 | rb.MovePosition(transform.position + velocity); 223 | } 224 | } 225 | ``` 226 | Aby kod poprawnie działał dla wybranego obiektu należy dołączyć do niego komponent ```Rigidbody```. Bardziej szczegółowo sterowaniem zajmiemy się na kolejnym laboratorium. 227 | 228 | 229 | 230 | 231 | ## Zadania 232 | 233 | >W celu ujednolicenia sposobu przechowywania własnych skryptów w folderze Assets utwórz folder scripts i tam umieszczaj własne skrypty. Dla każdego zadania (poza zadaniem 1) stwórz nową scenę o nazwie równoważnej nazwie zadania (np. zadania1 lub zadanie_1). Jeżeli dla obiektów będących przedmiotem zadania zostaną stworzone prefabrykaty (zalecane) to umieszczanie obiektów na kolejnych scenach będzie dużo łatwiejsze. Warto też wykorzystać opcję `Save as...` i zapisać scenę, na której trzeba bazować, pod nową nazwą. 234 | 235 | **Zadanie 1** 236 | Przeczytaj artykuł [https://docs.unity3d.com/Manual/2022.3/Documentation/VectorCookbook.html](https://docs.unity3d.com/2022.3/Documentation/Manual/VectorCookbook.html), który przypomni Ci zagadnienia związane z pojęciem wektorów odległości i sposobu na wykorzystanie tej wiedzy w środowisku Unity. 237 | 238 | **Zadanie 2** 239 | Stwórz nową scenę. Dodaj do niej obiekt typu Cube o wymiarach (2, 1, 1). Napisz skrypt, z publicznym polem speed (float), który będzie przemieszczał obiekt wzdłóż osi x o 10 jednostek i w momencie wykonania takiego przesunięcia będzie wykonywał ruch powrotny. 240 | 241 | **Zadanie 3** 242 | Do obiektu Cube z zadania 2 dodaj jakiś element, który będzie wskazywał na jej kierunek `forward`. Rozbuduj skrypt z zadania 2 (ale zapisz wszystko w nowym skrypcie), tak aby obiekt poruszał się 'po kwadracie' o boku 10 jednostek i docierając do wierzchołka wykonywał obrót o 90 stopni w kierunku kolejnego ruchu. 243 | 244 | **Zadanie 4** 245 | Dodaj nową scenę do swojego projektu. Stwórz obiekt, który będzie obiektem gracza (cube, sphere, cokolwiek). Dodaj do sceny płaszczyznę o wymiarach 20x20 jednostek. Dodaj możliwość przemieszczania obiektu po płaszczyźnie. 246 | 247 | **Zadanie 5** 248 | Wykorzystując możliwość dodawania obiektów czasie wykonania (zobacz: https://docs.unity3d.com/2022.3/Documentation/Manual/InstantiatingPrefabs.html) stwórz nową scenę a w niej: 249 | * dodaj płaszczyznę o wymiarach 10x10 250 | * w momencie uruchomienia trybu play generuj 10 obiektów typu Cube, które umieszczaj losowo na płaszczyźnie, ale tak, żeby w danym miejscu nie znalazł się więcej niż jeden obiekt. 251 | 252 | **Zadanie 6** 253 | Korzystając z przykładu w dokumentacji UNITY dostępnej pod adresem https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Mathf.SmoothDamp.html zaimplementuj go dla dwóch obiektów na swojej scenie i przetestuj zmieniając położenie w trybie `game` obiektu, który 'jest śledzony'. Przetestuj również metodę `Mathf.Lerp`. 254 | -------------------------------------------------------------------------------- /lab_04/character_inspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_04/character_inspector.png -------------------------------------------------------------------------------- /lab_04/fps_camera_placement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_04/fps_camera_placement.png -------------------------------------------------------------------------------- /lab_04/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 4 - Współprogramy oraz komponent CharacterController. 2 | 3 | 4 | ## 1. Coroutine (współprogram) 5 | 6 | Coroutine to byt zbliżony do funkcji, który posiada możliwość wstrzymania swojego wykonania, a następnie powrót do wykonania w miejscu, w którym zostało ono zakończone. W przypadku Unity tym punktem będzie klatka animacji. Aby zrozumieć lepiej ten koncept prześledź przykład poniżej. 7 | 8 | W skrypcie generowane jest 10 losowych pozycji obiektu, a następnie poprzez coroutine co określony odstęp czasu (domyślnie 3 sekundy) generowany jest kolejny obiekt i umieszczany w przestrzeni. Po dodaniu ostatniego obiektu współprogram jest zatrzymywany. 9 | 10 | > **Listing 1** 11 | ```csharp 12 | using System; 13 | using System.Collections; 14 | using System.Collections.Generic; 15 | using System.Linq; 16 | using UnityEngine; 17 | 18 | public class RandomCubesGenerator : MonoBehaviour 19 | { 20 | List positions = new List(); 21 | public float delay = 3.0f; 22 | int objectCounter = 0; 23 | // obiekt do generowania 24 | public GameObject block; 25 | 26 | void Start() 27 | { 28 | // w momecie uruchomienia generuje 10 kostek w losowych miejscach 29 | List pozycje_x = new List(Enumerable.Range(0, 20).OrderBy(x => Guid.NewGuid()).Take(10)); 30 | List pozycje_z = new List(Enumerable.Range(0, 20).OrderBy(x => Guid.NewGuid()).Take(10)); 31 | 32 | for(int i=0; i<10; i++) 33 | { 34 | this.positions.Add(new Vector3(pozycje_x[i], 5, pozycje_z[i])); 35 | } 36 | foreach(Vector3 elem in positions){ 37 | Debug.Log(elem); 38 | } 39 | // uruchamiamy coroutine 40 | StartCoroutine(GenerujObiekt()); 41 | } 42 | 43 | void Update() 44 | { 45 | 46 | } 47 | 48 | IEnumerator GenerujObiekt() 49 | { 50 | Debug.Log("wywołano coroutine"); 51 | foreach(Vector3 pos in positions) 52 | { 53 | Instantiate(this.block, this.positions.ElementAt(this.objectCounter++), Quaternion.identity); 54 | yield return new WaitForSeconds(this.delay); 55 | } 56 | // zatrzymujemy coroutine 57 | StopCoroutine(GenerujObiekt()); 58 | } 59 | } 60 | 61 | ``` 62 | W powyższym przykładzie zastosowana została funkcja ```WaitForSeconds()```, którą poprzedza zapis ```yield return```. To właśnie w momencie tego wywołania coroutine zostaje wstrzymana i od tego miejsca później wznowiona. Dzięki tej funkcji możemy również wywoływać kod częściej niż raz na klatkę. Domyślnie współprogram jest wznawiany w kolejnej ramce animacji jeżeli umieścimy w niej kod ```yield return null```, co pozwala na synchroniczną pracę współprogramów wraz z kolejnym wywołaniem funkcji ```Update()```. 63 | 64 | Przykład z manuala Unity pokazuje jak zsynchronizować zmianę właściwości koloru z kolejnym wywołaniem klatek animacji. W standardowej funkcji cały kod w niej zawarty zostałby wykonany w całości (atomowo) i tylko raz. Oczywiście moglibyśmy umieścić kod w funkcji ```Update()``` i monitorować upływający czas lub ilość klatek, które zostały wygenerowane od rozpoczęcia wywołania funkcji. 65 | 66 | > **Listing 2** 67 | ```csharp 68 | IEnumerator Fade() 69 | { 70 | for (float ft = 1f; ft >= 0; ft -= 0.1f) 71 | { 72 | Color c = renderer.material.color; 73 | c.a = ft; 74 | renderer.material.color = c; 75 | yield return null; 76 | } 77 | } 78 | ``` 79 | 80 | Więcej o coroutines można przeczytać pod adresem https://docs.unity3d.com/2022.3/Documentation/Manual/Coroutines.html. 81 | W Internecie można również natkąć się na wiele negatywnych komentarzy na temat współprogramów i powodu, dla którego pojawiają się w Unity (brak await/async w momencie kiedy rozpoczęto prace nad silnikiem Unity). Skoro jednak ich obecność w API Unity jest zaznaczona w dokumentacji oraz na schemacie przepływu (patrz link poniżej), ich użycie wydaje się więc wolnym wyborem dewelopera. 82 | 83 | > W manualu Unity znajduje się bardzo przydatny schemat kolejności wywołań poszczególnych zdarzeń silnika Unity, którego poznanie znacznie ułatwia podjęcie decyzji gdzie umieścić dany fragment kodu. Link: https://docs.unity3d.com/2022.3/Documentation/Manual/ExecutionOrder.html 84 | 85 | 86 | ## 2. Komponent [CharacterController](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/CharacterController.html) 87 | 88 | Jest to komponent, który możemy wykorzystać aby obsłużyć ruch obiektu w świecie Unity z już zaimplementowanymi pewnymi funkcjami i założeniami, które często musimy dla poruszającej się postaci zakodować. Komponent ten służy do poruszania obiektami bez wykorzystania komponentu Rigidbody ale z uwzględnieniem wszelkich colliderów. Komponent ten posiada dołączony collider w postaci kapsuły o wysokości 2 (co oddaje mniej więcej wielkość postaci ludzkiej) i promieniu 0.5. Te parametry można zmienić poprzez okno inspektora lub z poziomu skryptu. 89 | 90 | ![CharacterController in inspector](character_inspector.png) 91 | Do komponentu dodano również kilka modyfikowalnych właściwości: 92 | * **Slope limit** - maksymalny kąt nachylenia jaki poruszający się obiekt jest w stanie pokonać, 93 | * **Step Offset** - maksymalna wysokość schodka od podłoża (na którym aktualnie znajduje się poruszany obiekt) jaką można pokonać, 94 | * **Skin Width** - wielkość jaką collidery (postaci i inny, który jest akurat w stanie kolizji z postacią) mogą penetrować swoje granice. Zbyt niskie wartości mogą powodować, że postać będzie "utykać" przy zderzeniach z niektórymi coliderami. 95 | * **Min Move Distance** - minimalny dystans o jaki będzie się przemieszczał obiekt, jeżeli wartość przemieszczenia jest mniejsza, obiekt nie wykona ruchu. Może to zapobiegać efektowi drgania postaci. 96 | 97 | Na obiekt kontrolowany przez ten komponent nie działają siły fizyczne i obiekt nie będzie też działał na inne obiekty np. odpychając je. Można jednak dodać takie zachowanie poprzez implementację w metodzie ```OnControllerColliderHit()``` 98 | 99 | W [manualu](https://docs.unity3d.com/2022.3/Documentation/Manual/class-CharacterController.html) można znaleźć kilka wskazówek jak dostosować parametry komponentu do własnych potrzeb. 100 | 101 | Podpięcie tego komponentu nie oznacza, że nasza postać (obiekt) będzie od razu sie poruszał poprzez wykorzystanie domyślnych kontrolerów. Musimy to samodzielnie zaprogramować. Ruch odbywa się poprzez wywołanie funkcji ```Move()``` i przekazanie obiektu ```Vector3``` jako argumentu określającego kolejną pozycję. 102 | 103 | 104 | 105 | **Zadanie 1** 106 | Wykorzystaj kod z ```listingu 1``` i zmodyfikuj go tak, aby możliwe było: 107 | * określenie w inspektorze ilości obiektów losowych do wegenerowania, 108 | * pozycje ```x``` oraz ```z``` były pobierane adekwatnie dla obiektu platformy, do której skrypt jest dołączany (zakładamy, że tak będzie), 109 | > Wskazówka: https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Bounds.html 110 | * dodaj do swojego projektu nowe materiały, tak, aby było 5 różnych do wykorzystania i przydzielaj losowo materiał w trakcie tworzenia nowego obiektu. 111 | 112 | **Zadanie 2** 113 | Stwórz nową scenę i zbuduj w niej testowy poziom wykorzystując ProBuilder. Stwórz podejścia o różnym kącie nachylenia, schody i ściany. Dodaj dowolny model postaci (może to być dość prosta bryła) i wykorzystaj przykładową implementację ruchu z wykorzystaniem ```CharacterController``` z dokumentacji Unity ([tu](https://docs.unity3d.com/ScriptReference/2022.3/Documentation/CharacterController.Move.html)). Przetestuj poziom (aktualnie ustawiając kamerę tak, żeby obejmowała cały poziom) i ewentualnie dostosuj parametry komponentu jeżeli nie można pokonać niektórych przeszkód (wzniesienia, schody). 114 | 115 | **Zadanie 3** 116 | Podepnij kamerę pod postać tak aby była jego obiektem potomnym i ponownie sprawdź działanie programu. Może to być widok FPP lub TPP. 117 | 118 | ## 3. Wykorzystanie komponentu CharacterController w grze typu FPS 119 | 120 | Wykorzystanie przykładowej implementacji nie daje dobrych efektów. Poniżej oryginalna (prawie) postać przykładowego kodu wykorzystania funkcji ```CharacterController.Move()```. 121 | 122 | > **Listing 3** 123 | ```csharp 124 | using System.Collections; 125 | using System.Collections.Generic; 126 | using UnityEngine; 127 | 128 | public class MoveWithCharacterController : MonoBehaviour 129 | { 130 | private CharacterController controller; 131 | private Vector3 playerVelocity; 132 | private bool groundedPlayer; 133 | private float playerSpeed = 2.0f; 134 | private float jumpHeight = 1.0f; 135 | private float gravityValue = -9.81f; 136 | 137 | private void Start() 138 | { 139 | // zakładamy, że komponent CharacterController jest już podpięty pod obiekt 140 | controller = GetComponent(); 141 | } 142 | 143 | void Update() 144 | { 145 | groundedPlayer = controller.isGrounded; 146 | if (groundedPlayer && playerVelocity.y < 0) 147 | { 148 | playerVelocity.y = 0f; 149 | } 150 | 151 | Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); 152 | controller.Move(move * Time.deltaTime * playerSpeed); 153 | 154 | if (move != Vector3.zero) 155 | { 156 | gameObject.transform.forward = move; 157 | } 158 | 159 | // zmienia wysokość postaci. 160 | if (Input.GetButtonDown("Jump") && groundedPlayer) 161 | { 162 | playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue); 163 | } 164 | 165 | playerVelocity.y += gravityValue * Time.deltaTime; 166 | controller.Move(playerVelocity * Time.deltaTime); 167 | } 168 | } 169 | ``` 170 | Dodajmy możliwość sterowania postacią za pomocą myszki. Mysz może poruszać się w obu osiach, ale dla obu osi implementacja będzie nieco inna. **Ruch w osi ```X``` będzie obracał obiekt wokół osi ```Y``` a ruch myszą w osi ```Y``` będzie oznaczał obracanie samej kamery, która jest do obiektu gracza podpięta jako obiekt potomny - tym razem wokół osi X**. 171 | 172 | Kamerę powinniśmy umieścić gdzieś w okolicach "oczu" gracza lub innej postacji, ale tak, aby kamera nie była powyżej lub poniżej samej bryły gracza, co mogłoby spowodować jej przenikanie przez obiekty otoczenia. Przykładowe umieszczenie kamery na zrzucie poniżej. 173 | 174 | ![camera placement](fps_camera_placement.png) 175 | 176 | 177 | Rozpocznijmy z prostym skryptem. 178 | > **Listing 4** 179 | 180 | ```csharp 181 | using System.Collections; 182 | using System.Collections.Generic; 183 | using UnityEngine; 184 | 185 | public class LookAround : MonoBehaviour 186 | { 187 | // ruch wokół osi Y będzie wykonywany na obiekcie gracza, więc 188 | // potrzebna nam referencja do niego (konkretnie jego komponentu Transform) 189 | public Transform player; 190 | void Start() 191 | { 192 | // zablokowanie kursora na środku ekranu, oraz ukrycie kursora 193 | // aby w UnityEditor ponownie pojawił się kursor (właściwie deaktywowac kursor w trybie play) 194 | // wciskamy klawisz ESC 195 | Cursor.lockState = CursorLockMode.Locked; 196 | } 197 | 198 | // Update is called once per frame 199 | void Update() 200 | { 201 | // pobieramy wartości dla obu osi ruchu myszy 202 | float mouseXMove = Input.GetAxis("Mouse X") * Time.deltaTime; 203 | float mouseYMove = Input.GetAxis("Mouse Y") * Time.deltaTime; 204 | 205 | // wykonujemy rotację wokół osi Y 206 | player.Rotate(Vector3.up * mouseXMove); 207 | 208 | // a dla osi X obracamy kamerę 209 | transform.Rotate(new Vector3(mouseYMove, 0f, 0f), Space.Self); 210 | } 211 | } 212 | ``` 213 | 214 | Po podpięciu skryptu pod kamerę i dodaniu referencji do naszego gracza możemy uruchomić projekt. Po wykonaniu ruchu myszą widać bardzo niewielki ruch kamery. Taka sytuacja wynika z faktu, że wartości ```Mouse X``` oraz ```Mouse Y``` zwracają wartości dość małe, zależne od szybkości z jaką przemieszcza się kursor. Jest to odległość jaką pokonał kursor w trakcie czasu wyrenderowania jednej klatki animacji. Musimy więc zwiększyć te wartości. Najbardziej optymalnym podejściem będzie ustawienie go jako modyfikowalnego parametru. Dodatkowo można zaobserwować zjawisko inwersji ruchu myszy dla osi Y. Możemy to zmienić poprzez zmianę znaku przekazywanej wartości ```Mouse Y```. 215 | 216 | 217 | > **Listing 5 - zmodyfikowana wersja skryptu.** 218 | 219 | ```csharp 220 | using System.Collections; 221 | using System.Collections.Generic; 222 | using UnityEngine; 223 | 224 | public class LookAround : MonoBehaviour 225 | { 226 | // ruch wokół osi Y będzie wykonywany na obiekcie gracza, więc 227 | // potrzebna nam referencja do niego (konkretnie jego komponentu Transform) 228 | public Transform player; 229 | 230 | public float sensitivity = 200f; 231 | 232 | void Start() 233 | { 234 | // zablokowanie kursora na środku ekranu, oraz ukrycie kursora 235 | Cursor.lockState = CursorLockMode.Locked; 236 | } 237 | 238 | // Update is called once per frame 239 | void Update() 240 | { 241 | // pobieramy wartości dla obu osi ruchu myszy 242 | float mouseXMove = Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime; 243 | float mouseYMove = Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime; 244 | 245 | // wykonujemy rotację wokół osi Y 246 | player.Rotate(Vector3.up * mouseXMove); 247 | 248 | // a dla osi X obracamy kamerę dla lokalnych koordynatów 249 | // -mouseYMove aby uniknąć ofektu mouse inverse 250 | transform.Rotate(new Vector3(-mouseYMove, 0f, 0f), Space.Self); 251 | 252 | } 253 | } 254 | ``` 255 | 256 | Powinniśmy również nadać trochę realizmu i ograniczyć obrót wokół osi X, ale to jest już przedmiotem zadania do samodzielnego wykonania. 257 | 258 | Poruszanie się gracza aktualnie nie działa prawidłowo, a przynajmniej nie jak w większości gier typu FPS. Czas na kilka zmian w skrypcie poruszającym naszym graczem. 259 | 260 | > **Listing 6 - zmodyfikowana postać skryptu 261 | ```MoveWithCharacterController```** 262 | 263 | ```csharp 264 | using System.Collections; 265 | using System.Collections.Generic; 266 | using UnityEngine; 267 | 268 | public class MoveWithCharacterController : MonoBehaviour 269 | { 270 | private CharacterController controller; 271 | private Vector3 playerVelocity; 272 | private bool groundedPlayer; 273 | private float playerSpeed = 10.0f; 274 | private float jumpHeight = 1.0f; 275 | private float gravityValue = -9.81f; 276 | 277 | private void Start() 278 | { 279 | // zakładamy, że komponent CharacterController jest już podpięty pod obiekt 280 | controller = GetComponent(); 281 | } 282 | 283 | void Update() 284 | { 285 | // wyciągamy wartości, aby możliwe było ich efektywniejsze wykorzystanie w funkcji 286 | float moveX = Input.GetAxis("Horizontal"); 287 | float moveZ = Input.GetAxis("Vertical"); 288 | 289 | // dzięki parametrowi playerGrounded możemy dodać zachowania, które będą 290 | // mogły być uruchomione dla każdego z dwóch stanów 291 | groundedPlayer = controller.isGrounded; 292 | if (groundedPlayer && playerVelocity.y < 0) 293 | { 294 | playerVelocity.y = 0f; 295 | } 296 | 297 | // zmieniamy sposób poruszania się postaci 298 | // Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); 299 | // transform.right odpowiada za ruch wzdłuż osi x (pamiętajmy, że wartości będą zarówno dodatnie 300 | // jak i ujemne, a punkt (0,0) jest na środku ekranu) a transform.forward za ruch wzdłóż osi z. 301 | Vector3 move = transform.right * moveX + transform.forward * moveZ; 302 | controller.Move(move * Time.deltaTime * playerSpeed); 303 | 304 | // to już nam potrzebne nie będzie 305 | //if (move != Vector3.zero) 306 | //{ 307 | // gameObject.transform.forward = move; 308 | //} 309 | 310 | if (Input.GetButtonDown("Jump") && groundedPlayer) 311 | { 312 | // wzór na siłę 313 | playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue); 314 | } 315 | 316 | // prędkość swobodnego opadania zgodnie ze wzorem y = (1/2 * g) * t-kwadrat 317 | // okazuje się, że jest to zbyt wolne opadanie, więc zastosowano g * t-kwadrat 318 | playerVelocity.y += gravityValue * Time.deltaTime; 319 | controller.Move(playerVelocity * Time.deltaTime); 320 | } 321 | } 322 | ``` 323 | 324 | **Zadanie 4** 325 | Dodaj do skryptu ```LookAround``` ograniczenie obracania kamery do -90 i +90 stopni góra-dół (sprawdź metodę `Mathf.Clamp` (https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Mathf.Clamp.html) z API Unity). -------------------------------------------------------------------------------- /lab_05/box_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_05/box_components.png -------------------------------------------------------------------------------- /lab_05/elevator_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_05/elevator_one.png -------------------------------------------------------------------------------- /lab_05/physic_material.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_05/physic_material.png -------------------------------------------------------------------------------- /lab_05/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 5 - Wykrywanie i obsługa kolizji. 2 | 3 | Wykrywanie kolizji oraz odpowiednie reagowanie na zdarzenia przez nie generowane jest jednym z głównych elementów, który daje wrażenie interakcji elementów gry między sobą często w sposób naśladujący zachowanie w świecie rzeczywistym. 4 | Każdy kto spędził trochę czasu nad implementacją kolizji w swoim projekcie na pewno wie, że nie jest to sprawa prosta i sam silnik, nawet najlepszy, nie dostarcza wszystkich rozwiązań out of the box. W przypadku Unity, też można się szybko przekonać, że teoria a praktyka to różna para kaloszy. 5 | 6 | ## 1. Omówienie dostępnych koliderów i najważniejszych ich cech. 7 | 8 | ### 1.1 [Mesh collider](https://docs.unity3d.com/2022.3/Documentation/Manual/class-MeshCollider.html) - kolidery siatki. 9 | 10 | Są to kolidery budowane na podstawie siatki obiektu i pozwalają na precyzyjne wykrywanie kolizji jednak z dużym obciążeniem obliczeniowym oraz z pewnymi ograniczeniami. W trybie 2D odpowiednikiem takich zderzaczy jest Polygon Collider 2D. 11 | Ograniczeniem jest fakt, że dwa Mesh Collidery, które się zderzają nie generują żadnego zdarzenia, co można w pewnych przypadkach obejść poprzez zaznaczenie opcji ```Convex```, która upraszcza kształt kolidera. Dodatkową zaletą jest możliwość używania wypukłego kolidera jako wyzwalacza zdarzeń kolizji. Ograniczenie to wynika z obsługi tylko wypukłych koliderów przez silnik fizyczny Unity. Zalecane jest też niemodyfikowanie kształtów takich koliderów w trakcie wykonania, gdyż ma to znaczny wpływ na spadek wydajności. W większości przypadków dużo lepszym pomysłem jest zbudowanie kolidera z prymitywnych koliderów (cube, sphere, capsule, itp.). 12 | 13 | ### 1.2 Zderzacze i Rigidbody. 14 | 15 | Kolizje obsługiwane przez obiekty z komponentem Rigidbody są przykładem wykorzystania **koliderów dynamicznych**. Wymagają znacznie więcej mocy obliczeniowej, gdyż są przeliczane każdorazowo gdy zostanie wywołana metoda ```FixedUpdate``` (z reguły rzadziej niż ```Update```). **Statyczne kolidery** to takie, które wciąż obsługują kolizje, ale zazwyczaj nie zmieniają swojego położenia w trakcie gry. Są to obiekty bez komponentu Rigidbody. 16 | 17 | Kolidery z komponentem `Rigidbody` oprócz zgłaszania zdarzeń kolizji są elementami, które oddziałują i na które działają siły fizyczne. Wyjątkiem są obiekty z komponentem Rigidbody w trybie kinematycznym (```isKinematic``` z wartością ```true```), które są najczęściej "poruszane" z wykorzystaniem skryptów i nie reagują na zdarzenia fizyczne jak obiekty `Rigidbody` bez aktywnego trybu kinematycznego. Jednak takie obiekty wciąż oddziałują fizycznie na inne obiekty `Rigidbody`. 18 | 19 | ### 1.3 Materiały fizyczne. ([Physic Material](https://docs.unity3d.com/2022.3/Documentation/Manual/class-PhysicMaterial.html) oraz [Physics Material 2D](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/PhysicsMaterial2D.html)) 20 | 21 | Materiały fizyczne również wpływają na obsługę kolizji dwóch obiektów. 22 | 23 | ![physic material](physic_material.png) 24 | > Rys 1. Dostępne parametry fizycznych materiałów. 25 | 26 | Parametry te mają wpływ na zachowanie obiektu (precyzyjniej kolidera), zarówno w stanie spoczynku (tarcie statyczne) jak i w trakcie ruchu (tarcie dynamiczne). Oprócz tarcia można również określić sprężystość, której zachowanie w przypadku kolizji dwóch koliderów wyposażonych w materiał fizyczny można dodatkowo sprecyzować parametrami ```Friction Combine``` oraz ```Bounce Combine```. Po więcej szczegółów i precyzyjny opis odsyłam do manuala: [Physic material](https://docs.unity3d.com/2022.3/Documentation/Manual/class-PhysicMaterial.html). 27 | 28 | 29 | ### 1.4 Zdarzenia wywoływane przez kolidery. 30 | 31 | Istnieją trzy główne zdarzenia, które są zgłaszane przez kolidery. 32 | * OnCollisionEnter([Collision](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Collision.html)) - zgłaszane kiedy kontakt zostanie wykryty po raz pierwszy (poprzez aktualizację w silniku fizycznym), zgłaszane tylko raz, 33 | * OnCollisionStay([Collision](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Collision.html)) - zgłaszane kiedy po wykryciu kontaktu oba kolidery wciąż pozostają w kontakcie, zgłaszane co klatkę, 34 | * OnCollisionExit([Collision](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Collision.html)) - zgłaszane kiedy kontakt między koliderami się zakończy, zgłaszane raz. 35 | 36 | Klasa ```Collision``` pozwala oprócz określenia kolidera, który wywołał kolizję również na wykorzystanie większej ilości szczegółów takich jak ilość punktów kontaktu, punkty kontaktu oraz prędkość zderzenia co daje dodatkowe możliwości obsługi zderzeń. 37 | 38 | Jeżeli kolider zostanie określony jako wyzwalacz (poprzez ustawienie ```isTrigger``` na ```true```) będzie to oznaczało, że przy kontakcie innych koliderów generowane będą zdarzenia kolizji, ale obiekty nie będą blokowane przez ten kolider. Korzystanie z takiego kolidera wymaga wykorzystania poniższych metod: 39 | 40 | * OnTriggerEnter([Collider](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Collider.html)) - zgłaszane kiedy kontakt zostanie wykryty po raz pierwszy (poprzez aktualizację w silniku fizycznym), zgłaszane tylko raz 41 | * OnTriggerStay([Collider](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Collider.html)) - zgłaszane kiedy po wykryciu kontaktu oba kolidery wciąż pozostają w kontakcie, zgłaszane co klatkę 42 | * OnTriggerExit([Collider](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Collider.html)) - zgłaszane kiedy kontakt między koliderami się zakończy, zgłaszane raz. 43 | 44 | Zwróć uwagę na zmianę argumentu tych zdarzeń - tym razem jest to klasa ```Collider```. 45 | 46 | ### 1.5 Interakcje koliderów 47 | 48 | 1. **Character controller** - ten komponent posiada wbudowany kolider w kształcie kapsuły, który został zaprezentowany w lab 4. Kolider ten "zderza" się ze statycznymi koliderami i dzięki temu może poruszać się dość sprawnie po świecie w Unity. Ten kolider może również oddziaływać na obiekty z komponentem Rigidbody, ale wymaga dodania stosownego kodu. 49 | 50 | **_Listing 1_** - zmodyfikowana postać skryptu MoveWithCharacterController z lab 4 z wykorzystaniem fragmentu z dokumentacji (https://docs.unity3d.com/ScriptReference/2022.3/Documentation/CharacterController.OnControllerColliderHit.html) 51 | 52 | ```csharp 53 | using System.Collections; 54 | using System.Collections.Generic; 55 | using UnityEngine; 56 | 57 | public class MoveWithCharacterController : MonoBehaviour 58 | { 59 | private CharacterController controller; 60 | private Vector3 playerVelocity; 61 | private bool groundedPlayer; 62 | private float playerSpeed = 8.0f; 63 | private float jumpHeight = 1.0f; 64 | private float gravityValue = -9.81f; 65 | private float pushPower = 2.0f; 66 | 67 | private void Start() 68 | { 69 | // zakładamy, że komponent CharacterController jest już podpięty pod obiekt 70 | controller = GetComponent(); 71 | } 72 | 73 | void Update() 74 | { 75 | float moveX = Input.GetAxis("Horizontal"); 76 | float moveZ = Input.GetAxis("Vertical"); 77 | 78 | groundedPlayer = controller.isGrounded; 79 | if (groundedPlayer && playerVelocity.y < 0) 80 | { 81 | playerVelocity.y = -2f; 82 | } 83 | 84 | Vector3 move = transform.right * moveX + transform.forward * moveZ; 85 | controller.Move(move * Time.deltaTime * playerSpeed); 86 | 87 | if (Input.GetButtonDown("Jump") && groundedPlayer) 88 | { 89 | playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue); 90 | } 91 | 92 | // zgodnie ze wzorem y = (1/2 * g) * t-kwadrat, ale jednak w trybie play 93 | // okazuje się, że jest to zbyt wolne opadanie, więc zastosowano g * t-kwadrat 94 | playerVelocity.y += gravityValue * Time.deltaTime; 95 | controller.Move(playerVelocity * Time.deltaTime); 96 | } 97 | 98 | private void OnControllerColliderHit(ControllerColliderHit hit) 99 | { 100 | Rigidbody body = hit.collider.attachedRigidbody; 101 | 102 | // no rigidbody 103 | if (body == null || body.isKinematic) 104 | { 105 | return; 106 | } 107 | 108 | // We dont want to push objects below us 109 | if (hit.moveDirection.y < -0.3) 110 | { 111 | return; 112 | } 113 | 114 | // Calculate push direction from move direction, 115 | // we only push objects to the sides never up and down 116 | Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z); 117 | 118 | // If you know how fast your character is trying to move, 119 | // then you can also multiply the push velocity by that. 120 | 121 | // Apply the push 122 | body.velocity = pushDir * pushPower; 123 | } 124 | } 125 | ``` 126 | 127 | Przy takim zastosowaniu należy pamiętać o umieszczeniu obsługi zderzeń w odpowiednim miejscu metody `OnControllerColliderHit` w zależności czy inny kolider posiada podpięty komponent Rigidbody czy nie. Oczywiście powinniśmy unikać sytuacji, w której obsługa kolizji jest umieszczona w całości po stronie Character Controllera, dużo lepszym pomysłem jest izolowanie tego kodu w skryptach podpinanych pod inne niż gracz obiekty gry. 128 | 129 | 2. **Kolidery statyczne** 130 | 131 | Obiekt posiadający kolider ale bez Rigidbody, który wykrywa zderzenia z innymi koliderami również Rigidbody, ale nie oddziałują na nie siły tych zderzeń. Warto pamiętać o unikaniu przemieszczania i zmiany skali takich obiektów w czasie gry o ile to możliwe. 132 | 133 | 3. **Kolidery Rigidbody** 134 | 135 | Najczęściej wykorzystywany komponent jeżeli chcemy minimalnym nakładem pracy wykorzystać silnik fizyczny Unity. Kolidery, które występują razem z Rigidbidy zderzają się z innymi ciałami sztywnymi oraz koliderami statycznymi. 136 | 137 | 4. **Kolidery kinematyczne Rigidbody** 138 | 139 | Kinematyczny komponent Rigidbody wciąż może być 'sterowany' poprzez kod oddziałujący na komponent Rigidbody, ale ignorując siły fizyczne na niego działające. Taki obiekt jednak będzie oddziaływał z materiałami fizycznymi i innymi obiektami z komponentem Rigidbody. Najczęściej używa się takiej konfiguracji dla obiektów, które są przez większość czasu nieruchome, ale występuje potrzeba ich przemieszczenia dodatkowo działając siłą lub samym koliderem na inne obiekty (windy, drzwi, platformy itd.). 140 | W praktyce można również wykorzystać możliwość dynamicznego włączania i wyłączania atrybutu ```isKinematic``` w celu aktywowania lub deaktywowania oddziaływania sił fizycznych na obiekt w trakcie gry - np. symulacja działania siły wiatru w trakcie lotu, symulacja działania wybuchu na obiekt lub innych komponentów rigidbody jeżeli zaistnieje taka potrzeba. 141 | 142 | Aby się w tym wszystkim nie pogubić i dobrze zrozumieć kiedy jaki kolider zastosować (zwłaszcza dynamiczne) trzeba nieco wprawy i praktyki, ale warto mieć pod ręką tabelę, która zawiera informacje o interakcjach między koliderami: https://docs.unity3d.com/2022.3/Documentation/Manual/collider-types-interaction.html. 143 | 144 | 145 | > **Wskazówka:** Stosowanie koliderów, które są mniejszych rozmiarów niż siatka obiektu w połączeniu z materiałem fizycznym pozwala na symulację zderzenia z obiektami, które wydają się miękkie, przenikalne w pewnym stopniu. 146 | 147 | > **Wskazówka:** Ważnym aspektem jest również ustawienie parametru ```Collision Detection```, który ma wpływ na precyzję wyliczania kolizji oraz ilość cykli procesora zaangażowanych w wyliczanie kolizji. Użyj wskazówek z adresu https://docs.unity3d.com/2022.3/Documentation/Manual/class-Rigidbody.html. Zapamiętaj, że dla kinematycznych ciał sztywnych możliwe jest ustawienie wartości ```Discrete oraz Continuous Speculative```. Więcej o różnicach doczytasz [tutaj](https://docs.unity3d.com/2022.3/Documentation/Manual/ContinuousCollisionDetection.html). 148 | 149 | ### 1.6 Inne kolidery silnika Unity 150 | 151 | Silnik Unity posiada również inne kolidery, można je nazwać koliderami specjalnego przeznaczenia. Są to [Wheel Collider](https://docs.unity3d.com/2022.3/Documentation/Manual/class-WheelCollider.html) (krótki [Tutorial](https://docs.unity3d.com/2022.3/Documentation/Manual/WheelColliderTutorial.html)) oraz [Terrain Collider](https://docs.unity3d.com/2022.3/Documentation/Manual/class-TerrainCollider.html). Nie będą one omawiane w tym laboratorium, więc lekturę pozostawiam czytelnikowi. 152 | 153 | 154 | ## 2. Przykłady obsługi kolizji. 155 | 156 | Z tabelki kolizji wynika, że kolizje koliderów statycznych i rigidbody są rejestrowane, ale są jednak przypadki, w których się tak nie dzieje. 157 | Wykorzystując kontroller z listingu 1 dodajemy nowy obiekt i skrypt rejestrujący kolizję z graczem. 158 | 159 | Konfiguracja kostki, w której chcemy rejestrować zdarzenie kolizji. 160 | ![kostka](box_components.png) 161 | 162 | > Listing 2 - Skrypt CollisionDetect. 163 | ```csharp 164 | using System.Collections; 165 | using System.Collections.Generic; 166 | using UnityEngine; 167 | 168 | public class CollisionDetect : MonoBehaviour 169 | { 170 | private void OnCollisionEnter(Collision other) 171 | { 172 | if (other.gameObject.CompareTag("Player")) 173 | { 174 | Debug.Log("Player zderzył się z kostką."); 175 | } 176 | } 177 | } 178 | 179 | ``` 180 | Uruchamiamy grę, zderzamy się z kostką i ... ewidentnie z kostką się zderzamy powodując jej przemieszczanie, ale zdarzenie po stronie kostki nie jest rejestrowane. A po stronie kontrolera ? 181 | ```csharp 182 | ... 183 | private void OnControllerColliderHit(ControllerColliderHit hit) 184 | { 185 | if (hit.gameObject.name == "zolta_kostka") 186 | { 187 | Debug.Log("Wykryto kolizję kostki z Character Controller"); 188 | } 189 | ... 190 | } 191 | ... 192 | ``` 193 | Character Controller ową kolizję wykrywa i możemy ją obsłużyć. 194 | 195 | Żeby jednak nie było to wszystko takie oczywiste to nadajmy kostce jakąś prędkość, żeby pozostawała w ruchu. I usuwamy kod wykrycia kolizji z kontrolera. 196 | 197 | ```csharp 198 | using System.Collections; 199 | using System.Collections.Generic; 200 | using UnityEngine; 201 | 202 | public class CollisionDetect : MonoBehaviour 203 | { 204 | private Rigidbody _rigidbody; 205 | void Start() 206 | { 207 | _rigidbody = this.GetComponent(); 208 | } 209 | 210 | 211 | private void FixedUpdate() 212 | { 213 | _rigidbody.velocity = new Vector3(1, 0, 0); 214 | } 215 | 216 | private void OnCollisionEnter(Collision other) 217 | { 218 | if (other.gameObject.CompareTag("Player")) 219 | { 220 | Debug.Log("Player zderzył się z kostką."); 221 | } 222 | } 223 | } 224 | 225 | ``` 226 | 227 | Teraz w przypadku zderzenia gracza z kostką czasami będą się pojawiały komunikaty o wykryciu zderzenia, ale tylko jeżeli zderzamy się z kierunku zgodnego z ruchem kostki, ale przeciwnym zwrocie. Lawirowanie w dokumentacji i próba znalezienia dokładnego wytłumaczenia nie jest prosta, ale ta sytuacja związana jest z różnicą traktowania obiektów z `Rigidbody`, które są nieruchome, a tych które są w ruchu. Znowu odbywa się to w celu optymalizacji wydajności, co jednak przysparza wielu kłopotów developerom. 228 | 229 | Rozważmy teraz przykład windy pionowej, która miałaby naszego gracza wynieść do góry i rozpocząć swoje działanie po jego wejściu na powierzchnię owej windy. Skoro nasza winda będzie w stanie spoczynku dopóki na nią nie wejdziemy to wykorzystanie rozwiązania z kostką nie wchodzi w grę, chyba, że chcemy kod uruchamiający windę umieścić wewnątrz klasy `MoveWithCharacterController`, co z punktu widzenia zasad wytwarzania oprogramowania (tu akronim SOLID) nie jest dobrym pomysłem. 230 | 231 | Rozwiązanie tego problemu jest dobrym przykładem na wykorzystanie koliderów-wyzwalaczy. 232 | 233 | Budujemy platformę, która będzie naszą windą. Dodajemy kolider oraz komponent `Rigidbody`. Dodatkowo jako obiekt potomny dodajemy pusty obiekt, do którego dodajemy `BoxCollider` znajdujący się powyżej platformy. Z rozmiarem można poeksperymentować. Najważniejsze jest ustawienie opcji `isTrigger`, która nie będzie blokowała gracza, ale będzie zgłaszała zdarzenia kolizji. 234 | 235 | ![Winda pierwsza](elevator_one.png) 236 | 237 | > Listing 3 - przykładowa implementacja poruszania platformy 238 | ```csharp 239 | using System.Collections; 240 | using System.Collections.Generic; 241 | using UnityEngine; 242 | 243 | public class Elevator : MonoBehaviour 244 | { 245 | public float elevatorSpeed = 2f; 246 | private bool isRunning = false; 247 | public float distance = 6.6f; 248 | private bool isRunningUp = true; 249 | private bool isRunningDown = false; 250 | private float downPosition; 251 | private float upPosition; 252 | 253 | void Start() 254 | { 255 | upPosition = transform.position.y + distance; 256 | downPosition = transform.position.y; 257 | } 258 | 259 | void Update() 260 | { 261 | if (isRunningUp && transform.position.y >= upPosition) 262 | { 263 | isRunning = false; 264 | } 265 | else if (isRunningDown && transform.position.y <= downPosition) 266 | { 267 | isRunning = false; 268 | } 269 | 270 | if (isRunning) 271 | { 272 | Vector3 move = transform.up * elevatorSpeed * Time.deltaTime; 273 | transform.Translate(move); 274 | } 275 | } 276 | 277 | private void OnTriggerEnter (Collider other) 278 | { 279 | if (other.gameObject.CompareTag("Player")) 280 | { 281 | Debug.Log("Player wszedł na windę."); 282 | 283 | if (transform.position.y >= upPosition) 284 | { 285 | isRunningDown = true; 286 | isRunningUp = false; 287 | elevatorSpeed = -elevatorSpeed; 288 | } 289 | else if (transform.position.y <= downPosition) 290 | { 291 | isRunningUp = true; 292 | isRunningDown = false; 293 | elevatorSpeed = Mathf.Abs(elevatorSpeed); 294 | } 295 | isRunning = true; 296 | } 297 | } 298 | 299 | private void OnTriggerExit(Collider other) 300 | { 301 | if (other.gameObject.CompareTag("Player")) 302 | { 303 | Debug.Log("Player zszedł z windy."); 304 | } 305 | } 306 | } 307 | ``` 308 | 309 | > Listing 4 - inna, poprawiona wersja skryptu dla pionowej platformy. 310 | 311 | ```csharp 312 | using UnityEngine; 313 | 314 | 315 | public class Elevator : MonoBehaviour 316 | { 317 | public float elevatorSpeed = 2f; 318 | private bool isRunning = false; 319 | public float distanceToMove = 6.6f; 320 | private bool isUp = false; 321 | private bool isDown = true; 322 | private Vector3 downPosition; 323 | private Vector3 upPosition; 324 | private Vector3 currentTarget; 325 | 326 | void Start() 327 | { 328 | upPosition = transform.position + new Vector3(0, distanceToMove, 0); 329 | downPosition = transform.position; 330 | currentTarget = upPosition; 331 | } 332 | 333 | void Update() 334 | { 335 | if (isRunning) 336 | { 337 | if(Vector3.Distance(transform.position, currentTarget) < 0.02f){ 338 | if(currentTarget == upPosition){ 339 | isUp = true; 340 | } 341 | else if(currentTarget == downPosition){ 342 | isDown = true; 343 | } 344 | isRunning = false; 345 | return; 346 | } 347 | transform.position = Vector3.MoveTowards(transform.position, currentTarget, elevatorSpeed * Time.deltaTime); 348 | } 349 | } 350 | 351 | private void OnTriggerEnter (Collider other) 352 | { 353 | if (other.gameObject.CompareTag("Player")) 354 | { 355 | Debug.Log("Player wszedł na windę."); 356 | 357 | if (isUp) 358 | { 359 | isUp = false; 360 | currentTarget = downPosition; 361 | } 362 | else if (isDown) 363 | { 364 | isDown = false; 365 | currentTarget = upPosition; 366 | } 367 | isRunning = true; 368 | } 369 | } 370 | 371 | private void OnTriggerExit(Collider other) 372 | { 373 | if (other.gameObject.CompareTag("Player")) 374 | { 375 | Debug.Log("Player zszedł z windy."); 376 | } 377 | } 378 | } 379 | ``` 380 | 381 | Inną techniką jest zmiana własności ```parent``` obiektu gracza. Przydaje się szczegółnie w sytuacjach gdy przemieszczany obiekt nie jest w stanie 'pchać' ze sobą gracza. 382 | 383 | > Listing 5 - zmiana własności parent gracza. 384 | ```csharp 385 | ... 386 | private void OnTriggerEnter(Collider other) 387 | { 388 | if (other.gameObject.CompareTag("Player")) 389 | { 390 | Debug.Log("Player wszedł na windę."); 391 | // zapamiętujemy "starego rodzica" 392 | oldParent = other.gameObject.transform.parent; 393 | // skrypt przypisany do windy, ale other może być innym obiektem 394 | other.gameObject.transform.parent = transform; 395 | if (transform.position.y >= upPosition) 396 | { 397 | isRunningDown = true; 398 | isRunningUp = false; 399 | elevatorSpeed = -elevatorSpeed; 400 | } 401 | else if (transform.position.y <= downPosition) 402 | { 403 | isRunningUp = true; 404 | isRunningDown = false; 405 | elevatorSpeed = Mathf.Abs(elevatorSpeed); 406 | } 407 | isRunning = true; 408 | } 409 | } 410 | 411 | private void OnTriggerExit(Collider other) 412 | { 413 | if (other.gameObject.CompareTag("Player")) 414 | { 415 | Debug.Log("Player zszedł z windy."); 416 | // lub możemy też udtawić parent na null, jeżeli nasz player 417 | // był potomkiem bezpośrednio naszej sceny 418 | // other.gameObject.transform.parent = oldParent; 419 | // chociaż w nowej wersji Unity powyższa linia nie działa najlepiej 420 | other.gameObject.transform.parent = null; 421 | } 422 | } 423 | ... 424 | ``` 425 | 426 | 427 | ## **Zadania** 428 | 429 | **Zadanie 1** 430 | Przygotuj skrypt i przykład platformy poruszającej się horyzontalnie w momencie, w którym gracz na nią wejdzie. Platforma ma ustalony punkt docelowy i po dotarciu do niego powinna wrócić do miejsca początkowego. 431 | 432 | **Zadanie 2** 433 | Przygotuj prosty model drzwi przesuwanych poziomo, które będą otwierane jeżeli gracz znajdzie się odpowiednio blisko jednej ze stron drzwi. 434 | 435 | **Zadanie 3** 436 | Z przykładów z zajęć oraz zadania 1 przygotuj skrypt, który pozwoli na obsłużenie platformy, która może poruszać się dowolnie w przestrzeni od punktu do punktu. Punkty (w postaci obiektu `Vector3`) są przechowywane w dowolnej wybranej kolekcji. Wypróbuj możliwość dodawania kolejnych waypointów poprzez panel `Inspektor`. Platforma porusza się od pierwszego do kolejnego punktu i jak dotrze do ostatniego punktu, zawraca (czyli podąża tą samą drogą w przeciwnym kierunku). 437 | 438 | **Zadanie 4** 439 | _(Zadanie dotyczy poziomu z lab 04)_ 440 | Stwórz nowy obiekt na scenie imitujący płytę naciskową. Po wejściu na nią (kolizja ?) gracz powinien zostać wyrzucony w powietrze z trzykrotnie większą "siłą" niż w przypadku skoku. 441 | 442 | **Zadanie 5** 443 | _(Zadanie dotyczy poziomu z lab 04)_ 444 | Stwórz nowy obiekt, który będzie obiektem przeszkodą, dodaj do niego tag. Stwórz z tego obiektu prefabrykat i dodaj kilka instancji prefabrykatu do sceny w różnych miejscach poziomu. Dodaj do obiektu gracza skrypt, który będzie zawierał kod sprawdzający czy doszło do kontaktu pomiędzy graczem a przeszkodą (można wyszukiwać obiekty za pomocą tagu). Wyświetlaj komunikat o rozpoczęciu kontaktu w konsoli. 445 | -------------------------------------------------------------------------------- /lab_06/assets/Troll2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0000_feet2left (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0000_feet2left (2).png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0000_right-hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0000_right-hand.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0001_feet2right (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0001_feet2right (2).png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0001_left-arm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0001_left-arm.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0002_left-sholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0002_left-sholder.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0003_right-brow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0003_right-brow.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0004_left-brow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0004_left-brow.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0005_scull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0005_scull.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0006_left-ear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0006_left-ear.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0007_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0007_head.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0008_right-ear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0008_right-ear.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0009_torso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0009_torso.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0010_left-feet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0010_left-feet.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0011_left-hip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0011_left-hip.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0012_left-leg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0012_left-leg.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0013_pelvis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0013_pelvis.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0014_left-feet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0014_left-feet.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0015_left-hip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0015_left-hip.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0016_left-leg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0016_left-leg.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0017_left-hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0017_left-hand.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0018_weapon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0018_weapon.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0019_left-arm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0019_left-arm.png -------------------------------------------------------------------------------- /lab_06/assets/Troll2/troll_0020_left-sholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/Troll2/troll_0020_left-sholder.png -------------------------------------------------------------------------------- /lab_06/assets/craftpix-062999-2d-fantasy-orc-free-sprite-sheets.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/craftpix-062999-2d-fantasy-orc-free-sprite-sheets.zip -------------------------------------------------------------------------------- /lab_06/assets/freetileset.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/freetileset.zip -------------------------------------------------------------------------------- /lab_06/assets/mountain_landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/mountain_landscape.png -------------------------------------------------------------------------------- /lab_06/assets/orc_1_separated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/assets/orc_1_separated.png -------------------------------------------------------------------------------- /lab_06/import_inspector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_06/import_inspector.png -------------------------------------------------------------------------------- /lab_06/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 6 - elementy gry 2D, część 1 2 | 3 | 4 | > **Wymagania** 5 | > Na potrzeby laboratorium oraz zadań potrzebne będą dodatkowe pakiety: 6 | > * 2D Sprite 7 | > * 2D SpriteShape 8 | > * 2D Animation 9 | > * 2D Tilemap Editor 10 | > Upewnij się, że są zainstalowane lub zainstaluj brakujące. 11 | 12 | 13 | 14 | Materiały zawarte w tym laboratorium są tylko częścią tego co można znaleźć w oficjalnej dokumentacji dla projektów 2D w Unity. Aby zdobyć rozeznanie w szerszym aspekcie przeczytaj część znajdującą się pod adresem: https://docs.unity3d.com/2022.3/Documentation/Manual/Unity2D.html 15 | 16 | 17 | ## 1. **Import grafiki 2D do projektu Unity** 18 | 19 | Przygotowanie grafiki i modeli dla gry wymaga zaplanowania sposobu ich wykorzystania w grze. Czy będzie to gra z grafiką typu 'pixel art', czy będziemy korzystać z grafiki w wysokiej rozdzielczości. To wymaga przygotowania obiektów w skali, tak aby zachować odpowiednie proporcje i jakość grafiki. Powinniśmy również w przypadku korzystania z 'kafelków' (ang. tiles) odpowiednio dopasować wielkość grafiki, co pozwoli na bardziej precyzyjne dopasowanie wielkości elementów do siatki dostępnej w Unity. 20 | 21 | Pojedynczy plik graficzny możemy zaimportować bezpośrednio z widoku `Project` i wybierając z menu kontekstowego opcję `Import New Asset...`. Po zaimportowaniu pliku w oknie inspektora możemy zmienić ustawienia importu lub pozostawić je jako domyślne. 22 | 23 | ![inspector import](import_inspector.png) 24 | 25 | 26 | `Texture Type` określa typ grafiki, który chcemy dla importowanego obrazu wybrać. Wybór będzie miał wpływ na możliwość zdefiniowania dodatkowych parametrów i wykorzystanie w projekcie. 27 | 28 | **Dostępne typy:** 29 | * Default - domyślna wartość, która pozwala na określenie podstawowych parametrów obrazu oraz pozwala na określenie kształtu tekstury ([Texture Shape](https://docs.unity3d.com/2022.3/Documentation/Manual/class-TextureImporter.html#textureshape)) 30 | * Normal map - jest to rodzaj tekstury, który odpowiada za efekt gry światłem na jej powierzchni (tzw. bump mapping) umożliwiając powstanie złudzenia wypukłości tekstur unikając tworzenia faktycznych wypukłości, które są bardziej kosztowne obliczeniowo. 31 | * Editor GUI and Legacy GUI - wykorzystywane do umieszczania tekstur na powierzchni obiektów GUI lub HUD 32 | * Sprite (2D and UI) - typ wykorzystywany dla tzw. Sprite'ów, czyli grafiki najczęściej uzywanej w grach 2D 33 | * Cursor - pozwala na wykorzystanie tekstury dla kursora, np. celownika 34 | * Cookie - jest to specjalny rodzaj tekstur służący do generowania efektu cienia rzucanego przez obiekt znajdujący się między źródłem światła a powierzchnią, do której owo światło dociera. Więcej: [Cookies](https://docs.unity3d.com/2022.3/Documentation/Manual/Cookies.html) 35 | * Lightmap - jest to tekstura, w której zastosowane są już niektóre efekty świetlne, zapisane na stałe, pozwalając uniknąć generowania tych efektów w czasie rzeczywistym, jeżeli dany element tego nie wymaga. 36 | * Single Channel - rodzaj tekstury, gdzie możemy określić tylko jeden z kanałów (alfa lub red) 37 | 38 | 39 | 40 | **`Sprite Mode`** pozwala na określenie czy mamy do czynienia z pojedynczym Sprite'em (`Single`) czy może ze zbiorem Sprite'ów (`Multiple`) umieszczonych w jednym pliku. Możemy również przyciąć istniejącą teksturę wybierając opcję `Polygon` i następnie w `Sprite Editor` zmieniając wyświetlany obszar poprzez zmianę kształtu z opcji `Sprite Custom Outline`. 41 | 42 | **`Pixel Per Unit`** (PPU) to bardzo ważny parametr, którym określamy ile pikseli obrazu przypada na jedną jednostkę w środowisku Unity. Zaplanowanie użycia tego parametru przed przystąpieniem do prac nad grafiką jest zazwyczaj dobrym pomysłem. 43 | 44 | **`Mesh Type`** pozwala na określenie obszaru Sprite'u, `Full Rect` to określenie obszaru jako czworobok a `Tight` to automatyczne stworzenie kształtu bazując na przezroczystych pikselach, które znajdują się w obszarze obrazu. Zazwyczaj dopasowane do nieprzezroczystych pikseli obrazu. Dla obrazów mniejszych niż 32x32 piksele uzywany jest automatycznie `Full Rect` nawet jak wybrany został parametr `Tight`. 45 | 46 | **`Extrude Edges`** określa w pikselach jaki obszar otaczający Sprite będzie wolny - zgodnie z opisem w dokumentacji. W rzeczywistości zmiana tych parametrów nie przynosi żadnych rezultatów. 47 | 48 | **`Pivot`** pozwala na ustalenie punktu obrotu dla danego elementu. 49 | 50 | **`Generate Physics Shape`** jeżeli nie został zdefiniowany niestandardowy kształt (`Custom Physics Shape`) Unity wygeneruje autoamtycznie kształ pokrywający się z krawędziami danego Sprite'u. 51 | 52 | **`Remove Matte`** jest ustawienie stosowane do plików PSD (Photoshop), które używają przezroczystości. Poprawia wygląd krawędzi przylegających do przezroczystego obszaru. 53 | 54 | **`Read/Write Enabled`** włączenie tej opcji umożliwia dostęp do danych tekstury z poziomu skryptów. 55 | 56 | **`Generate Mip Maps`** włączenie tej opcji przydaje się w przypadku gdy obraz będzie skalowany w widoku sceny do bardzo małych rozmiarów. Wygenerowane zostaną miniaturowe wersje tych obrazów. 57 | 58 | **`Wrap Mode`** definiuje zachowanie obrazu kiedy używany jest jako kafelek ([więcej tu](https://docs.unity3d.com/2022.3/Documentation/Manual/class-TextureImporter.html#WrapMode) oraz [tu](https://docs.unity3d.com/2022.3/Documentation/ScriptReference/TextureWrapMode.html)). 59 | 60 | **`Filter Mode`** zmienia zachowanie tekstury kiedy zostaje ona zmodyfikowana przez przekształcenia 3D. `Point` oznacza brak filtrowania (rozmycia) i stosowane jest do grafiki typu Pixel Perfect. `Bilinear` i `Trilinear` rozmywa obraz kiedy go przybliżamy. 61 | 62 | **`Aniso level`** wpływa korzystnie na jakość wyświetlanego Sprite'a kiedy widok kamery jest dkierowany na niego pod kątem ostrym. 63 | 64 | Ustawienia, które znajdują się na samym dole przedstawionego powyżej okna umożliwiają dostosowanie ustawień dla poszczególnych platform, na których gra zostanie uruchomiona. `Default` zawiera domyślne ustawienia a pozostałe zakładki dla wybranych platform docelowych. 65 | Więcej szczegółów o możliwych ustawieniach dla wybranych parametrów znajdziesz pod linkiem: https://docs.unity3d.com/2022.3/Documentation/Manual/class-TextureImporter.html#platform 66 | 67 | > Dodatkowe materiały: 68 | > * https://learn.unity.com/tutorial/importing-2d-assets-into-unity-2019-3#5f7cfc5cedbc2a0022112cab 69 | 70 | ### **Sprite Editor** 71 | 72 | **`Sprite Editor`** pozwala na edycję takich właściwości obrazu jak punkt obrotu, krawędzie dla skalowania typu 9-slice, niestandardowy kształt fizyczny (wykorzystywany ze zderzaczami oraz materiałami fizycznymi). To narzędzie pozwala również w trybie `Multiple` na pocięcie jednego pliku z wieloma Sprite'ami na oddzielne Sprite'y. Proces ten może być automatyczny, ręczny lub można spróbować pociąć plik automatycznie i wykonać poprawki w trybie ręcznym. 73 | 74 | Sprite Editor zawiera również narzędzie **`Skinning Editor`** które pozwala tworzyć szkielety złożone z kości, które daje możliwość dodania animacji w sposób dużo bardziej efektywny i dynamiczny. 75 | 76 | 77 | **Wykonaj zadanie nr 0, 1 oraz 2.** 78 | 79 | 80 | ## 2. **Rigging - budowanie szkieletu.** 81 | 82 | Aby ułatwić sobie proces budowania szkieletu najwygodniej jest przygotować Sprite z postacią pocięty tak, że każda część ciała to oddzielny sprite. Jednak należy go zaimportować w trybie `Single`. Jeżeli będzie to pojedynczy Sprite, będziemy musieli włożyć więcej pracy w dostosowanie podziału kształtu oraz wag oddziaływania poszczególnych kości na otaczające ją 'ciało' postaci. 83 | 84 | 85 | > Dodatkowe materiały do nauki: 86 | > * https://learn.unity.com/tutorial/rigging-a-sprite-with-the-2d-animation-package# 87 | > * https://www.youtube.com/watch?v=EZtpACxCTEE 88 | > * https://www.youtube.com/watch?v=vap04-Py9QM 89 | 90 | 91 | **Wykonaj zadanie nr 3 oraz 4.** 92 | 93 | 94 | ## Zadania 95 | 96 | **Zadanie 0** 97 | Jako, że kolejny lab będzie kontynuacją bieżącego, dobrym pomysłem wydaje się stworzenie nowego projektu 2D dla tego projektu. Tym razem nie jest konieczne umieszczanie całego projektu w repozytorium. W ostatnim zadaniu opisane są szczegóły dotyczące elementów do umieszczenia w repo. 98 | 99 | **Zadanie 1** 100 | Zaimportuj [grafikę](assets/mountain_landscape.png) do projektu Unity i przy pomocy `Sprite Editor'a` potnij ją na oddzielne Sprite'y. Uwzględnij wykorzystanie minimum 3 Sprite'ów jako 9-slice'y. Dodatkowe wskazówki i przykłady znajdziesz pod adresem: https://docs.unity3d.com/2022.3/Documentation/Manual/9SliceSprites.html 101 | 102 | **Zadanie 2** 103 | Przygotuj przykładową scenę wykorzystując assety ze zbioru dostępnego pod adresem https://opengameart.org/content/rpg-tiles-cobble-stone-paths-town-objects. Warto dodać nowe warstwy na scenie oraz przypisać elementy do odpowiednich warstw oraz ustalić kolejność renderowania obiektu w warstwie. Jeżeli masz problem z kolejnością wyświetlania elementów przeczytaj https://docs.unity3d.com/2022.3/Documentation/Manual/2DSorting.html 104 | 105 | **Zadanie 3** 106 | Zaimportuj grafikę przedstawiającą [Trolla](assets/Troll2.png) i dodaj do niego szkielet bazując na przykładzie z labu oraz załączonych linkach z materiałami dodatkowymi. Pamiętaj o nazwaniu poszczególnych kości dla ułatwienia ich późniejszej identyfikacji. "Pocięty" troll znajduje się w folderze [assets/Troll2](assets/Troll2). Najwygodniej będzie zapisać wszystkie części w jednym pliku - można to zrobić przy pomocy programu Gimp. 107 | 108 | **Zadanie 4** 109 | Dodaj szkielet na scenę, ułóż elementy w odpowiednim porządku i sprawdź czy kolejność kości jest poprawna. Dodaj komponent `Sprite Skin` i wksaż kość bazową. 110 | 111 | W ramach rozliczenia z zadań za bieżący lab, proszę udostępnić screen z przygotowanym poziomem z zadania numer 2. Postać z zadania numer 4 będzie potrzebna na kolejnych zajęciach. 112 | 113 | 114 | Materiały użyte w laboratorium pochodzą z: 115 | * https://opengameart.org/content/2d-lost-garden-zelda-style-tiles-resized-to-32x32-with-additions 116 | * https://www.gameart2d.com/free-platformer-game-tileset.html 117 | * https://craftpix.net/ -------------------------------------------------------------------------------- /lab_07/ground_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_07/ground_settings.png -------------------------------------------------------------------------------- /lab_07/movement_script_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_07/movement_script_settings.png -------------------------------------------------------------------------------- /lab_07/platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_07/platform.png -------------------------------------------------------------------------------- /lab_07/player_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_07/player_components.png -------------------------------------------------------------------------------- /lab_07/player_rigidbody_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_07/player_rigidbody_settings.png -------------------------------------------------------------------------------- /lab_07/readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Lab 7. Tworzenie gry 2D, część 2. 3 | 4 | 5 | ## 1. Animacja postaci z wykorzystaniem szkieletu oraz komponentu IK (Inverse Kinematics). 6 | 7 | > Tutoriale godne polecenia: 8 | > * https://www.youtube.com/watch?v=eXIuizGzY2A 9 | > * https://www.youtube.com/watch?v=Ed8CoET9b6U 10 | > * https://www.youtube.com/watch?v=Htl7ysv10Qs 11 | 12 | ## 2. Sprite shape - efektywne budowanie gry platformowej 2D. 13 | 14 | > Tutoriale: 15 | > * https://docs.unity3d.com/Packages/com.unity.2d.spriteshape@3.0/manual/index.html 16 | > * https://www.raywenderlich.com/3045258-introduction-to-unity-sprite-shapes 17 | > * https://learn.unity.com/tutorial/working-with-spriteshape 18 | > * https://blogs.unity3d.com/2018/09/20/intro-to-2d-world-building-with-sprite-shape/ 19 | > * https://www.youtube.com/watch?v=GSo_fU1JdfM 20 | 21 | 22 | ## 3. Maszyna stanów animacji - animation state machine. 23 | 24 | Podstawy tworzenia animacji oraz obsługi maszyny stanów animacji zostaną zaprezentowane przez prowadzącego. 25 | 26 | > Tutoriale: 27 | > * https://www.youtube.com/watch?v=hkaysu1Z-N8 28 | 29 | 30 | ## 4. Dodajemy kilka gotowych elementów 31 | 32 | Assety są dostępne w labie numer 6 - [freetilesets](../lab_06/assets/freetileset.zip). 33 | 34 | Skrypty do poruszania postacią. Skrypty pochodzą ze zbiorów Brackey's, ale zostały zmodyfikowane. 35 | 36 | **_Listing 1_** 37 | 38 | ```csharp 39 | using UnityEngine; 40 | using UnityEngine.Events; 41 | 42 | public class CharacterController2D : MonoBehaviour 43 | { 44 | [SerializeField] private float m_JumpForce = 350f; // Amount of force added when the player jumps. 45 | [Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f; // How much to smooth out the movement 46 | [SerializeField] private bool m_AirControl = false; // Whether or not a player can steer while jumping; 47 | [SerializeField] private LayerMask m_WhatIsGround; // A mask determining what is ground to the character 48 | [SerializeField] private Transform m_GroundCheck; // A position marking where to check if the player is grounded. 49 | [SerializeField] private float m_delayGroundCheck = 0.25f; 50 | 51 | const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded 52 | private bool m_Grounded; // Whether or not the player is grounded. 53 | private Rigidbody2D m_Rigidbody2D; 54 | private bool m_FacingRight = true; // For determining which way the player is currently facing. 55 | private Vector3 m_Velocity = Vector3.zero; 56 | private float timeBeforeGroundCheck = 0f; 57 | 58 | [Header("Events")] 59 | [Space] 60 | 61 | public UnityEvent OnLandEvent; 62 | 63 | [System.Serializable] 64 | public class BoolEvent : UnityEvent { } 65 | 66 | private void Awake() 67 | { 68 | m_Rigidbody2D = GetComponent(); 69 | 70 | if (OnLandEvent == null) 71 | OnLandEvent = new UnityEvent(); 72 | } 73 | 74 | private void Update() 75 | { 76 | if (!m_Grounded) 77 | { 78 | timeBeforeGroundCheck -= Time.deltaTime; 79 | } 80 | } 81 | 82 | private void FixedUpdate() 83 | { 84 | if (timeBeforeGroundCheck > 0f) 85 | { 86 | return; 87 | } 88 | bool wasGrounded = m_Grounded; 89 | m_Grounded = false; 90 | 91 | // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground 92 | // This can be done using layers instead but Sample Assets will not overwrite your project settings. 93 | Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround); 94 | for (int i = 0; i < colliders.Length; i++) 95 | { 96 | if (colliders[i].gameObject != gameObject) 97 | { 98 | m_Grounded = true; 99 | if (!wasGrounded) 100 | OnLandEvent.Invoke(); 101 | } 102 | } 103 | } 104 | 105 | public void Move(float move, bool jump) 106 | { 107 | //only control the player if grounded or airControl is turned on 108 | if (m_Grounded || m_AirControl) 109 | { 110 | // Move the character by finding the target velocity 111 | Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y); 112 | // And then smoothing it out and applying it to the character 113 | m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing); 114 | 115 | // If the input is moving the player right and the player is facing left... 116 | if (move > 0 && !m_FacingRight) 117 | { 118 | // ... flip the player. 119 | Flip(); 120 | } 121 | // Otherwise if the input is moving the player left and the player is facing right... 122 | else if (move < 0 && m_FacingRight) 123 | { 124 | // ... flip the player. 125 | Flip(); 126 | } 127 | } 128 | // If the player should jump... 129 | if (m_Grounded && jump) 130 | { 131 | m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce)); 132 | m_Grounded = false; 133 | timeBeforeGroundCheck = m_delayGroundCheck; 134 | } 135 | } 136 | 137 | private void Flip() 138 | { 139 | // Switch the way the player is labelled as facing. 140 | m_FacingRight = !m_FacingRight; 141 | 142 | // Multiply the player's x local scale by -1. 143 | Vector3 theScale = transform.localScale; 144 | theScale.x *= -1; 145 | transform.localScale = theScale; 146 | } 147 | } 148 | ``` 149 | 150 | **_Listing 2_** 151 | 152 | ```csharp 153 | 154 | using UnityEngine.SceneManagement; 155 | using UnityEngine; 156 | 157 | public class PlayerMovement : MonoBehaviour 158 | { 159 | public CharacterController2D controller; 160 | public Animator animator; 161 | public float runSpeed = 30f; 162 | bool jump = false; 163 | float horizontalMove = 0f; 164 | 165 | void Update() 166 | { 167 | 168 | horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed; 169 | animator.SetFloat("Speed", Mathf.Abs(horizontalMove)); 170 | 171 | if (Input.GetButtonDown("Jump")) 172 | { 173 | jump = true; 174 | animator.SetBool("IsJumping", true); 175 | } 176 | } 177 | 178 | void FixedUpdate() 179 | { 180 | controller.Move(horizontalMove * Time.fixedDeltaTime, jump); 181 | jump = false; 182 | } 183 | 184 | public void OnLanding() 185 | { 186 | Debug.Log("OnLanding()"); 187 | animator.SetBool("IsJumping", false); 188 | } 189 | } 190 | 191 | ``` 192 | 193 | Aby sterowanie głównym bohaterem działało poprawnie trzeba jeszcze dodać w inspektorze zdarzenie dla skryptu `CharacterController2D` tak jak na poniższym zrzucie ekranu. 194 | 195 | ![Script details](movement_script_settings.png) 196 | 197 | Zbiór komponentów dla głównego bohatera: 198 | 199 | ![Component list](player_components.png) 200 | 201 | Ustawienia komponentu Rigidbody2D dla głównego bohatera: 202 | 203 | ![Rigidbody settings](player_rigidbody_settings.png) 204 | 205 | Własność **What Is Ground** wskazuje na obiekt typu LayerMask, czyli warstwę, którą ustawimy jako warstawę zawierającą elementy podłoża naszego poziomu gry np. platformy. Na poniższym zrzucie ekranu zaprezentowano kilka kolejnych ustawień. W panelu **hierarchy** widać istniejący obiekt **GroundCheckObject**, który jest usytułowany w okolicach stóp głównego bohatera a promieniu 0.25 jednostki od tego punktu będą wykrywane kolizje (overlap) z dowolnym obiektem, który znajduje się na utworzonej warstwie o nazwie **ground** (widać po prawej stronie zrzutu w oknie **Inspector**). 206 | 207 | Na zrzucie znajduje się również platforma stworzona za pomocą Sprite Shape Profile (Open shape), do której został dodany collider oraz została ona umieszczona właśnie na warstwie **ground**. 208 | 209 | ![Ground settings](ground_settings.png) 210 | 211 | 212 | **Zadania** 213 | 214 | 1. Dodaj animację dla skoku, ataku oraz otrzymania obrażeń. 215 | 2. Dodaj odpowiednie parametry i przejścia w komponencie `Animator`. 216 | 3. Zbuduj przykładowy poziom wykorzystując udostępnione assety. Wykorzystaj element typu Sprite Shape. W miarę możliwości zorganizuj elementy poziomu w odpowiednich warstwach (również warstwach sortowania). Dodaj tagi dla gracza. -------------------------------------------------------------------------------- /lab_08/assets/craftpix-net-484869-free-minotaur-tiny-style-2d-sprites.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_08/assets/craftpix-net-484869-free-minotaur-tiny-style-2d-sprites.zip -------------------------------------------------------------------------------- /lab_08/assets/craftpix-net-563568-free-wraith-tiny-style-2d-sprites.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_08/assets/craftpix-net-563568-free-wraith-tiny-style-2d-sprites.zip -------------------------------------------------------------------------------- /lab_08/lab_8_starter_light_2022.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kropiak/unity_uwm/2180785f0f6b2e17ce27c0bc111efbb4b67ea2c4/lab_08/lab_8_starter_light_2022.zip -------------------------------------------------------------------------------- /lab_08/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 8. Tworzenie gry 2D, część 3. Wrogowie. A* pathfinding. 2 | 3 | > Projekt startowy, który można wykorzystać: [starter](lab_8_starter_light_2022.zip) 4 | > W projekcie jest jedna scena, a na niej postać głównego bohatera z dodanym skryptem do poruszania się po przykładowym poziomie. 5 | > Zaimplementowana jest również kamera śledząca głównego bohatera oraz reset poziomu po updaku z platformy. 6 | > Dodana jest również część animacji, ale nie wszystkie przejścia w maszynie stanów animacji są dokończone. 7 | 8 | **Zadanie 1** 9 | 10 | Zadanie polega na stworzeniu postaci wroga naziemnego, która będzie poruszała się stale między puntem A i B dopóki postać naszego bohatera nie pojawi się w promieniu "reakcji" wroga. Punkty A i B mogą być umieszczane dowolnie (ale wciąż sensownie dla wroga naziemnego). Jeżeli bohater (player) pojawi się w promieniu zasięgu wroga będzie on poruszał się w kierunku naszego bohatera aż dotrze do niego, ale tylko pomiędzy punktami A oraz B. To na razie uprości implementację rozwiązania i nie pozwoli wrogom na niekontrolowane spadanie z platform. Jeżeli oddalimy się od wroga poza zasięg reakcji powinien powrócić do swojego wcześniejszego "zajęcia". 11 | 12 | > **Opcjonalnie!** 13 | > Jeżeli chcesz użyć czegoś bardziej wyrafinowanego, w stylu Field of View (FoV) zobacz te tutoriale: 14 | > * https://www.youtube.com/watch?v=CSeUMTaNFYk (część 1) 15 | > * https://www.youtube.com/watch?v=3-jPo2wzvdw (część 2) 16 | > 17 | > lub 18 | > * https://www.youtube.com/watch?v=rQG9aUWarwE (część 1) 19 | > * https://www.youtube.com/watch?v=73Dc5JTCmKI (część 2) 20 | 21 | 22 | _Import postaci wroga_ 23 | 24 | Postać przykładowego wroga możesz pobrać z adresu: https://craftpix.net/freebies/free-minotaur-tiny-style-2d-sprites/ 25 | 26 | Ten pakiet zawiera również gotowy pakiet Unity, który wystarczy zaimportować aby wykorzystać m.in. animacje, które zostały już dla tej postaci stworzone. Problemem, który się pojawi może być kolejność renderowania sprite'ów w warstwach. Można to zmienić poprzez wartość pola `order in layer` poszczególnych sprite'ów. 27 | 28 | Po zaimportowaniu element, ten dostępny jest jako prefabrykat. 29 | 30 | Wykorzystaj tylko animację idle (domyślna) oraz animację ruchu wroga. Dodaj skrypt, który będzie wykorzystywany do sterowania wrogiem - możesz wykorzystać zmodyfikowaną wersję skryptów z poprzednich zajęć (`CharacterController2D`). Pamiętaj o dodaniu odpowiednich komponentów (Rigidbody2D, odpowiedni collider 2D). 31 | 32 | Postaraj się zaplanować dodanie komponentów i skryptów tak, aby ten element był reużywalny. Będzie to oznaczało, że będzie możliwe dodanie innej postaci wroga, zmodyfikowanie położenia punktów A i B dla każdej instancji wroga. 33 | 34 | **Zadanie 2** 35 | 36 | Obejrzyj film dostępny pod adresem https://www.youtube.com/watch?v=jvtFUfJ6CP8 a następnie dodaj wroga powietrznego na podstawie informacji z obejrzanego materiału wykorzystując gotowy pakiet implementujący algorytm A*. Link znajdziesz w opisie filmu. 37 | 38 | Film jest podzielony na dwie części, gdzie w pierwszej wykorzystane są gotowe możliwości pakietu, a w drugiej skrypt sterujący postacią wroga jest pisany krok po kroku. Wybierz jeden ze sposobów dla swojego zadania. 39 | 40 | Postać latającego wroga możesz wykorzystać używając gotowego pakietu https://craftpix.net/freebies/free-wraith-tiny-style-2d-sprites/ lub dowolnego wybranego przez siebie (bez łamania praw autorskich). 41 | 42 | 43 | > **UWAGA!**: Jako wynik pracy w repozytorium dodajemy skrypt dla zadania 1, który steruje zachowaniem przeciwnika naziemnego. 44 | 45 | > Dla zadania 2 można nagrać krótki film prezentujący poruszanie się wroga powietrznego lub umieścić spakowany projekt w podobnej formie jak projekt startowy dołączony do labu 9. -------------------------------------------------------------------------------- /lab_09/readme.md: -------------------------------------------------------------------------------- 1 | # Lab 9 - Zadanie specjalne. 2 | 3 | Zadaniem do wykonania jest stworzenie trójwymiarowego modelu Waszego wyboru za pośrednictwem oprogramowania Mechroom oraz Blender lub innego pozwalającego na edycję modeli 3D. 4 | 5 | Zdjęcia modelu musicie wykonać samodzielnie, może to być obiekt znajdujący się na zewnątrz (pomnik, ławka, drzewo, kamień itp.) lub coś co znajdziecie wokół swojego najbliższego otoczenia. Można również zrobić model samego siebie :) Aby całość się udała potrzeba co najmniej około 20 zdjęć, ale im więcej tym lepiej. Warto przed rozpoczęciem robienia zdjęć przeanalizować podlinkowane tutoriale. 6 | > **Do repozytorium należy dołączyć zrzut modelu, plik z modelem (może być .obj, .blend, .psb) oraz minimum 3 zdjęcia użyte do jego wygenerowania (w celu weryfikacji, pamiętajmy, że Google również pozwala na wyszukiwanie obrazem ;-) ).** 7 | 8 | 9 | Najlepsze projekty zostaną nagrodzone +1 do oceny końcowej (jeżeli się da :) ), zachwytem prowadzącego oraz szacunkiem wśród pozostałych członków grupy :) 10 | 11 | ## **Potrzebne składniki:** 12 | 1. **Meshroom** 13 | 14 | Jest to oprogramowanie OpenSource w ramach projeku [AliceVision](https://alicevision.org/). Dzięki temu oprogramowaniu przy zachowaniu pewnych zasad robienia zdjęć można stworzyć z nich realistyczne modele 3D, które po obróbce mogą być wykorzystane na wiele sposobów. Oprogramowanie wykorzystuje fotogrametrię do osiągnięcia finalnego celu czyli metadanych o zdjęciu i ustawieniach urządzenia za pomocą którego zostało zrobione. 15 | 16 | Meshroom pobieramy spod adresu: https://alicevision.org/#meshroom. 17 | 18 | Oprogramowanie oferuje również wsparcie dla kart Nvidia z procesorami CUDA. Aby to wykorzystać należy najpierw zainstalować odpowiedni Toolkit. 19 | 20 | Jeżeli na wyposażeniu nie ma karty Nvidia, to można spróbować obejść ten problem wykorzystując np. Google Colab i darmowy, ograniczony, dostęp do GPU od Googla. 21 | 22 | Zobacz dokumentację tu: 23 | * https://github.com/alicevision/meshroom/wiki/Meshroom-in-Google-Colab-(cloud) 24 | * https://shawngraham.github.io/CCAD/notebooks/meshroom/ 25 | 26 | 27 | Podstawowy workflow po uruchomieniu programu Meshroom jest wystarczający, żeby stworzyć model i wyeksportować go to zewnętrznego programu modelującego. Przy zbyt małej ilości zdjęć lub ich nieprawidłowym wykonaniu mogą pojawić się błędy, które trzeba będzie samodzielnie rozwiązać. Najczęściej polega to na lepszym wyborze zdjęć lub ponownym ich zrobieniu przy lepszym oświetleniu i ze zbliżoną odległością od obiektu. 28 | 29 | 1. **Nvidia CUDA toolkit** 30 | 31 | Jeżeli na wyposażeniu znajduje się przyzwoita karta Nvidia z procesorami CUDA warto przyspieszyć proces generowania modelu (który w zależności od ilości zdjęć może zająć duuuużo czasu). Meshroom (zgodnie z zapisem w dokumentacji) wspiera Nvidia toolkit w wersji 10. 32 | 33 | Nvidia Toolkit: https://developer.nvidia.com/cuda-10.0-download-archive 34 | 35 | 3. **Oprogramowanie do modelowania** 36 | 37 | Oprogramowanie jest niezbęde, żeby dodać szlify do modelu i pozbyć się niepotrzebnie wykrytych elementów, zbędnych detali i zredukować ilość wierzchołków modelu. 38 | 39 | Model z Meshroom można obrobić w Blenderze, ZBrush, Maya i inne. Blender jest tu niezłym wyborem, ze względu na fakt, że jest to oprogramowanie OpenSource z bardzo dużymi możliwościami. 40 | 41 | Blender: https://www.blender.org/download/ 42 | 43 | 44 | ## Przydatne materiały 45 | 46 | 1. Tutorial z wykorzystaniem Meshroom oraz Blender do stworzenia modelu: https://www.kodeco.com/9559662-using-meshroom-to-insert-real-life-objects-in-unity 47 | 2. Manual Meshroom: https://meshroom-manual.readthedocs.io/en/latest/ 48 | 3. Niezły tutorial Meshroom + Blender: https://www.youtube.com/watch?v=k4NTf0hMjtY 49 | 50 | 51 | 52 | ## Czekam na ciekawe projekty! -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Projektowanie gier w środowisku UNITY, semestr 2024Z/2025L 2 | 3 | ## **1. Cele przedmiotu.** 4 | 5 | Celem przedmiotu jest zaprezentowanie studentom możliwości silnika Unity oraz środowiska Unity Editor. Mimo wielu możliwości graficznego narzędzia wymagana jest też umiejętność programowania w języku C# w oparciu o API silnika Unity. Temat tworzenia gier jest bardzo obszerny i obejmuje takie zagadnienia jak programowanie (bardzo często dotyczy zaawansowanych zagadnień), grafika i animację komputerową, tworzenie dźwięków,muzyki znajomość zagadnień fizyki. Z tego powodu w trakcie zajęć zostaną zaprezentowane tylko wybrane aspekty tworzenia gier, uznane przez prowadzącego za istotne. 6 | 7 | ## **2. Organizacja zajęć.** 8 | 9 | Zajęcia będą podzielone na odrębne tematycznie laboratoria, ale ze względu na rozległość niektórych zagadnień część może bazować na pracy wykonanej wcześniej. W celu optymalizacji prowadzenia zajęć i skupieniu się na głównym celu danego laboratorium projekt startowy może być wcześniej przygotowany przez prowadzącego. 10 | 11 | Na początku zajęć prowadzący zaprezentuje omawiane zagadnienie wraz z przykładami, a następnie student otrzyma zadania do samodzielnego wykonania w trakcie zajeć. 12 | 13 | ## **3. Zasady oceniania i zaliczenie przedmiotu.** 14 | 15 | Zaliczenie przedmiotu odbędzie się na podstawie oceny projektu gry na temat wspólnie ustalony z prowadzącym, aktywności w trakcie zajęć oraz obecności. Prezentacja projektu odbędzie się w formie krótkiego gameplaya oraz odpowiedzi prowadzącego na kilka pytań dotyczących projektu (również kodu). Projekt musi być wcześniej przesłany do zatwierdzenia z zachowaniem ustalonego terminu (zostanie ustalony wspólnie ze studentami w trakcie zajęć). 16 | 17 | ### **3.1 Wymagania zaliczeniowego projektu gry.** 18 | 19 | Tematyka gry jest dowolna pod warunkiem, że nie łamie zasad dobrych obyczajów i ogólnie przyjętych norm społecznych. Jeżeli student nie zaproponuje własnego tematu, prowadzący wskaże temat takiego projektu. 20 | 21 | W projekcie gry należy uwzględnić: 22 | 23 | 1. Możliwość interakcji za pomocą kontrolera (klawiatura, mysz, pad itp.). 24 | 2. Należy użyć komponentów wykorzystujących silnik fizyczny Unity (Rigidbody, Rigidbody2D). 25 | 3. W projekcie muszą znaleźć się co najmniej 3 skrypty własne - nie będące komponentami Unity API. 26 | 4. W projekcie należy również umieścić elementy UI charakterystyczne dla danego typu gry (score, speed, reset, start, itp.) 27 | 5. Należy użyć również co najmniej jednego pliku audio (muzyka w tle, dźwięk pojawiający się w wyniku jakiegoś zdarzenia w grze, itp.). 28 | 29 | ## **4. Polecane zasoby do nauki silnika Unity.** 30 | 31 | 1. [Unity Learn](https://learn.unity.com/) - niezwykle uporządkowane i bogate źródło wiedzy z samego źródła. Możliwość śledzenia postępów, zróżnicowane poziomy trudności poszczególnych tutoriali. 32 | 2. [Unity Docs](https://docs.unity3d.com/Manual/index.html) - oficjalna dokumentacja Unity. Obejmuje zarówno opis Unity Editor jak i Unity scripting API. 33 | 3. [Brackeys YouTube](https://www.youtube.com/channel/UCYbK_tjZ2OrIZFBvU6CCMiA) - dostępny również Discord. Niestey 18 września 2020 ogłoszono, że nowe materiały w tej formule nie będą się już pojawiały. Jednak jest tam kilkaset (!) filmów, z których można nauczyć się wielu zagadnień związanych z tworzeniem gier w środowisku Unity. 34 | 4. Oficjalny kanał Unity w serwisie YouTube: https://www.youtube.com/channel/UCG08EqOAXJk_YXPDsAvReSg 35 | 5. [Kodeco (wcześniej Raywenderlich.com)](https://www.kodeco.com/library?q=unity) - duży zbiór tutoriali (nie tylko dla Unity), również płatnych. Dobra jakość materiałów. 36 | 6. [CGCookie](https://cgcookie.com/search/query?q=unity&category=&type=) - bardziej kojarzony ze środowiskiem Blender 3D, ale te dwie platformy znjadują się we wspólnym ekosystemie gier video. Minusem bez wątpienia mała ilość darmowego contentu, plusem - wysoka jakość. 37 | 7. [CGCookie YouTube](https://www.youtube.com/user/unitycookie/) - kanał YouTube grupy CGCookie. --------------------------------------------------------------------------------