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

Dzisiejszy odcinek: Jak pracować w zespole – Unity i system kontroli wersji.

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

Jest to wpis gościnny. Autorem poniższego tutoriala jest: Marcin Sroczyński.

Tekst jest z grubsza oryginalny, ja zająłem się jedynie częścią redaktorską. Dajcie znać, jeśli artykuł wam się spodoba, bo z tego co wiem, mój dzisiejszy gość, chciałby się z wami częściej dzielić wiedzą. Żeby nie przedłużać, oddaje głos Marcinowi.

Wprowadzenie

Wielu użytkowników Unity korzysta z niego samodzielnie. W internecie znajdziemy setki tysięcy poradników dotyczących tworzenia gier w Unity, od których warto zacząć. Jednak po pewnym czasie pracy, przychodzi moment w którym chcielibyśmy tworzyć projekt już nie tylko w pojedynkę, a w większej grupie np. ze znajomymi ze studiów lub z innego miasta. W takim wypadku konieczne będzie korzystanie z serwisu, który wykorzystuje System Kontroli Wersji(VCS – Version Control System). Takimi serwisami są np. GitHub oraz Bitbucket.

Okazuje się jednak, że przy wspólnej pracy nad projektem zetkniemy się z problemem tzw “konfliktów”. Czym jest konflikt? Krótko mówiąc będzie to sytuacja kiedy ten sam obiekt zostanie zmieniony przez 2 osoby jednocześnie, a następnie zostanie podjęta próba przesłania zmian (pushowania) do repozytorium (miejsce gdzie trzymana jest “wspólna” wersja projektu). Uda się osobie, która zrobi to pierwsza, natomiast druga osoba, będzie musiała wcześniej pobrać najnowszą wersję projektu. Właśnie przy tej próbie pobrania wystąpi konflikt, który będziemy musieli usunąć samodzielnie posługując się odpowiednimi narzędziami.
[stextbox id=”info” defcaption=”true”]Przyznam, że gdy pierwszy raz szukałem informacji na temat usuwania konfliktów na scenach nie znalazłem żadnego poradnika, ani w języku polskim ani w języku angielskim. Przeszukiwanie dokumentacji, jednego tematu na forum Unity (który poruszą tą kwestię), w którym osoby miały problem z konfiguracją narzędzi do usuwania konfliktów, oraz samodzielne walczenie z błędami zajęło mi kilka godzin. Byłem bardzo zdziwiony, że tak niewiele osób szukało informacji na tak ważny temat, dlatego postanowiłem przekazać część zdobytej wiedzy czytelnikom Marka, być może niektórym z nich taka wiedza będzie przydatna – mam taką nadzieję :).[/stextbox]

Instalacja potrzebnych narzędzi

Nim zaczniemy naszą pracę będziemy potrzebować 2 narzędzi:

  1. Systemu Kontroli Wersji – skorzystamuy z GIT for Windows, który do pobrania jest za darmo z oficjalnej strony.
  2. Narzędzia, które pozwoli nam na połączenie różnic pomiędzy wersjami plików. Unity wspiera współpracę z 2 takmi narzędziami. Jednym z nich jest Plastic SCM, drugim jest Perforce.

W tym artykule pokażę pracę z tym drugim. Perforce P4Merge do pobrania jest za darmo ze strony producenta. Polecam wybrać wersję “HELIX P4MERGE: VISUAL MERGE TOOL”, czyli wersję wyposażoną w GUI, dzięki czemu łączenie różnic, będzie nieco łatwiejsze.

Utworzenie projektu

Po instalacji obu narzędzi na komputerze, możemy zająć się stworzeniem testowego projektu w Unity. Następnie musimy wykonać dwie bardzo istotne zmiany. Z głównego paska menu wybieramy “Edit > Project Settings > Editor”. W ustawieniach zmieniamy 2 pola:

  1. Version Control Mode: Visible Meta Files
  2. Asset Serialization Mode: Force Text.
Screen_01
Edit -> Project Settings -> Editor
Screen_02
Zmieniamy parametry

Dzięki tym zmianom dla każdego obiektu w folderze Assets utworzony zostanie plik tekstowy, zawierający o nim wszystkie informacje wymagane przez Unity.

Następnie tworzymy zwykłą kostkę i ustawiamy ją na scenie na pozycji na przykład (2, 0, 0) po czym zapisujemy scenę, projekt i zamykamy Unity.

Screen_03
Ustawiamy testową kostkę na scenie

Uworzenie repozytorium

Wchodzimy na stronę bitbucket . Jeżeli nie mamy konta, możemy je w tej chwili założyć za darmo.

Po zalogowaniu z górnego paska menu wybieramy zakładkę “Repositories > Create repository”.

Wybieramy odpowiednią opcję
Wybieramy odpowiednią opcję

Wpisujemy nazwę naszego repozytorium – u mnie jest to “test”. Rozwijamy zakładkę settings i z niej wybieramy język w jakim będzie projekt – u mnie jest to C#. Teraz możemy kliknąć “Create repository”.

Tworzymy repozytorium
Tworzymy repozytorium

Stronę, która nam się otworzyła zostawiamy tymczasowo w przeglądarce – będzie nam potrzebna za moment.

Nowe okno po utworzeniu repozytorium
Nowe okno po utworzeniu repozytorium

Konfiguracja GIT’a

Wchodzimy w folder z naszym projektem. Klikamy PPM, a następnie wybieramy “Git Bash Here”.

Lokacja odpowiedniego menu
Lokacja odpowiedniego menu

Jak widzimy otwarta została konsola Git’a, w której będziemy wpisywać nasze polecenia.

Konsola Git'a
Konsola Git’a

Dla osób które pierwszy raz korzystają z Git’a należy wpisać nazwę użytkownika oraz adres e-mail korzystając z 2 komend:

git config --global user.name "nazwa_użytkownika"
git config --global user.email "adres_email"

Kolejną rzeczą jaką należy zrobić, to utworzyć plik .gitignore. Czym jest plik .gitignore? Jest to plik tekstowy w którym określamy jakie pliki lub katalogi chcemy zignorować. Pliki oraz foldery zawarte w pliku .gitignore nie zostaną zapisane w repozytorium – będą widoczne tylko lokalnie na naszym komputerze. Jeżeli ktoś zastanawia się dlaczego jest to potrzebne podaję krótki przykład.

W folderze z projektem przechowujemy bardzo wiele rzeczy, które dla współpracujących z nami nie będą w cale potrzebne, a zwyczajnie będą zwiększać wagę repozytorium i zmniejszać czytelność tego co w nim się znajduje. Przykładem folderu, który nie jest potrzebny jest np folder “Builds”, w którym zapisujemy zbudowane aplikacje. Inne przykłady to np pliki .userprefs czy folder Library.

Plik .gitignore tworzymy wpisując w konsoli komendę touch .gitignore, po czym zatwierdzamy enterem.

Tworzymy plik gitignore
Tworzymy plik gitignore

W pliku z projektem utworzył się nam pusty plik. Otwieramy go i wklejamy zawartość pliku .gitignore, możecie pobrać tutaj: gitIgnore. Po czym zapisujemy go i zamykamy.

Teraz musimy poinformować Git’a z jakich narzędzi do mergowania chcemy korzystać. W naszym przypadku będą takie dwa:

  1. UnityYAMLMerge – narzędzie, które otrzymujemy wraz z Unity, które umożliwia mergowanie (łączenie) zmian na scenie, oraz w prefabach. W wielu przypadkach sam YAML wystarczy, niestety zdarzają się przypadki (konflikty), które musimy rozwiązać ręcznie. Do tego potrzebne nam będzie narzędzie numer dwa.
  2. Perforce P4Merge – umożliwia nam ręczne połączenie plików w których wystąpił konflikt.

Przechodzimy do konsoli i wpisujemy komendę git config –global –edit i zatwierdzamy enterem.

Koniguracja
Komenda konfiguracji

Pokaże nam się okno w którym znajdziemy informacje dotyczące konfiguracji gita na naszym komputerze (np. nazwę i adres email użytkownika, które przed chwilą wpisaliśmy). Mamy tez możliwość wpisania z jakich narzędzi do mergowania chcemy korzystać i to właśnie teraz zrobimy.

Przekopiujmy do konsoli: (aby mieć możliwość edycji tekstu w konsoli musimy wcisnąć klawisz insert, natomiast aby przekopiować tekst ze schowka używamy skrótu ‘shift’ + ‘insert’):

[merge]
tool = unityyamlmerge
[mergetool "unityyamlmerge"]
trustExitCode = false
cmd = 'C:\\Program Files\\Unity 5.4.0b15\\Editor\\Data\\Tools\\UnityYAMLMerge.exe' merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"
[mergetool "p4merge"]
path = C:/Program Files/Perforce/p4merge.exe

Ważne teraz są 2 rzeczy:

  1. Ścieżka do pliku UNITYamlMerge.exe pokazana wyżej, jest ścieżką domyślną i jeżeli podczas instalacji Unity jej nie zmienialiście to powinno wszystko działać. Polecam jednak mimo wszystko odnalezienie tego pliku na dysku i sprawdzenie, czy ścieżka jest prawidłowa. (Zwróćcie uwagę na podwójne, lewe ukośniki!)
  2. Ścieżka do pliku p4merge.exe. Znów, jeżeli jest to ścieżka domyślna to będzie ona wyglądać tak jak wyżej, jeżeli nie, należy odnaleźć plik na dysku i wpisać do niego odpowiednią ścieżkę.

Po zmianach plik config powinien wyglądać tak:

Poprawny plik config
Poprawny plik config

Teraz możemy nacisnąć klawisz ‘esc’ co spowoduje wyjście z trybu wprowadzania zmian, a następnie wpisać :wq i zatwierdzić enterem. Powinniśmy wyjść do głównego okna konsoli Git’a.

Następnym krokiem jest edycja pliku “mergspecfile”. Znajduje się on w tej samej lokalizacji co plik UnityYAMLMerge.exe.

Lokalizacja pliku
Lokalizacja pliku

Następnie otwieramy plik i zmieniamy linijki znajdujące się pod “# Perforce merge” na jedną linijkę:

" * use "%programs%\Perforce\p4merge.exe" "%b" "%l" "%r" "%d" "

Ponownie musimy podać ścieżkę do pliku p4merge.exe. Dla wyjaśnienia: symol “%programs%” zastępuje ścieżki “C:\Program Files” oraz “C:\Program Files (x86)”. Jeżeli program p4merge zainstalowaliśmy w innym miejscu na dysku, podajemy do niego odpowiednią ścieżkę. Plik zapisujemy i zamykamy.

Modyfikacja pliku
Modyfikacja pliku

Dodanie projektu do repozytorium

W tym momencie zakończyliśmy konfigurowanie narzędzi i możemy zabrać się za dodanie projektu do repozytorium, oraz przetestowanie narzędzi w akcji.
Na początek dodajemy projekt do repozytorium.

Przechodzimy do przeglądarki. Na panelu z lewej strony wybieramy zakładkę “Overview”. W oknie które nam się pojawiło rozwijamy panel “I have an existing project” i kopiujemy z niego drugą linijkę, która wygląda tak: “git remote add origin https://NazwaUżytkownika@bitbucket.org/NazwaUżytkownika/test.git”.

Linijka do skopiowania
Linijka do skopiowania

W folderze z projektem otwieramy konsolę i wpisujemy pojedynczo następujące komendy:

git init
git add .
git commit -m 'nazwa commita'
git remote add origin https://NazwaUżytkownika@bitbucket.org/NazwaUżytkownika/test.git
git push -u origin --all
  1. git init – inicjalizuje puste repozytorium git,
  2. git add . – dodaje wszystkie zmodyfikowane i nowe pliki do zainicjalizowanego repozytorium,
  3. git commit -m ‘commit pierwszy’ – jest to zatwierdzenie dokonanych zmian w projekcie i dodanie ich do lokalnego repozytorium,
  4. git remote add origin – łączy lokalne repozytorium ze zdalnym repozytorium na Bitbucket’cie,
  5. git push -u origin –all – dodaje zmiany do zdalnego repozytorium.

Test

W porządku, dodaliśmy nasz projekt do repozytorium. Pora dodać konflikty w scenie i wypróbować zainstalowane narzędzia.

Musimy mieć 2 wersje projektu, aby zasymulować zmiany jakie mogłaby dokonać osoba współpracująca z nami, dlatego pierwszym krokiem jest sklonowanie projektu z repozytorium do folderu na komputerze.

Aby sklonować projekt wchodzimy na naszą stronę na Bitbucket’cie. W lewym górnym rogu klikamy na ikonkę clone i kopiujemy zawartość do schowka.
Następnie otwieramy folder na komputerze do którego chcemy skopiować projekt. Otwieramy konsole Git’a(PPM > Git bash here). Do konsoli wklejamy zawartość schowka (‘shift’ + ‘insert’) i zatwierdzamy enterem. Zostaniemy poproszeni o podanie hasła do konta Bitbucket. Po wpisaniu hasła projekt zostanie sklonowany do katalogu na komputerze.

W tym momencie mamy 3 wersje projektu. Jedną na repozytorium, oraz dwie na naszym komputerze.

Otwieramy jeden z projektów (bez znaczenia który – ja otworzę pierwszy utworzony projekt) i dokonujemy zmian.

Najprostszym konfliktem na scenie jest konflikt położenia obiektu. Zmieńmy położenie kostki na np (-5, 0, 0), zapiszmy i zamknijmy projekt.

Otwórzmy konsolę gita w projekcie w którym dokonaliśmy zmian. A następnie dodajmy zmiany do repozytorium. Dla przypomnienia komendy które musimy wpisać:

git add .
git commit -m 'nazwa commita'
git push
Zapisujemy zmiany w repozytorium
Zapisujemy zmiany w repozytorium

Okej, dodaliśmy zmiany do repozytorium. Otwórzmy teraz drugi projekt – jeżeli nie widzimy kostki to znaczy, że musimy otworzyć scenę, na której znajduje się kostka. Jak widać kostka znajduje się w miejscu (2, 0, 0). Nic dziwnego, w końcu pobraliśmy projekt z repozytorium, natomiast zmiany wprowadzone w pierwszym projekcie zostały dodane do repozytorium później.

Zmieńmy położenie kostki na np: (6, 0, 0), zapiszmy scenę i wyłączmy Unity.

Teraz pora na to na co czekaliśmy. Spróbujmy dodać zmiany do repozytorium. Wpisujemy:

git add
git commit 'nazwa comita'
git push
Błąd przy dodawaniu
Błąd przy dodawaniu

Jak widać push został odrzucony. Nasz projekt jest w tym momencie “za projektem” na repozytorium. Aby teraz coś zdziałać, musimy najpierw pobrać zmiany do naszego projektu, a dopiero później będziemy mogli wrzucić nasze modyfikacje do repozytorium. Aby pobrać projekt używamy komendy git pull.

Jak widzimy nie udało nam się pobrać projektu z repozytorium, ponieważ występuje konflikt na scenie. Na szczęście jesteśmy na to przygotowani i mamy narzędzie które nam pomoże. Wpisujemy komendę:

git mergetool --tool=unityyamlmerge

Ponieważ jest konflikt na scenie z którym YAML nie jest w stanie sobie poradzić otworzy nam się okno programu p4merge, abyśmy mogli ręcznie usunąć konflikty.

Okno ręcznego usuwania konfliktów
Okno ręcznego usuwania konfliktów

W oknie programu znajdziemy 3 okna:

  • lewe – source (źródło), wersja z repozytorium,
  • środkowe – baza, czyli nasz oryginalny plik,
  • prawe – target, czyli zmiany które wprowadziliśmy w projekcie.

Wszystkie trzy możliwości są pokazane w oknie wynikowym na dole ekranu. Wersję, którą chcemy ostatecznie zaakceptować wybieramy klikając na ikony po prawej stronie ekranu.

Wybierzmy wersję w której nasza kostka położona jest na pozycji (6, 0, 0). Zapisujemy zmiany i wychodzimy z programu (skróty ‘ctrl’ + ‘s’ oraz ‘ctrl’ + ‘w’, lub używając komend z górnego paska menu file > save, file > exit).

Po wyjściu z p4merge’a powinno zakończyć się mergowanie. Możemy teraz dodać obecną – najnowszą wersję projektu do repozytorium. Wpisujemy komendy:

git add .
git commit -m 'polaczone projekty'
git push

Tym razem pushowanie odbyło się bez żadnych problemów. Otwórzmy projekt nr 2 i spójrzmy czy kostka cały czas znajduje się na pozycji (6, 0, 0). Kostka faktycznie znajduje się na dobrym miejscu (zauważmy, że gdybyśmy wybrali położenie kostki (-5, 0, 0) podczas mergowania, to byłaby to nowa pozycja kostki).

Sprawdźmy teraz co z pierwszym projektem. Pobieramy najnowszy projekt (używając komendy “git pull”).

Pobieramy ostatnie zmiany
Pobieramy ostatnie zmiany

Widzimy że projekt pobrał najnowsze zmiany automatycznie.

Otwórzmy projekt nr 1 i przekonajmy się czy kostka zmieniła swoje położenie z (-5, 0, 0) na (6, 0, 0). Faktycznie kostka zmieniła swoje położenie, co oznacza że udało nam się prawidłowo skonfigurować narzędzia do usuwania konfliktów.

Możliwe problemy

Dla uproszczenia w powyższym przykładzie korzystaliśmy tylko z jednej kostki na scenie. Nie utworzyliśmy z tej kostki prefaba, a niestety przy prefabach pojawia się problem o którym chciałbym teraz wspomnieć. Ponieważ zdaję sobie sprawę, że dla osób które skorzystają z wymienionych metod będzie to na pewno przydatne. Nie chciałbym opisywać tutaj wszystkiego jeszcze raz od początku, ponieważ nie miałoby to sensu, dlatego opiszę co zrobiliśmy inaczej i zaprezentuję na jaki błąd możemy się natknąć.

Jedyną zmianą jest zamiana kostki na scenie na kostkę w prefabach. Wyobraźmy sobie, że zamiast zostawiać kostkę na scenie, przeciągamy ją do prefabów, a kostkę ze sceny usuwamy. To tyle. Od tego resztę zmian dokonujemy identycznie, tylko że na prefabie. W momencie gdy będziemy próbowali pobrać do projektu zmiany z repozytorium używając komendy “git pull” zostaniemy poinformowani o konflikcie, zupełnie tak jak wcześniej. Jeżeli następnie spróbujemy użyć YAML’a (korzystając z komendy git mergetool –tool=unityyamlmerge ) otrzymamy błąd:

Błąd przy prefabie
Błąd przy prefabie

Nie chciałbym zagłębiać się w to, czym spowodowany jest ten błąd. Został on zgłoszony już dawno temu i niestety Unity ciągle go nie naprawiło.

Po kliknięciu “OK”, zostaniemy zapytani czy merge zakończył się powodzeniem? Odpowiadamy zgodnie z prawdą, że nie (n).

Następnie zostaniemy zapytani Czy kontynuować mergowanie dla innych elementów? odpowiadamy, że tak (y). W zależności od ilości zmian możemy otrzymać to samo pytanie jeszcze kilka razy. Jeżeli YAML poradzi sobie z danym elementem, to otrzymamy następne pytanie, jeżeli nie, otworzy nam się okno z programem p4merge i możliwością ręcznego rozwiązania konfliktu. Czynność powtarzamy dopóki nie zakończą się pytania.

Ale nie zapomnijmy o najważniejszym – w końcu z jakiegoś powodu otrzymaliśmy błąd. Cóż, wynika to z tego, że wystąpił konflikt w prefabie – niestety nie otworzyło nam się okno p4merge’a z możliwością usunięcia konfliktu, dlatego wywołujemy je sami wpisując:

git mergetool --tool=p4merge

Teraz od razu otworzy nam się okno programu, gdzie będziemu mogli usunąć konflikt.

A co z OS Xem

Możliwe, że dla niektórych korzystających na co dzień z urządzeń firmy Apple przydatna będzie informacja, że wszystkie kroki wykonujemy identycznie. Jedynie czego użytkownicy Mac’a nie muszą robić to instalacja “Git for Windows”, ponieważ funkcjonalności tego programu mają dostępne od razu w terminalu.

Kwestie końcowe:

Zdaję sobie sprawę, że ilość kroków potrzebnych do wykonania jest bardzo duża, a łączenie zmian w plikach nie jest zbyt intuicyjne. Niestety na chwilę obecną nie znam lepszej metody, która pozwoliłaby na współpracę wielu osobom na raz. Jednak dla wszystkich, którzy potrzebują takich narzędzi, ale na bieżąco nie śledzą zmian prezentowanych przez Unity mam coś na pocieszenie.

Na konferencji GDC 2016, o której Marek wspominał w osobnym poście. Unity zaprezentowało narzędzie Unity Collaborate, który pozwoli na dużo łatwiejszą pracę w grupach wieloosobowych. Niestety dla nas ten system jest dopiero w wersji zamkniętej Alfy, co oznacza, że zanim trafi w nasze ręce przyjdzie jeszcze trochę czasu poczekać.