Nie żeby mi się nudziło, ale generator postaci oparty o zasady Kryształów Czasu był jednym z założeń zabawy w pisanie mini gry rpg i wykorzystania przygody Sladuma jako bazy do nauczenia się Godota i C# przy okazji.
Stąd po bardzo krótkim czasie (zaledwie dwa-trzy dłuższe posiedzenia w ciągu ostatnich dni) udało się osiągnąć wstępny projekt kolejnej mechaniki gry (i kolejnej na tę chwilę nie dokończonej lecz nie mogłem się powstrzymać) czyli wspomnianego generatora postaci.
I tak patrząc na to jak szybko udało mi się stworzyć wyjściową wersję w C# generującą cechy w porównaniu z tym jak męczyłem się przy JavieScript, aby osiągnąć podobny efekt... jestem miło zaskoczony. Niby kod, a w sumie struktury obiektów POJO mógłbym przenieść niemal 1:1 jednakże zauważyłem w starym kodzie mnóstwo elementów, które były po prostu źle przemyślane.
Nie ma się co oszukiwać - doświadczenie w programowaniu procentuje.
Aktualnie kod w C# jest wygodniejszy w użyciu oraz czytelniejszy. Skomplikowane elementy dotyczące struktur potrzebne do wygenerowania cech stały się bardziej generyczne. Mechanizm losuje cechy główne i odporności w identyczny sposób w oparciu o takie same obiekty przenoszone w kodzie. W poprzedniej wersji nie udało mi się osiągnąć takiej spójności danych. Zawsze też jest opcja wstępnego refaktoru napisanych klas ponieważ już teraz widzę kilka elementów, które z powodzeniem mogę skrócić.
Oczywiście nowy generator nie ma pełnej obsługi wszystkich kroków wymaganych do stworzenia pełnoprawnej postaci. Brakuje w nim losowania wagi, pochodzenia, uwzględnienia wszystkich profesji i ras czy zalet i wad postaci, zawodów... ale już teraz widzę, że dodawanie tych elementów będzie o wiele prostsze niż w JavieScript. Dobrze też, że pliki które tworzyły bazę danych dla starego generatora, w miarę łatwo będę mógł przekształcić w pliki jsona i wczytać do kodu zamiast mozolnie wszystko przepisywać na nowo.
Ale koniec lania wody, pora na prezentację.
Można wylosować człowieka (mężczyznę) w profesji wojownika na poziomie 0. Elementy wchodzące w definicji rasy oraz profesji są zgodne z tym co jest w KC-tach.
|
Mam trzy zakładki grupujące dane. Ogólny wygląd jest paskudny, ale nie to było celem.
|
|
Wylosowane statystyki postaci wraz z wyświetlonymi składowymi (po prawej stronie od cech) z których zostały obliczone |
|
I to samo, ale dla odporności. |
Stary generator postaci (dostępny tutaj
Generator postaci Kryształy Czasu ) pod względem zawartości bije na głowę to co teraz napisałem jednakże siedziałem nad nim z miesiąc(jak nie dwa) a tu to dopiero początek. I w innym języku :)
I trochę o kodzie
Jak wiecie pisze w dla Godot w C#. Struktura klas nie jest nadmiernie skomplikowana.
Jest generator cech (zlany w jedną gównianą klasę z kontrolerem ekranu wyświetlającym cechy i to musze obowiązkowo poprawić) i generator dla odporności oraz klasy wspierające.
I o ile część losująca nie jest zbyt interesująca najfajniejsze klasy to StatDefinition odpowiadająca za definicję cech postaci - tak głównych jak i odporności oraz klasa odpowiedzialna za kostki. Poniżej jak wygląda w kodzie (zwykłe POJO ale o szerokim zastosowaniu)
public class StatDefinition
{
/* nazwa cechy*/
public StatName Name;
/* długa nazwa parametru*/
public string LongName;
/* wartośc bazowa */
public int BaseValue;
/* czy powinna być losowana w generatorze */
public bool ShouldBeRolled = true;
/* czy to zdolnosć profesji lub rasy i możliwa przerzucana dla lepszego wyniku */
public bool ProffStat = false;
/* definicja kostki jaka trzeba rzucać */
public RollDefinition RollCode;
}
I sama definicja przykładowo Żywotność dla człowieka , której w KC nie przerzucamy przy generowaniu
internal StatDefinition HitPoints { get; } =
new()
{
Name = StatDefinition.StatName.HP,
LongName = "Hit points",
BaseValue = 100,
ShouldBeRolled = false,
};
Tutaj inaczej dla Siły, którą nie dość że rzucamy z użyciem k100 to jest także zdolnością profesyjną i mamy możliwość wybrania większego z dwóch rzutów
internal StatDefinition Strength { get; } =
new()
{
Name = StatDefinition.StatName.SF,
LongName = "Strength",
BaseValue = 50,
ProffStat = true,
RollCode = Generator.RollCode.D100,
};
A tutaj oparta o ten sam szablon odporność na iluzję
internal StatDefinition Illusion { get; } =
new()
{
Name = StatDefinition.StatName.ILLUSION,
LongName = "Illusion",
BaseValue = 10,
RollCode = Generator.RollCode.D10Premium,
};
Powyższe pozwala szybko definiować statystyki i wrzucać do wspólnego kodu genrującego. Poprzedni kod w JavaScript nie dawał takich możliwości.
I druga klasa która wyszła dosyć zgrabnie - definiująca kostkę
public class RollDefinition
{
/* nazwa kostki */
public string Name;
/* min wartość dla kości */
public int minValue;
/* max wartość dla kości */
public int maxValue;
/* chyba do wyrzucenia */
public int toAdd;
/* czy kość premiowa */
public bool premium;
/* czy to pojedyncza kosc */
public bool onedice;
private Random rollStat = new Random();
public int Roll()
{
var rolledValue = 0;
if (minValue > -1)
{
if (premium)
{
rolledValue = RollPremium();
}
else
{
rolledValue = rollStat.Next(minValue, maxValue);
}
}
return rolledValue;
}
private int RollPremium()
{
var rolledValue = rollStat.Next(minValue, maxValue);
if (rolledValue == maxValue - 1)
{
rolledValue += RollPremium();
}
return rolledValue;
}
}
oraz przykładowa implementacja - tutaj k10 premiowe
internal RollDefinition PremiumD10 { get; } =
new()
{
Name = "PremiumD10",
onedice = true,
minValue = 1,
maxValue = 11,
premium = true,
};
A jakie zmiany jeszcze wejdą do kodu?
Poza wydaje się oczywistymi elementami czyli refaktorem nie używanych rzeczy (np. dwa pola w klasie RollDefinition nigdzie nie zostały użyte czy wspomniane zlanie w jedno kontrolera ekranu z generatorem cech ) to obowiązkowe będzie wczytywanie charakterystyk dla cech czy definicji profesji z plików json. Aktualnie jest to zaszyte w kodzie (co widać po sposobie definiowania cech postaci podanym powyżej) i nie jest to nie jest optymalna metoda pracy.
Docelowo oczywiście wrzucenie kodu do głównego projektu małej przygody Sladuma i uwzględnienie w mechanice walki.
To na tyle.
Miłego!