W ostatnich odcinkach na temat LifeLIke nauczyłem się, jak wybierać wrogów, jak tworzyć samego siebie (sooo deep! ). Dzisiaj ponownie wracamy do tematyki walki. Tym razem takiej praktycznej … ale tylko na pięści!
Czytaj dalej „LifeLike – Przyłóż swojemu wrogowi!”
LifeLike – Tworzenie Postaci i Okno Szczegółów
Już słyszę ten chór ludzi, którzy wołają “Buuuu! Gdzie ta cholerna walka i te cholerne tury!”.
I wiecie co? Macie rację … ale pomęczę was dłużej. W dzisiejszym odcinku naszej telenoweli pod tytułem “LifeLike – żmudny proces tworzenia prostej gry”, kontynuuje temat UI.
Dług technologiczny
Na swoim blogu i prezentacjach Arek (http://www.benedykt.net/) wielokrotnie wspominał na temat długu technologicznego i zasadach Solid. Ten pierwszy jest kluczowy i rozwija trochę temat długiego tworzenia projektu i każdego modułu. Jak wiadomo, gdy pójdziemy na skróty w tworzeniu i wykonamy dużo rzeczy na odpieprz, zemści się to na nas w procesie refaktoryzacji czy optymalizacji lub w późniejszym rozwoju. Czyli wszelako źle zaprojektowany projekt, kod będzie szybkim rozwiązaniem, ale za przeproszeniem ch.. rozwiązaniem. Wiem, że nie jest to idealnie SOLIDowy projekt, gdyż nie ma depedency injector. Pewnie wiele modułów i rozwiązań można by było lepiej oprogramować , a sposób otwarcia paneli też mógłby być lepszy, ale staram się wciąż rozwijać w technologii tworzenia gier.
Tworzenie Postaci – Ciąg dalszy
Wiecie, czego najbardziej brakuje mi w tworzeniu UI do Unity? MVVM (Model View ViewModel), gdzie w warstwie ViewModel mamy tylko Properties i logikę biznesową. Naszym modelem byłby np. CharacterStatisticDataModel, a w warstwie View bindowalibyśmy elementy z Widoku. Wiecie ile zaoszczędziło by to kodu i pracy w implementacji okien, które mają dość dużo pól? … Sporo. Marudzę na to, ponieważ w oknie tworzenia postaci dodałem nowe pola i kontrolki – do ustawiania statystyk. Na tę chwilę wszystkie nasze statystyki zaczynają się od 1. Limit punktów dla postaci wynosi 10. Poniżej 0 nie stworzymy postaci. Wyżej niż 10 .. no way!
Jak zauważyliście w poprzedniej części, dla kontrolek tworzy się listenery z delegatami zamiast akcji z delegatami. Dla Sliderów, których używamy do rozdysponowania punktów dla każdej wartości używamy onValueChanged.
StrengthSlider.onValueChanged.AddListener(StrengthChanged);
Brakuje trochę wpf parametru, do jakiej kontrolki się odwołujemy. Uprościłoby to trochę kod.
Następnym kluczowym dla projektu elementem jest okno postaci. W obecnej wersji tylko ze statystykami i imieniem. W przyszłości -> z ekwipunkiem i dodatkowym atrybutami.
Pod klawiszem i otwieramy nasze okienko z postacią. Kiedy je otwieramy, wyłączamy obsługę klawiszy i wyłączamy UI gry.
if (!OpenedWindow) { if (Input.GetKeyDown(LightKey)) IsDay = !IsDay; if (Input.GetKeyDown(FightNormalKey)) FightSystem.AttackEnemy(); if (Input.GetKeyDown(SelectEnemyKey)) SelectEnemy(); if (Input.GetKeyDown(ExitKey)) EndGame(); if (Input.GetKeyDown(OpenDetailKey)) OpenDetail(); _gameUI.enabled = true; } else { _gameUI.enabled = false; }
Dotyczy to również okna kreatora postaci (w końcu, kto chce manipulować światłem w trakcie wpisywania swojego imienia).
Na obecną chwilę, zamknięcie Okna ze szczegółami postaci lub kreatora polega na … zabiciu go i Zmianie *OpenedWindow* na false.
Szczerze, w tym oknie tak samo brakowało mi MVVM, ale w mniejszym stopniu, pewnie odczuję brak na późniejszym etapie – w przypadku nowych poziomów i opcji dodania skill point.
Podsumowanie
To tyle na dzisiaj w tematyce UI. Pod adresem: Dostępna jest również zaaktualizowana wersja gry, m.in wzbogacona o nowe okno postaci. Następny wpis już w weekend 🙂
Cheers
Filmik z gry w mov (quick time) inaczej nie zapisuje
LifeLike – UI i Kreator Tworzenia Postaci
W poprzedniej części było coś na temat tworzenia UI, teraz przejdziemy do tworzenia naszej postaci. Czyli tworzymy “czarodzieja” dla postaci. (ang. Wizard – Czarodziej – czyli okno z kreatorem)
Kod prezentowany w dalszej części, jak zwykle dostępny w całości na GitHubie.
LifeLike – Interfejs Użytkownika
Witam w następnej części dotyczącej LifeLike. Poprzednio pisałem o zaznaczaniu postaci i dodawaniu przeciwników oraz przełączaniu się między nimi. Dzisiaj, przejdę do UI!
Manager UI w LifeLike
Jak można było zobaczyć, z UI można było spotkać się w menu głównym i w mini grze The Ball, które znajdują się pod linkiem poniżej. Link
W UI Managerze zawarte są metody do kontrolowania komponentów UI, jak np. okno z logami oraz z szczegółami. UI Manager jest podpięty do GameManagera.
Ekran Logów
PIerwszym elementem dla rasowych Rogue Like i Oldschoolowych RPG jest ekran logów. Czyli pole tekstowe z logiem – ile zadaliśmy, co znaleźliśmy i ewentualnie, co, kto do nas powiedział.
Jednak ekran logów trzeba było ograniczyć do określonej liczby linijek – tzn. czyścić te pierwsze, aby cały czas nie było więcej niż wybrana liczba linijek – u mnie 10. Logi dodaje się przez metodę AddLog(treść), a edytor przyjmuje podstawowe tagi html jak „b”, „i” oraz \t i \n dla nowej linii.
Cały kod zobaczycie na GitHubie, a fragment o którym mówię, zobaczycie poniżej.
public void AddLog(string log) { ClearFirstLine(); _stringLog.AppendLine(log); GameLog.text = _stringLog.ToString(); }
Zaznaczony Przeciwnik
W poprzedniej części nauczyliśmy się, jak zaznaczać przeciwnika i przełączać się pomiędzy nimi, dlatego też, aby to rozszerzyć, stworzyłem panel do wyświetlania danych wybranego wroga.
Obecnie wyświetlane jest jego imię, lvl oraz coś, co poruszę w następnym punkcie, do którego potrzebny jest…
private void SelectedEnemyPanel() { if (EnemyUtils.SelectedEnemy==null) return; if (SelectedEnemyStatistic != null) { SelectedEnemyStatistic.text = string.Format("<b>Name</b>: {0} \n<b>Class Name</b>: {1}", EnemyUtils.SelectedEnemy.EnemyCharacter.Name, EnemyUtils.SelectedEnemy.ClassName); } if (SelectedEnemyDetail != null) { SelectedEnemyDetail.text = string.Format("<b>Distance:</b>{0}", EnemyUtils.SelectedEnemy.Distance); } }
Dystans
Tak, dobrze wiedzieć, jak daleko jesteśmy od przeciwnika, nie tylko, aby był to nowy wodotrysk do wyświetlania, ale także jest to przydatne do systemu walki dystansowego oraz jako informacja, czy jesteśmy na tyle blisko, aby zaatakować bezpośrednio.
Tu by się przydała trochę wiedza z uczelni oraz wzór na odległość między 2 wektorami … ale Unity dostarcza nam Vector.Distance pomiędzy graczem a wrogiem.
Dystans dodałem do klasy Enemy. Pomaga to także posortować przeciwników ze względu na dystans od gracza.
public int Distance { get { if (GameManager.Instance.PlayerObject != null) return (int) Vector2.Distance(GameManager.Instance.PlayerObject.transform.position, transform.position); Debug.Log(GameManager.Instance.PlayerObject); return 0; //Matematyka jednak cos daje! // return (int) Mathf.Sqrt(Mathf.Pow(Player.transform.position.x - SelectedEnemy.transform.position.x, 2) + // Mathf.Pow(Player.transform.position.y - SelectedEnemy.transform.position.y, 2)); } }
Podsumowanie
To tyle na temat UI. Temat będzie jeszcze poruszony przy okienku tworzenia postaci oraz dodawania szczegółów dotyczących gracza.
Kod jak zwykle można znaleźć na GitHub https://github.com/aluspl/RogueLikeDSP.
Chciałem dodać player, ale Unity upiera się, że klasy Enemy nie ma … mimo że jest .
Pozdrawiam!
LifeLike – Walka Bezpośrednia – na serio!
Tak, tym razem na serio, będę kontynuował walkę bezpośrednią. Zauważyłem, że jeśli skupię się na kodzie i robię wpis “Code First”, a nie “Theory First” – jak to miało miejsce w poprzednim wpisie, to powstaje dużo kodu, a zostaje mało czasu na jego opis. Będę więc się trochę streszczał. 🙂
Refactoring LifeLike
Z racji wkurzających żółtych podpowiedzi w nowym Rider oraz paru pomysłów związanych z przeciwnikami, postanowiłem zrobić lekką refaktoryzację – w tym zmiany namespace i foldery plików + parę narzędzi do zarządzania przeciwnikami.
Wróg… jest czerwony!
W poprzednim wpisie wspominałem o inspiracji Superhot, w tym postanowiłem słowa zamienić w czyny i stworzyć tego wroga. Jest to, lekka modyfikacja naszego playera, który swoją drogą, również zmienił grafikę. W przyszłości, każdy zasłuży na swój własny wygląd.W tym, będzie po prostu Red Manem ..i wygląda tak:
Przeciwniku, pojaw się na mapie!
A przy okazji dodaj się do listy Przeciwników, aby łatwo Cię było potem wybrać … i zabić.
…
private void AddEnemy(MapElement[,] map, int x, int y) { if (MaxEnemies <= 0) return; var chance = _random.Next(100)==1; if (chance) return; if (map[x,y]!=MapElement.Floor) return; var enemy=Instantiate(Enemies.FirstOrDefault(), GetPosition(x, y), Quaternion.identity , EnemiesCollection); GameManager.Instance.AddEnemy(enemy); MaxEnemies--; }
Założyłem sobie, że przeciwnik musi pojawić się na podłodze, a nie w ścianie. A i musi być w ograniczonej liczbie. 🙂 Póki co, generator działa ze zbyt dużą częstotliwością, więc szansa na pojawienie się przeciwnika jest bardzo duża – za duża.
Ale cóż, ważne, że takim oto sposobem, nasz czerwony wróg pojawił się na mapie !
Przeciwniku, bądź Oznaczony!
Kolejnym kluczowym elementem, jest wiedza … kogo zaatakowaliśmy. 🙂
…
Przeciwnik dostał ten sam shader, co podłoga, więc nie jest widoczny w nocy, ale dodałem mu jakiś element oznaczenia. Małą lampkę, która oznacza, że przeciwnik jest zaznaczony. Zaznaczenia zmieniamy, przez kliknięcie TAB (lub innego przypisanego klawisza)
private void SelectEnemy() { if (Enemies.Count < = 0) return; if (EnemyUtils.EnemyIndex == Enemies.Count) EnemyUtils.EnemyIndex = 0; foreach (var enemy in Enemies) { enemy.IsSelected = false; } Debug.Log("Selected Enemy: "+EnemyUtils.SelectedEnemy.EnemyCharacter.Name + "Current Index: "+ EnemyUtils.EnemyIndex); Enemies[EnemyUtils.EnemyIndex].IsSelected = true; EnemyUtils.EnemyIndex++; }
Podsumowanie
To tyle w dzisiejszym odcinku. Temat kontynuowany będzie też w następny wpisie. Jak widać, nie jest to wcale mało rozbudowany system, a gdy będziemy chcieli do tego dodać jeszcze walkę dystansową i mierzenie, czy dany przeciwnik faktycznie jest w zasięgu bezpośredniego czy dalekiego ataku, to system będzie naprawdę sporo rozbudowany. Nie zapominajmy też, że będzie UI, szansa trafienia oraz okno z logiem naszych ataków.
Link do gry i aktualnej wersji jak zwykle na githubie
LifeLike – Walka Bezpośrednia
A w przyszłości i dystansowa 🙂
Tematem dzisiejszego wieczorno-sobotniego wpisu jest kolejna część dotycząca walki. Byłem świadkiem wpisów na blogach, które mają maksymalnie po 2-3 zdania, 2 razy w tygodniu i to totalnie o niczym. Nie chcę iść tą drogą, ale niestety skutkuje to tym, że ciężko mi czasami wrzucić 2 posty tygodniowo. Dzisiaj przechodzimy do kolejnej części na temat walki, czyli to, czym roguelike żyją .. lub nie 🙂
LifeLike – Postać i Ataki
- Już dzisiaj wyjazd do Grecji, ale nie mogę zaniedbać czytelników (o ile jakichś mam, ale jeśli wierzyć statystykom Google Analytics wychodzi na to, że ktoś to jednak czyta).
Tym razem krótko, ale rzetelnie – ataki. Szanse powodzenia oraz przykładowy atak specjalny – Tech Talk! Czytaj dalej „LifeLike – Postać i Ataki”
Android SDK – Setup
Hello, this is my first post in english. As I’ve promised in polish version of this post, I wanted to recreate my Android SDK Tutorials. This time, with new technologies, new patterns and in 2 languages! Deal With It.
Czytaj dalej „Android SDK – Setup”
LifeLike – Postać i Statystyki
Ostatnio poruszyłem temat Testów, które przydadzą się do kolejnego punktu – postaci. W końcu od tego zaczęły się moje koncepty. Moja druga połówka trochę mi pomogła, jak rozpisywałem, jak to widzę na ścianie, za co jej ogromnie dziękuje. Więc zapraszamy do cyklu : Postać i Statystyki
Testy
Wróćmy do testów z poprzedniej części (link), bo jest to integralna część tego fragmentu wpisu. Niestety, dodatkowe projekty w Solucji, które nie są od Unity, są czyszczone przy każdym przeładowaniu, więc trzeba ręcznie dodać wcześniej stworzony projekt z testami do naszej solucji, za każdym razem, gdy się solucja nadpisuje przez edytor Unity. Z racji, że ostatnio pracuję bardziej na kodzie, nie muszę się aż tak często męczyć. Wszelkie testy można znaleźć na githubie w projekcie Test.
Base Character
Klasa, która określa zarys postaci. Czy to naszej, czy przeciwnika. Odpowiada za ataki, specjalne ataki, statystyki postaci, jej punkty życia. Każda klasa postaci, którą tworzę, dziedziczy po niej, dodając do głównych funkcji dodatkowe, jak np. więcej typów ataków.
Dzięki tej uniwersalności, łatwiej zrobić back-end do ataków, oraz zrobić je bardziej generyczne. Po prostu same plusy z obiektowego punktu tworzenia gier. Jak to powinno praktycznie wyglądać ? Może ktoś mi powie, kto jest bardziej wprawiony.
Dzięki temu sposobowi, łatwiej będziemy mogli się dostać do statystyk dla naszej postaci, np. z poziomu UI.
Tworzenie postaci
Żeby nie iść w złe nawyki i byle jaki kod, stworzyłem CharacterFactory, który zwraca klasę ze statystykami, w zależności od naszej nazwy. W praktyce, w późniejszej fazie i po obliczeniach dla systemu walki itp. Charakterystyki startowe, będą charakterystyczne dla danej klasy, a potem w fazie rozwoju, będziemy mogli je rozszerzać…
Na tworzenie postaci, stworzyłem testy większości funkcji, choć nie są kompletne … jeszcze 🙂
W każdym bądź razie, system walki ma swoje zaczątki, jednak będzie brane pod uwagę coś więcej niż siła, a każde wyliczenie do podstawowej walki będzie brane pod unit testy, więc spokojnie 🙂
Przy okazji stworzyłem nowe klasy : Super Hobo (styl małpy, wiedźmińskie alkohole itp) oraz klasy, które będą skupione na przeciwnikach jak Boss, Hobo itp
public static BaseCharacter GetPlayerClass(string classType, CharacterStatisticDataModel statistic ) { switch (classType) { case ItGuyClass.ClassType: return new ItGuyClass(statistic); case SuperHoboClass.ClassType: return new SuperHoboClass(statistic); case HoboClass.ClassType: return new HoboClass(statistic); case CorpoBoss.ClassType: return new CorpoBoss(statistic); case CorpoRat.ClassType: return new CorpoRat(statistic); default: return null; } }
Atak
W początkowej fazie Damage = Siła.
Lecz w następnych etapach rozgrywki, powodzenie ataku będzie zależne od zręczności obu postaci, a siła ataku będzie liczbą losową zmniejszoną o przyszły ekwipunek postaci. Oczywiście szansa uniku będzie tym większa, im większa różnica zręczności, a sam atak będzie liczbą losową (taaak, grało się w RPG).
public virtual string Attack(BaseCharacter enemy) { var damage = Strength; enemy.HealthPoint -= damage; return GameLogSystem.Attack(damage, enemy); }
Podsumowanie
To tyle na dzisiaj, postać będzie rozwijana przez co najmniej 2-3 części, ale nie pominę oczywiście tworzenia przeciwnika na mapie oraz UI przygotowanego do walki (wyświetlanie logów, ataku itp).
Miłego czytania 🙂
Cały kod dostępny na porn… znaczy githubie!
ANDROID – INSTALACJA SDK
W ramach DSP2017 poza #LifeLike postanowiłem zrobić popularny ostatnio w kinach Remastering. Dawno planowałem, ale nie było motywacji do tego, ale wypada nadrobić istotne braki w tematyce mobilnej, którą w końcu się specjalizowałem.
Na pierwszy plan wchodzi instalacja SDK, o którą były pytania. Jako bonus, w najbliższym czasie dodam wersję angielską tego postu (nie, nie użyje google translate!)
Instalator
Pierwsza część wpisu dotyczy instalacji narzędzi na system od Apple. Tak, system, którym tak długo gardziłem, aż po zakupie stwierdziłem “Wooow, to taki ładny i praktyczny w obsłudze linux, którego lubi Adobe i Unity”. Instalacja w obecnych czasach nie jest tak skomplikowana jak wcześniej. Pierwszy sposób ogranicza się do kilku kroków, ale niezależnie od platformy jest on prosty. Polega ona na pobraniu paczki Android Studio ze strony [Download Android Studio and SDK Tools | Android Studio](https://developer.android.com/studio/index.html).
Strona, z której pobierzemy Android Studio z SDK
Wystarczy zainstalować i już.
Homebrew
Druga opcja przyda się każdemu programiście i użytkownikowi Maca. Chcąc, nie chcąc, każdy szanujący się programista powinien pogodzić się z linią komend, gdyż bywa ona bardzo użyteczna i odpowiednio się odwdzięczy.
Pewnie wiele pamięta z ubuntu “apt-get install” do instalacji aplikacji, wtyczek itp. W przypadku Mac OS, takim narzędziem jest właśnie Homebrew:https://brew.sh).
Instalacja jest prosta. Uruchamiamy terminal, wklejamy komendę ze strony Android i enter!
Po zainstalowaniu, wpisujemy w linii komend aby pobrać sdk:
brew install android-sdk
Homebrew pobiera android-sdk i instaluje go na naszym urządzeniu. Jeśli potrzebujecie dodać sdk do PATH, aby mieć dostęp do narzędzi z platformy, wpisujemy w konsoli :
export PATH=$PATH:/usr/local/Cellar/android-sdk/<VERSION>/tools:/usr/local/Cellar/android-sdk/<VERSION>/platform-tools
gdzie to VERSION naszego SDK.
Podsumowanie
To tyle w dzisiejszym odcinku. Jeśli chcecie coś więcej na ten temat, piszcie albo na FP albo na maila.