Kolejna recenzja dla Was, czytelnicy! Z racji konieczności uzupełniania luk wiedzy celem zwiększenia szans na zatrudnienie, sięgnąłem po raz drugi po lekturę dotyczącą silnika "Unity", co dałem wyraźnie do zrozumienia w poprzednim artykule z tego cyklu, i tak oto macie przed sobą pełną oraz (mam nadzieję) rzetelną recenzję lektury tego samego autora, "Unity na start! Programowanie dla nastolatków"! Usiądźcie sobie wygodnie na czymkolwiek i dowiedzcie się jak odbieram wspomniany tytuł stworzony zarówno dla dzieci, jak i rodziców!
Tweet |
CZY RZECZYWIŚCIE KSIĄŻKA "UNITY NA START! PROGRAMOWANIE DLA NASTOLATKÓW", JEST DOBRA NA START?
Mocno się spóźniłem z recenzją, bo zakładałem pierwotnie że uda się to wypuścić na początku maja, a tu mamy już trzeci tydzień. Studia nie dają za dużo możliwości złapania tchu, mimo ciągłego odmawiania sobie wypoczynku na słońcu przy bardzo ładnej pogodzie :(.
Dzieło jest już drugim przeze mnie przeczytanym z rzędu, który napisał Pan Jacek Ross. Książka wyróżnia się od innych sposobem przekazu informacji, tak aby zrozumiał i opanował je każdy czytelnik, niezależnie od wieku. Uwzględniono dwa punkty widzenia, gdyby lekturę trzymał w rękach rodzic lub podopieczny.
Jak rozwinąć myśl, żeby nie spoilerować? Książka jest pół-podręcznikiem, pół-powieścią. Co każdy rozdział mamy coś w rodzaju wątku fabularnego (pojawia się narrator i są dialogi), a później są kroki do wykonania jeden po drugim ujęte już bardziej formalnie co należy zrobić. Całość kręci się wokół projektowania zabawnego projektu, w którym gracz steruje hamburgerem i strzela pysznym mięskiem w zdrowe warzywa :D.
Ogólnie wszystko się ładnie zazębia od zbierania zasobów do gry z domeny publicznej, przez tworzenie interakcji pomiędzy obiektami przy użyciu "Unity Playground" z gotowymi skryptami zmodyfikowanymi lub od nowa przygotowanymi przez autora, aż do tworzenia walki z bossem razem z przejściem do następnego poziomu ;), a na deser jest budowa gry na systemy Windows. Całość wieńczy słowniczek pojęć, które wplątały się w fabułę opisującą dyskusję pomiędzy ojcem a synem, kilkanaście pytań i odpowiedzi na styl FAQ oraz lista kodów źródłowych (część stanowi zmodyfikowane komponenty "Unity Playground", a część została napisana od początku). Poznałem parę cennych porad jak się uczyć "game dev'u", które umieszczone są w finalnym rozdziale oraz dowiedziałem się o istnieniu samego pakietu "Unity Playground", więc wcale nie żałuję, że sobie wziąłem tę książeczkę i przeczytałem ;). Zgrało się to całkiem nieźle, choć jak to w każdej lekturze pojawiło się wiele "ale". Zaraz sobie rozpiszemy te wszystkie "ale", tylko w pierwszej kolejności wiecie co ;):
Recenzując książkę autorstwa Pana Jacka Rossa oraz Ksawerego Rossa i prezentując swoje zdanie na jej temat, nie leżało w mojej intencji żadne złośliwe wytykanie błędów ani ośmieszenie. Jedynym moim celem publikacji recenzji było przedstawienie swojej subiektywnej opinii oraz sprostowanie pewnych przytoczonych treści, aby ewentualne ponowne wydanie książki było pozbawione wskazanych błędów, jeśli faktycznie takimi są (bo sam mogę się mylić!).
Startujemy z ujawnianiem błędów lektury "Unity na start! Programowanie dla nastolatków"!
GRZESZKI KSIĄŻKI
Niestety, w odróżnieniu od lektury tego samego pana na temat "LEGO Microgame", tutaj znalazło się mnóstwo chochlików dziennikarskich i niedopowiedzień wymagających mojej jak najszybszej interwencji. Najpierw grubsze, potem chudsze, aż przejdziemy do literówek.
"WOLNA AMERYKANKA" Z USTAWIENIAMI
Rozpocznę od problemu, który "rozlewa się" chyba na rekordową liczbę stron w tej książce. Często doświadczyłem sytuacji, w której gdy starałem się domyślić poszczególnych kroków z samej historyjki zanim przeszło się do "Kroków do wykonania" w ujęciu "tutorialowym" (zrób to, zrób tamto), zdarzało się że trzeba było ponownie przejść przez wszystkie kroki, gdyż po stronie historyjki była tylko opisana czynność, a po stronie listy kroków były już konkretne liczby lub ustawienia dla pozycji, atrybutów i tym podobnych rzeczy. Chodzi mi o to, że dopiero pod koniec rozdziału pojawiały się szczegóły odnośnie wprowadzanych wartości. Ja wiem, że nie wszystkie są obowiązkowe, jednakże czytelnik kiedy jest kompletnie zielony i chce się nauczyć poruszanych zagadnień, będzie z pewnością naśladować wykonywane czynności napisane przez autora. I jak będzie napisane o pozycji X równej 5.5, to znaczy że najlepiej taką wprowadzić.
Choć rodzi to konieczność powracania do poprzednich kroków i edytowanie wartości, to rozumiem że ciężko można temu w pełni zapobiec, bo dialog prezentuje zagadnienie w wersji "light" w formie historyjki, więc trudno się spodziewać sztywnego formalnego słownika, choć pojawia się część obcojęzycznych fraz i niezrozumiałych wyrazów. Wspomniany problem jest na tyle poważny, że niektóre wartości przeczą tym podanym w dialogu. Mianowicie:
- brak informacji o przesunięciu obiektu "PanBurgerDol" w osi X
- Dialog (strona #38):
"[...] zmień pole Position/Y na -1.4."
- Kroki do wykonania (strona #41):
"[...] zmień wartość pola Y na -1.4, a pola X na 0.5."
- Dialog (strona #38):
- niespójność przypisywanych wartości atrybutom "Linear Drag" i "Speed"
- Dialog (strona #47):
"Ustaw pole na 20, a dodatkowo w komponencie MoveWithArrows parametr Speed zwiększmy na 15 [...]"
- Kroki do wykonania (strona #51 i #52):
"Friction ustaw na 20 [...]" "W komponencie MoveWithArrows ustaw pole Speed na 20 […]"
Rysunek 5.1 pokazuje wartość atrybutu "Linear Drag" ("Friction") w komponencie "Rigidbody2D" równą 15, a atrybut "Speed" w komponencie "MoveWithArrows" na 20
- Dialog (strona #47):
- niespójność przypisywanej wartości tekstowi wyświetlającemu punkty zdrowia gracza (najpierw minuskuły, a potem majuskuły)
- Dialog (strona #60):
"Zmień je na zdrowie [...]"
- Kroki do wykonania (strona #65):
"Zmień zawartość pola Text na ZDROWIE [...]"
- Dialog (strona #60):
WYBRAKOWANE INSTRUKCJE
W "Unity na start! Programowanie dla nastolatków" w każdym rozdziale występuje po dialogu część zwana "Kroki do wykonania", w której znajduje się uszczegółowienie czynności do wykonania w ujęciu formalnym. Zauważyłem w pewnych miejscach błędy w postaci źle użytego, bądź brakującego słowa. Nie jestem gołosłowny, bowiem dopatrzyłem się następujących sformułowań wymagających poprawki:
- strona #125 ("Kliknij obiekt StrzałSer w oknie hierarchii i wybierz Prefab/Unpack Completely.")
- brak informacji o tym, że aby otworzyć menu kontekstowe posiadające opcję "Prefab/Unpack Completely", należy kliknąć prawym przyciskiem myszy
- strona #126 ("Przejdź do inspektora i zaznacz pole Filter By Tag, a w polu Filter Tag wpisz wartość Player.")
- brak informacji o komponencie "Modify Health", które posiada wspomniane atrybuty "Filter By Tag" oraz "Filter Tag"
- rysunek na stronie #128
- brak polecenia przypisania wartości "Size" w osi Y w komponencie "Collider2D" równej 10
- brak polecenia zaznaczenia opcji "Relative To This Object" w komponencie "Create Object"
- strona #145
- brak polecenia utworzenia prefaba obiektu "PociskChili" (w ostatnim punkcie występuje zdanie: "[...] zmień wartości pola Prefab To Spawn komponentu Object Creator Area na PociskChili.", co sugeruje konieczność uprzedniego utworzenia prefaba)
- strona #152 ("Dodaj obiektowi ScianaSygnal komponenty: Collider 2D i Rigidbody 2D")
- brak doprecyzowania jaki to ma być konkretnie komponent wykrywacza kolizji ("Collider2D" jest klasą nadrzędną wszystkich rodzajów)
ZABRAKŁO WAŻNEJ RZECZY!
Strona #41 lektury tłumaczy jak uczynić obiekty podobiektami innych obiektów (żeby były ich "dziećmi"). Jak byk widnieje taki punkt:
"Przesuń obiekt PanBurgerGora do wnętrza PanBurgerCaly, ponad obiekt PanBurgerDol."
Ja bym dodał kolejny punkt zaraz po tym, żeby koniecznie zresetować komponent "Transform", gdyż wartości niezerowe mogą później mieszać kiedy obiekt staje się częścią innego. Ale tylko to, słowo!
ATRYBUT WIDMO
To jest strona #43. Na niej znajdziecie taki akapit o komponencie "Camera" i o atrybutach "ClippingPlanes" oraz "FieldOfView" (BTW, nazwy zostały źle napisane, bo słowa są osobno - więcej w sekcji o literówkach). Kłopot w tym, że tego drugiego nie ma! Kamera nie posiada takiego atrybutu jak "Field of View", po prostu nie! Być może dlatego, że "Unity" jakoś wykrywa że jest to projekt 2D i w takim wypadku jasne jest, że ustawianie pola widzenia dla obiektów płaskich jest już mniej sensowne niż dla układu przestrzennego. Nie jest to też ukrywane przez pakiet "Unity Playground", bo poklikałem "Turn Playground on" i "Turn Playground off" restartując silnik, a opcja nie pojawiła się w żadnym z przypadków. Tak czy siak, nie znalazłem żadnego "Field of View".
Jeszcze moment. Nie twierdzę, że go tam nigdy nie było. Ja podczas projektowania gry razem z książką, korzystałem z wersji 2021 i może ten atrybut został w nowszej wersji przeniesiony gdzieś indziej, dlatego też nie ma o co robić dymu (sama książka "Unity na start! Programowanie dla nastolatków" powstała w 2021 roku, więc "miała prawo").
WŁAŚCIWE INSTANCJE NA NIEWŁAŚCIWYM MIEJSCU
Sięgamy do strony #149, czyli do początku rozdziału 14 ("Wchodzimy na wyższy poziom"). Dwaj główni bohaterowie rozpatrują zagadnienie w jaki sposób zachować punktację i punkty zdrowia po przejściu do kolejnej sceny za pomocą komponentu "Load Level". Zgadzam się z tym, że wraz z załadowaniem nowej sceny, obiekty "OpakowanieGry" i "InterfejsUzytkownika" będą powielone. Tylko potem pada zdanie, które mnie zbiło z tropu:
"Wtedy będą po dwa razy na scenie i gra nie będzie działać."
Być może ja to źle zrozumiałem myśląc że autorowi chodzi o to, że dwie instancje BYŁYBY na tej samej scenie, gdyby nałożyło się skrypt wywołujący metodę "DontDestroyOnLoad". "Byłyby", ponieważ dopiero po tej wypowiedzi jest mowa o dodaniu komponentu skryptowego, "NieNiszczMnie", w którym to można znaleźć wywołanie powyższej metody. Bez tego, nie ma mowy o przeniesieniu "starych" obiektów z jednej do drugiej sceny, i tym samym o natrafieniu na duplikaty BEZ USUWANIA OSOBNYCH INSTANCJI W DRUGIEJ SCENIE. Coś tu się nie zgadza logicznie...
PÓŹNE UŚWIADOMIENIE
Strona #84, miśki. Trochę nie spodobał mi się ten fragment zdania:
"[...] wybierz nasz StrzalWolowina z okienka Assets."
Co w nim takiego nieodpowiedniego? Zleciało jakieś dwadzieścia wersów od pierwszego napomknięcia o obiekcie pocisku wołowiny ("Wrzuć więc na scenę kawałek mięsa z zasobów graficznych [...]"), a o samej nazwie dowiaduję się dopiero z tego miejsca. Krótko pisząc - zleciało zbyt wiele tekstu, żeby dowiedzieć się jaką nazwę nadać obiektowi, jak już zdążyło się ten obiekt zrobić. Ponadto ten fragment jest tak napisany, jakbyśmy już byli wprowadzeni wcześniej w temat, a nigdzie wcześniej nie ma podanej nazwy "StrzalWolowina". Powinno się dodać wzmiankę o nadaniu nowej nazwy w momencie robienia z obiektu prefaba, tak by było chyba najlepiej...
SPRZECZNOŚĆ
Kolejna pomyłka wykryta tym razem na stronie #127. Streszczając jak się tylko da, chodzi o złe przekazanie informacji w treści instrukcji. To mogłoby wylądować w "Wybrakowanych instrukcjach", aczkolwiek tu mamy do czynienia z niepoprawną wartością aniżeli jej brakiem. Padają takie zdania:
"[...] wpisz wartości pól: Offset X=2.5 [...]"
"[...] ustaw obiekt i jego kolider tak, aby przesłaniał połowę lewej strony obrazka tła."
Przepraszam, tylko jak ustawię zgodnie z poleceniem, to przesłonię połowę PRAWEJ strony, bo przesunięcie w osi X ma wartość dodatnią ;).
NADMIAR SKALI
Strona #52 dała mi do myślenia. Mowa o skalowaniu obiektu robiącego za niewidzialną ścianę, na którą nałożono komponent "BoxCollider2D". Zastanowiło mnie po co skalować cały obiekt jak wystarczy tylko zmienić rozmiar samego wykrywacza kolizji (atrybut "Size")??? Gdyby nałożyło się jakąś grafikę, to raczej dostosowywałoby się wykrywacz kolizji do grafiki, a nie rozciągało cały "sprite", prawda?
"PLAY" Z KAŻDEGO MIEJSCA W "UNITY"!
"[...] wciśnij przycisk Play w oknie Game"
Taki fragment ujrzycie na stronie #27. Małe sprostowanko: przycisk do odtwarzania sceny "Play" nie należy do okna "Game", tylko jest bezpośrednio nad nim. Można się do niego dostać bez przechodzenia do okna "Game". Jest możliwość kliknięcia mając otwarte okno "Scene" na przykład, jak również każde inne.
"ALSO NOT KNOWN AS"
Strona #136 zastanowiła mnie w kontekście wspominania autora wykorzystywanych paczek dźwięków na potrzeby realizacji projektu. Raz jest wspominana nazwa użytkownika ("[...] autorstwa Qubodup [...]" stronę wcześniej), a raz autor. Z ciekawości zajrzałem na stronę wykorzystywaną w książce i chodzi o tego samego autora, a myślałem pierwotnie że to ktoś inny. Nie lepiej trzymać się jednego określenia?
I DO SPEAK POLSKA
Podpis rysunku na samym dole strony #146 brzmi tak:
"Stan pola Layer Collision Matrix w sekcji fizyki 2D ustawień projektu"
Może to jest robienie z igły widły, jednak nazwy najlepiej żeby były używane już w jednym języku, a nie tak pół na pół. Było wcześniej "Physics 2D", niech już tak zostanie. "Project Settings" i wszystko jasne.
KOPIUJ, WKLEJ. DOSŁOWNIE!
Czy spostrzegliście, że na stronie #190 został powtórzony nie tyle sam kod źródłowy, co wręcz cały rozdział o skrypcie "SkryptWzmocnien"? Być może planowano wstawić inną treść o podobnej nazwie lub liczbie linijek. Nie wnikam.
"UNITY PLAYGROUND" PRZEZ DUŻE P!
Miszmasz dotyczący nazywania katalogu pojawił się również na stronie #27, na której jest treść dotycząca konieczności utworzenia folderu dla pakietu "Unity Playground". Właśnie...w zasadzie to "Unity playground", bo tak jest na rysunku. Stronę dalej widzimy odwołania do katalogu nazwanego "Unity playground" małą literą, a powinno się wielką, zgodnie z poleceniem. Niespójność potrafi człowieka zatrzymać na dłuższą chwilę ;).
NOT AGAIN!
W poprzednio recenzowanej lekturze było o "klikaniu klawiszy". Być może się czepiam, jednak nie uznaję tego za poprawne sformułowanie. Tak samo jest w "Unity na start! Programowanie dla nastolatków" i to w kilku miejscach. Są to:
- "[...] kliknij klawisz Enter." (strona 42)
- "[...] po kliknięciu klawisza strzałki [...]" (strona 46)
- "[...] spowodowanej kolejnym kliknięciem klawisza." (strona 47)
POWOŁYWANIE SIĘ NA NIEZGODNĄ WERSJĘ "UNITY"
Drobna sprawa na stronie #21, choć przykuło to moją uwagę. Pod sam koniec strony, pada takie zdanie:
"Na rysunku 2.1 jest to wersja Unity 2020.2.1f1 [...]"
A jak się przyjrzymy wspomnianemu rysunkowi, to na nim widać wersję 2020.1.12f1. Mamy cyfrową niezgodność!
NIE TYLKO STĄD POCHODZI SŁOWO "BUG"
Kurs na stronę #179, tam gdzie w książce "Unity na start! Programowanie dla nastolatków" zaczyna się "Mały słowniczek języka graczy". Nie mam nic do wyjaśnień pochodzenia słowa "bug", bo jest napisane elegancko. Ja bym tylko uzupełnił o parę zdań na temat niejakiej Grace Hopper i jej raporcie z 1947 roku na temat awarii systemu spowodowanej przez wlatującego tam owada. Warto wiedzieć o samej genezie tego pojęcia.
KODY ŹRÓDŁOWE
Zanim obejrzycie sobie zbiór wykrytych literówek, zostawiłem podobny spis zastrzeżeń co do pozostawionych treści kodów źródłowych na samym końcu książki. Trochę czasu programuję, żeby zwrócić uwagę na formatowanie czy powtarzalność i nie mogę przejść obojętnie obok tych szczegółów. "Unity na start! Programowanie dla nastolatków" czeka "generalny remont" jednym zdaniem, jeśli chodzi o skrypty. Oto co mi nie pasowało (bez urazy i dokuczania, powtarzam ponownie!):
- "AudioAction" (strona 183-184)
- wszystkie dane składowe mają nazwy pisane wielką literą (przeczy to konwencji nazewniczej)
- brak odstępu pomiędzy danymi składowymi, a metodą
- brak odstępu pomiędzy instrukcją, a instrukcją "return"
- "AutoMoveNoPhysics" (strona 184)
- brak odstępu pomiędzy dyrektywą "using", a nagłówkiem klasy
- zbędny odstęp nawiasów okrągłych od nazwy metody "FixedUpdate"
- niewłaściwa metoda do translacji obiektu przy użyciu komponentu "Transform" (powinna być "Update" zamiast "FixedUpdate", bo jest przeznaczona do kalkulacji fizyki, a obiekt nie wymaga komponentu "Rigidbody2D" ani zaznaczenia typu "Kinematic", które pozwala na translację przez "Transform" mimo posiadania tego komponentu)
- brak przemnożenia zmiany pozycji przez właściwość "Time.deltaTime" (prędkość translacji jest zależna od liczby klatek na sekundę!!!)
- "BezwarunkoweZniszczenie" (strona 185)
- brak zmiennej lokalnej dla przechowania komponentu "ConditionDestroy" (można było uprościć treść instrukcji warunkowej)
- brak odstępu pomiędzy instrukcją, a instrukcją warunkową
- brak odstępu pomiędzy instrukcją, a instrukcją "return"
- "ConditionDestroy" (strona 185)
- "FindEnemyTarget" (strona 186)
- brak odstępu pomiędzy dyrektywami "using", a nagłówkiem klasy oraz pomiędzy danymi składowymi, a metodą
- zła nazwa skryptu sugerująca wyszukiwanie samych przeciwników (lepiej brzmiałoby "FindTargetByTag", bo równie dobrze można wyszukiwać po tagu "Truskawka" :D)
- dana składowa "FollowTag" jest napisana wielką literą (przeczy to konwencji nazewniczej)
- brak odstępu pomiędzy danymi składowymi, a metodami
- brak odstępu między metodami
- brak podziału na mniejsze metody (metoda "Update" ma zbyt wiele instrukcji)
- brak odstępu pomiędzy instrukcjami, a instrukcjami warunkowymi w metodzie "Update"
- brak zmiennej lokalnej dla przechowania komponentu "AutoMove" w metodzie "Update" (można było uprościć treść instrukcji warunkowej)
- "FollowTargetByTag" (strona 186-187)
- brak odstępu pomiędzy dyrektywą "using", a nagłówkiem klasy
- dana składowa "FollowTag" jest napisana wielką literą (przeczy to konwencji nazewniczej)
- brak odstępu pomiędzy daną składową, a metodą
- w instrukcji warunkowej, można było zamienić warunek:
FollowTag != ""
na:
!FollowTag.Empty
- brak odstępu pomiędzy instrukcją, a instrukcją warunkową
- "NieNiszczMnie" (strona 187)
- "PointsAction" (strona 187-188)
- brak odstępu pomiędzy dyrektywą "using", a atrybutem "AddComponentMenu" oraz pomiędzy atrybutem "AddComponentMenu", a nagłówkiem klasy
- brak odstępu pomiędzy danymi składowymi, a metodą
- nieprawidłowe wcięcie metody "ExecuteAction"
- brak odstępu pomiędzy instrukcjami, a instrukcjami "return" w metodzie "ExecuteAction"
- "SkryptPanaBurgera" (strona 188-189)
- brak odstępu pomiędzy dyrektywami "using", a nagłówkiem klasy
- niepotrzebny odstęp przed średnikiem w instrukcji definicji zmiennej o nazwie "PrzesuniecieJednegoObiektu"
- wszystkie publiczne dane składowe mają nazwy pisane wielką literą
- brak odstępu pomiędzy publicznymi, a prywatnymi danymi składowymi
- brak odstępu pomiędzy danymi składowymi, a metodą
- instrukcje warunkowe w pętli "for" w metodzie "Start", powinny być jednym blokiem połączonym słowami kluczowymi "else if" (i tak nie będzie miała miejsca sytuacja, w której jeden obiekt posiada dwie różne nazwy)
- sprawdzanie w instrukcji warunkowej łańcuchów znaków używając operatora porównania w metodzie "Start" i "AktualizujDzialo":
transform.GetChild(i).name _dziala[i].name
a powinno się przez metodę "Equals" (jeszcze lepiej zamienić sprawdzanie nazwy na sprawdzanie tagów i wykorzystanie metody "CompareTag")
- brak metody dla podobnych do siebie instrukcji w metodzie "PrzesunObiekty":
_dziala[i].transform.localPosition = new Vector3(_dziala[i].transform.localPosition.x, _startowyObiekt.transform.localPosition.y + przesuniecie, _dziala[i].transform.localPosition.z); _koncowyObiekt.transform.localPosition = new Vector3(_koncowyObiekt.transform.localPosition.x, _startowyObiekt.transform.localPosition.y + przesuniecie, _koncowyObiekt.transform.localPosition.z);
- brak zmiennej lokalnej dla przechowania obiektu działa typu "GameObject" o nazwie "_dziala[i]" dla metody "AktualizujDzialo" i "PrzesunObiekty" (można było uprościć treść wielu instrukcji)
- brak odstępu pomiędzy różnymi instrukcjami
- brak podziału na mniejsze metody (wszystkie metody mają zbyt wiele instrukcji)
- "SkryptWzmocnien" (strona 189-190)
- brak odstępu pomiędzy dyrektywą "using", a nagłówkiem klasy oraz między metodami
- brak modyfikatora dostępu dla danej składowej "_panBurger" (to żaden problem, tylko z reguły powinno się mimo wszystko podkreślać, że jest to składowa prywatna, nawet jeśli w C# dane składowe są domyślnie prywatne)
- brak odstępu między metodami
- "ModifyHealthAttribute" (strona 190-191)
- brak odstępu pomiędzy dyrektywami "using", a atrybutem "AddComponentMenu" oraz pomiędzy atrybutem "AddComponentMenu", a nagłówkiem klasy
- niespójne wcięcia danych składowych, komentarza i metod
- brak odstępu pomiędzy metodą "OnCollisionEnter2D", a "OnTriggerEnter2D"
- sprawdzanie w instrukcji warunkowej taga po operatorze porównania w metodzie "OnTriggerEnter2D", a lepiej jest przez metodę "CompareTag"
- brak zmiennej lokalnej dla przechowania komponentu "DestroyAction" w metodzie "OnTriggerEnter2D" (można było uprościć treść instrukcji warunkowej)
- "HealthSystemAttribute" (strona 191-192)
- brak odstępu pomiędzy dyrektywami "using", a atrybutem "AddComponentMenu" oraz pomiędzy atrybutem "AddComponentMenu", a nagłówkiem klasy
- brak odstępu pomiędzy publiczną, a prywatnymi danymi składowymi
- brak odstępu pomiędzy daną składową, a metodą "Start"
- brak odstępu pomiędzy instrukcją, a instrukcją warunkową w metodzie "ModifyHealth"
- brak zmiennej lokalnej dla przechowania komponentu "DestroyAction" (można było uprościć treść instrukcji warunkowej)
- brak podziału na mniejsze metody (metody "Start" i "ModifyHealth" mają za dużo instrukcji)
- "Action" (strona 193)
- brak odstępu pomiędzy dyrektywami "using", a nagłówkiem klasy
- brak odstępu pomiędzy daną składową, a metodą
- "ConditionBase" (strona 193-194)
- brak odstępu pomiędzy dyrektywami "using", a nagłówkiem klasy
- prywatna dana składowa ("alreadyHappened") znajduje się w środku danych składowych publicznych
- instrukcję w metodzie "ExecuteAllActions":
actionResult == false
można było uprościć:
!actionResult
choć rozumiem takie użycie ze względu na nazwę
- brak odstępu pomiędzy instrukcją, a instrukcją warunkową
- brak odstępu pomiędzy instrukcją, a instrukcją "return"
- brak podziału na mniejsze metody (metoda "ExecuteAllActions" ma zbyt wiele instrukcji)
- "FollowTarget" (strona 194-195)
- brak odstępu pomiędzy dyrektywami "using", a atrybutami "AddComponentMenu" i "RequireComponent" oraz pomiędzy atrybutami "AddComponentMenu" i "RequireComponent", a nagłówkiem klasy
- brak metody dla powtarzającego się wyrażenia:
(target.position – transform.position)
- brak metody dla powtarzających się wywołań metody "rigidbody2D.MovePosition":
rigidbody2D.MovePosition(Vector2.Lerp(transform.position, transform.position + Vector3.right, Time.fixedDeltaTime * speed)); rigidbody2D.MovePosition(Vector2.Lerp(transform.position, transform.position + kierunek, Time.fixedDeltaTime * speed));
- brak podziału na mniejsze metody (metoda "FixedUpdate" ma zbyt wiele instrukcji)
- "Patrol" (strona 195-197)
- brak odstępu pomiędzy dyrektywami "using", a atrybutami "AddComponentMenu" i "RequireComponent" oraz pomiędzy atrybutami "AddComponentMenu" i "RequireComponent", a nagłówkiem klasy
- brak odstępu pomiędzy publicznymi, a prywatnymi danymi składowymi
- brak odstępu pomiędzy danymi składowymi, a metodą "Awake"
- zmienna lokalna "w" powinna być na samej górze i dzielić ją jeden wiersz odstępu od zmian danych składowych "currentTargetIndex" i "newWaypoints" w metodzie "Start"
- brak odstępu pomiędzy instrukcją, a pętlą "for" w metodzie "Awake" i "Start"
- brak odstępu pomiędzy operatorami, a operandami (argumentami) w instrukcji modyfikującej wartość zmiennej "currentTargetIndex" z wykorzystaniem operatora trójargumentowego, w metodzie "FixedUpdate":
currentTargetIndex = (currentTargetIndex<newWaypoints.Length-1) ? currentTargetIndex +1 : 0;
- brak metody dla powtarzających się wywołań metody "Utils.SetAxisTowards" w metodach "Start" i "FixedUpdate":
Utils.SetAxisTowards(lookAxis, transform, ((Vector3)newWaypoints[1] – transform.position).normalized); Utils.SetAxisTowards(lookAxis, transform, ((Vector3)currentTarget – transform.position).normalized);
- brak metody dla powtarzających się instrukcji normalizującej wektor:
((Vector3)newWaypoints[1] – transform.position).normalized ((Vector3)currentTarget – transform.position).normalized
- zbędna zmienna lokalna "thisPosition" w metodzie "Reset" (można od razu wstawić transform.position, gdyż i tak nie jest to modyfikowane)
- zbędne odstępy nawiasów kwadratowych i okrągłych od nazw w metodzie "Reset" ("waypoints" i "Vector2")
- brak odstępu między metodami
- brak odstępu pomiędzy zmiennymi lokalnymi, a instrukcjami
- brak odstępu pomiędzy instrukcjami, a instrukcjami warunkowymi
- brak podziału na mniejsze metody (metody "Awake", "Start" i "FixedUpdate" mają w sobie zbyt wiele instrukcji)
- niespójne umieszczenie nawiasów okrągłych obok etykiet metod; raz są obok nazwy, a raz dzieli je spacja odstępu
LITERÓWKI I INNE DROBNOSTKI
A teraz literóweczki "Unity na start! Programowanie dla nastolatków", te same kochane i lubiane :). Podzieliłem to na literówki i inne drobne błędy znalezione podczas starannego czytania.
LITERÓWKI
Informuję, że część dotycząca nazw komponentów może być do dyskusji, ponieważ w "Unity" komponenty skryptowe przyjmują obie formy nazw. W plikach zasobów ("assets") nazwy trzymają się konwencji "PascalCase", a jako komponent w menu inspektora słowa są już oddzielane spacją:
- "[...] i faktycznie przetworzenie [...]", zamiast "[...] i faktyczne przetworzenie [...]" (strona 9)
- "[...] w inspektorze pola Scale z 1 na 0.25.", zamiast "[...] w inspektorze pole Scale z 1 na 0.25." (strona 37)
- "[...] w komponencie SpriteRenderer o nazwie OrderInLayer [...]", zamiast "[...] w komponencie Sprite Renderer o nazwie Order in Layer [...]" (strona 39)
- "[...] znajdź komponent o nazwie SpriteRenderer.", zamiast "[...] znajdź komponent o nazwie Sprite Renderer." (strona 41)
- "Ustaw wartość -1 w polu OrderInLayer.", zamiast "Ustaw wartość -1 w polu Order in Layer." (strona 41)
- "[...] Unity powinno znaleźć skrypt o takie nazwie.", zamiast "[...] Unity powinno znaleźć skrypt o takiej nazwie." (strona 42)
- "Nie zapomnij o zmianie wartości OrderInLayer [...]", zamiast "Nie zapomnij o zmianie wartości Order in Layer [...]" (strona 42)
- "[...] w polu FieldOfView komponentu Camera.", zamiast "[...] w polu Field Of View komponentu Camera." (strona 43)
- "[...] pole ClippingPlanes komponentu Camera.", zamiast "[...] pole Clipping Planes komponentu Camera." (strona 43)
- "Zmień po prostu wartość pola TypoOfControl z ArrowKeys na WASD.", zamiast "Zmień po prostu wartość pola Type Of Control z Arrow Keys na WASD." (strona 48)
- "[...] opcję Playground/Turn Playground off [...]", zamiast "[...] opcję Playground/Turn Playground Off [...]" (strona 51)
- "[...] opcję Playground/Turn Playground on [...]", zamiast "[...] opcję Playground/Turn Playground On [...]" (strona 51)
- "[...] tylko będzie LinearDrag.", zamiast "[...] tylko będzie Linear Drag." (strona 51)
- "[...] może nazywać się LinearDrag [...]", zamiast "[...] może nazywać się Linear Drag [...]" (strona 51)
- "[...] pole FreezeRotation [...]", zamiast "[...] pole Freeze Rotation [...]" (strona 51)
- "[...] pole TypeOfControl [...]", zamiast "[...] pole Type Of Control [...]" (strona 51)
- "[...] zielona obwódka będzie pokazana, tylko gdy w oknie inspektora komponent kolidera jest rozwinięty.", zamiast "[...] zielona obwódka będzie pokazana, tylko gdy w oknie inspektora komponent kolidera jest włączony." (zwijanie komponentu nie wpływało na widok obwódki, strona 53)
- "[...] pole PointsWorth na 5.", zamiast "[...] pole Points Worth na 5." (strona 71)
- "[...] o nazwie P_explosion [...]", zamiast "[...] o nazwie P_Explosion [...]" (strona 73)
- "P_explosion powstał jako kopia [...]", zamiast "P_Explosion powstał jako kopia [...]" (strona 73)
- "[...] komponent o nazwie ParticleSystem.", zamiast "[...] komponent o nazwie Particle System." (strona 74)
- "Znajdź zasób P_explosion [...]", zamiast "Znajdź zasób P_Explosion [...]" (strona 78)
- "[...] wypełniając pole Actions [...]", zamiast "[...] wypełniając pole Gameplay Actions [...]" (strona 84)
- "Ustaw wartość mouse 0", zamiast "Ustaw wartość Mouse 0" (strona 85)
- "Wartość JustPressed [...]", zamiast "Wartość Just Pressed [...]" (strona 85)
- "Ustaw KeptPressed [...]", zamiast "Ustaw Kept Pressed [...]" (strona 85)
- "[...] nazwany P_impact", zamiast "[...] nazwany P_Impact" (strona 87)
- "[...] a pola Tag [...]", zamiast "[...] a pola Filter Tag [...]" (strona 91)
- "[...] wartość pola Target na ThisObject [...]", zamiast [...] wartość pola Target na This Object [...] (strona 92)
- "[...] większą wartość Order In Layer [...]", zamiast "[...] większą wartość Order in Layer [...]" (strona 99)
- "[...] komponent Collision Condition [...]", zamiast "[...] komponent Condition Collision [...]" (strona 99)
- "[...] PunktyPomidora i ZniszczeniePomidora i zmień ich nazwy [...]", zamiast "[...] PunktyPomidora oraz ZniszczeniePomidora i zmień ich nazwy [...]" (powtórzenie spójnika, strona 101)
- "Z menu kontekstowego wybierz opcję RemoveComponent", zamiast "Z menu kontekstowego wybierz opcję Remove Component" (strona 102)
- "[...] wybierz pole Look At Target [...]", zamiast "[...] wybierz pole Look at Target [...]" (strona 102)
- "[...] która w tym momencie nazywała się DzialoWolowinow (Create Object Action) [...]", zamiast "[...] która w tym momencie nazywała się DzialoWolowinowe (Create Object Action) [...]" (strona 104)
- "[...] wartość pola Order In Layer [...]", zamiast "[...] wartość pola Order in Layer [...]" (strona 106)
- "Komponent Objects Creator Area [...]", zamiast "Komponent Object Creator Area [...]" (strona 110)
- "[...] dodaj komponent Objects Creator Area.", zamiast "[...] dodaj komponent Object Creator Area." (strona 113)
- "[...] przede wszystkim Gameplay actions w Condition Destroy)", zamiast "[...] przede wszystkim Gameplay Actions w Condition Destroy)" (strona 115)
- "Utwórz kolejne obiekty wrogów [...]", zamiast "Utwórz kolejne obiekty spawnerów wrogów [...]" (z kontekstu wynika, że chodzi o utworzenie "spawnera", strona 115)
- "[...] dobrane czasy w Time ToDestruction.", zamiast "[...] dobrane czasy w Time To Destruction." (strona 117)
- "odparł z uśmiechem się tata.", zamiast "odparł z uśmiechem tata." lub "odparł z uśmiechnięciem się tata." (XD, strona 122)
- "[...] powinni mieć zaznaczone pole Filter By Tag, w polu [...]", zamiast "[...] powinni mieć zaznaczone pole Filter By Tag, a w polu [...]" (strona 123)
- "[...] nie zapomnij zmienić pola PrefabToCreate w komponencie CreateObject [...]", zamiast "[...] nie zapomnij zmienić pola Prefab To Create w komponencie Create Object [...]"(strona 125)
- "[...] w polu Tag_To_Check_For [...]", zamiast "[...] w polu Tag to check for [...]" (strona 127)
- "http://opengameart.org" (czemu nie "https"?, strona 134)
- "[...] autora Cynicmusic [...]", zamiast "[...] autora cynicmusic [...]" (pseudonim jest napisany małą literą, strona 135)
- "[...] autora Qubodup [...]", zamiast "[...] autora qubodup [...]" (pseudonim jest napisany małą literą, strona 135)
- "4 projectile lanuches", zamiast "4 projectile launches" (strona 136)
- "[...] jedynie pole Clip [...], zamiast [...] jedynie pole AudioClip [...]" (strona 137)
- "[...] odparła tata.", zamiast "[...] odparł tata." (XD, strona 141)
- "Przejdź do komponentu Renderer [...]", zamiast "Przejdź do komponentu Sprite Renderer [...]" (strona 145)
- "[...] w komponencie Auto Move No Physic [...]", zamiast "[...] w komponencie Auto Move No Physics [...]" (strona 145)
- "Dodaj obiektowi ScianaSygnal komponenty: Collider 2D i Rigidbody 2D", zamiast "Dodaj obiektowi ScianaSygnal komponenty: Collider2D i Rigidbody2D" (strona 152)
- "[...] ogórki strzelają za szybko [...]", zamiast "[...] ogórki poruszają się za szybko [...]" (z kontekstu wynika że chodziło o pociski, a pociski nie strzelają, strona 156)
- "[...] kliknij jeszcze przycisk Player settings [...]", zamiast "[...] kliknij jeszcze przycisk Player Settings [...]" (strona 157)
- "[...] pozycję Edit/Project settings, a następnie zakładkę Physics2D i sekcję Layer Condition Matrix", zamiast "[...] pozycję Edit/Project Settings, a następnie zakładkę Physics 2D i sekcję Layer Collision Matrix." (brak kropki kończącej zdanie, strona 165)
- "Przykładem jest SpriteRenderer [...]", zamiast "Przykładem jest Sprite Renderer [...]" (strona 168)
- "Innym przykładem może być MeshRenderer [...]", zamiast "Innym przykładem może być Mesh Renderer [...]" (strona 168)
- "Sam często jest niewidoczny." (kropka przed zdaniem w nawiasie, strona 169)
- "[...] aby członkowie zespołu robili tę samą grę!" (wykrzyknik przed zdaniem w nawiasie, chyba że usunie się nawiasy z następnego zdania, strona 169)
- "System cząsteczek tworzy komponent ParticleSystem.", zamiast "System cząsteczek tworzy komponent Particle System." (strona 170)
- "[...] musi posiadać komponent AudioSource.", zamiast "[...] musi posiadać komponent Audio Source." (strona 171)
- "Jeśli chcesz ponowie ukryć te pola [...]", zamiast "Jeśli chcesz ponownie ukryć te pola [...]" (strona 173)
- "(Tag & Layers)", zamiast "(Tags & Layers)" (strona 173)
- "W przypadku dodawanie etykiety [...]", zamiast "W przypadku dodawania etykiety [...]" (strona 173)
- "Kliknij dwukrotne prefab [...]", zamiast "Kliknij dwukrotnie prefab [...]" (strona 175)
- "[...] pozycję Edit/Project settings.", zamiast "[...] pozycję Edit/Project Settings." (strona 177)
- "Wybierz zakładkę Physics2D.", zamiast "Wybierz zakładkę Physics 2D." (strona 177)
- "Znajdź sekcję Layer Condition Matrix [...]", zamiast "Znajdź sekcję Layer Collision Matrix [...]" (strona 177)
- "[...] w polu OrderInLayer w komponencie SpriteRenderer.", zamiast "[...] w polu Order in Layer w komponencie Sprite Renderer." (strona 178)
- "Komponent BezwarunkoweZniszczenie [...]" (jedna spacja za dużo po nazwie komponentu, strona 185)
- "[...] sterującym zachowaniem i wyglądam [...]", zamiast "[...] sterującym zachowaniem i wyglądem [...]" (strona 188)
INNE BŁĘDY
Drobny fragmencik na pozostałe błędy książki "Unity na start! Programowanie dla nastolatków", których nie da się zakwalifikować jako drobne pomyłki w piśmiennictwie:
- inna czcionka zdania "Tak, pamiętam." (strona 58)
- inna czcionka zdania "To po co one są? - dociekał syn." (strona 61)
- nazwa komponentu "CreateObject" nie została wyróżniona inną czcionką na samym dole (strona 125)
- "dodał uczenie tata" (nie rozumiem znaczenia, strona 150)
CZY KSIĄŻKA JEST WARTA ZAKUPU?
Raz kolejny: to zależy. Zależy czy zadowolicie się tworzeniem gier z użyciem wyłącznie modułu "Unity Playground", bo wokół niego kręci się co najmniej 90% mechaniki projektu z Panem Burgerem w roli głównej. Nie znajdziecie w niej ŻADNYCH wątków na temat nauki programowania w "CSharpie", są tylko na końcu kody źródłowe autorstwa Pana Jacka Rossa. Wtedy możecie odłożyć książkę "Unity na start! Programowanie dla nastolatków" i poszukać innych bardziej technicznych tytułów. Jeżeli jednak nie zależy Wam wcale na nauce kodowania, tylko chcecie pobawić się wspomnianym pakietem, to nic nie stoi na przeszkodzie, żeby sobie kupić książkę. Po jej przeczytaniu będziecie mieli pojęcie o tym, jak zacząć projekt, jak go skończyć i zbudować grę w postaci pełnoprawnej aplikacji w postaci pliku wykonywalnego "exe". Jednak Wasza zdolność do tworzenia gier będzie się ograniczać do korzystania z pakietu "Unity Playground". Decyzja należy do Was!
"Unity na start! Programowanie dla nastolatków" okaże się dobrym zakupem, jeśli nie interesuje nas ręczne programowanie funkcjonalności i mamy świadomość, że tworzenie gry nie wychodzi poza wykorzystywanie pakietu "Unity Playground".
Tak się sprawy mają. Raz jeszcze dziękuję za pełne przeczytanie i w kółko na okrągło powtarzam, że nie piszę o tych błędach i pomyłkach dla przyjemności czy żeby dokuczyć. Odkąd kupiłem parę lat temu dwie pierwsze książki informatyczne w życiu, po prostu pokochałem czytać. Chcę pomóc Wam, drodzy czytelnicy, w podjęciu słusznej decyzji czy kupić, czy nie, bo to też jest inwestycja czasowa. A czas to najważniejsza waluta człowieka. Nie wiem czy Helion na tym skorzysta w momencie tworzenia drugiego wydania tej książki w przyszłości, jednak często widzę jak udostępnia posty innych twórców na temat lektur, więc może...