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:

Jesteśmy Zieloni … Ci dobrzy
Oni są Czerwoni … są Be

Przeciwniku, pojaw się na mapie!

A przy okazji dodaj się do listy Przeciwników, aby łatwo Cię było potem wybrać … i zabić.

[csharp]
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–;
}
[/csharp]

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 !

Luke ! I am Your Enemy

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)

[csharp]
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++;
}
[/csharp]

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 – 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
[csharp]
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;
}
}
[/csharp]

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).

[csharp]
public virtual string Attack(BaseCharacter enemy)
{
var damage = Strength;
enemy.HealthPoint -= damage;
return GameLogSystem.Attack(damage, enemy);
}
[/csharp]

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!

Blackberry Jam Session w Amsterdamie

Dawno dawno temu w odległym Amsterdamie, gdzieś pomiędzy 3-7 dniem miesiąca luty , w przerwie pomiędzy pracą inżynierską, a pisaniem VII części kursu ,miałem okazję wyjechać na konferencje BlackBerry Jam dla Developerów, która odbyła się w Amsterdamie. Podróż ta nie była krótka, ponieważ odbywała się za pomocą Autokaru, na którego trzeba było jednak dojechać, ponieważ trasa rozpoczynała się w stolicy państwa Polskiego. Czytaj dalej Blackberry Jam Session w Amsterdamie