C++ mogło nie przypaść Ci do gustu jeśli wcześniej pracowałeś w AMOSie. Dlatego, że AMOS i generalnie wszystkie odmiany Basica zostawiają wiele złych nawyków podczas projektowania i pisania programów. Po pierwsze w AMOSie programy pisze się głównie rozkaz po rozkazie, bez wcześniejszego planowania, nagminnie korzysta się z polecenia "Goto", programowanie proceduralne takie jak w C istnieje, ale jest szczątkowe. Swoją drogą w C polecenie "goto" istnieje, ale jest bardzo nie zalecane i uważane za zły nawyk.
Programowanie w C++ rządzi się innymi prawami, wymaga odmiennego podejścia do zagadnienia, czyli pisanego programu. Program trzeba najpierw zaprojektować i stworzyć "świat" podzielony na szereg obiektów o określonych cechach. Trzeba określić relacje między tymi obiektami, znaleźć części wspólne między obiektami, opisać zachowanie się obiektów. Ma to bardzo dobre odniesienie do świata rzeczywistego.
Tworząc świat gry np. Giany Sisters trzeba najpierw stworzyć bohatera, później świat w którym ten bohater się porusza no i następnie postacie przeszkadzające naszemu bohaterowi w podróży, jak również skarby które może zebrać itp. Pisząc w C++ najlepiej oddzielić implementację różnych zachowań bohatera od jego rzeczywistego rysowania i animacji. Te procedury będą zapewne napisane jako wstawki asemblerowe ;) Na przykład
klasa Giana to nasza bohaterka, którą charakteryzuje m.in:
- położenie na mapie,
- zwrot, czyli kierunek w którym się porusza,
- prędkość marszu,
- przyspieszenie w pionie (czyli czy skacze lub spada),
Świat w jakim się porusza charakteryzuje ziemia, po której stąpa oraz platformy po których może skakać. Dodatkowo w tym świecie mogą być obecne wrogie stwory oraz skarby do zebrania (grałem kiedyś w Giana Sisters i piszę to co pamiętam z tej gry). Stworki mają cechy wspólne z bohaterką, ponieważ to też są jakieś istoty, które poruszają się, jednakże ich zachowaniem kierują zupełnie inne siły, tj. idą w prawo aż do napotkania przeszkody po czym kierują się w lewo itd. Skarby (owoce itp.) charkateryzuje przede wszystkim położenie oraz punkty ile zbierze się za podniesienie danego przedmiotu. Poza tym są to martwe przedmioty, które się nie poruszają, co odróżnia je od żywej fauny naszego świata.
Zatem możemy stworzyć najpierw
klasę świat, w którym wszystko się dzieje. Świat będzie zawierał położenie wszystkich platform, przeszkód oraz dane o wszystkich obiektach (stworach, skarbach) wewnątrz tego świata. Np. w C++ napiszemy:
class CGianaWorld
{
public:
CPlatform *m_FirstPlatform;
CObstacle *m_FirstObstacle;
CBaddie *m_FirstBaddie;
CTreasure *m_FirstTreasure;
CHeroGiana m_Hero;
};
CPlatform to klasa która określa platformę w naszym świecie po której może chodzić nasza bohaterka, jak i wrogowie. Mogą też na niej leżeć skarby.
class CPlatform
{
public:
CPlatform *m_NextPlatform, *m_PrevPlatform;
ULONG m_XStart, m_YStart;
ULONG m_XEnd, m_YEnd;
ULONG m_Graphics;
BOOL OnPlatform();
};
Wszystkie obiekty w naszym świecie są powiązane ze sobą za pomocą węzłów (tworzą tzw. listę). Najlepiej gdy te obiekty są posortowane względem położenia [X,Y], wtedy operacje na takich obiektach będą bardzo szybkie.
class CObstacle
{
public:
CObstacle *m_NextObstacle, *m_PrevObstacle;
ULONG m_X, m_Y;
ULONG m_Kind;
BOOL OnObstacle();
};
class CBaddie
{
public:
CBaddie *m_NextBaddie, *m_PrevBaddie;
ULONG m_X, m_Y;
LONG m_Direction;
ULONG m_Kind;
BOOL IsHarming();
BOOL IsDiying();
VOID Move();
};
class CTreasure
{
public:
CTreasure *m_NextTreasure, *m_PrevTreasure;
ULONG m_X, m_Y;
ULONG m_Kind;
BOOL IsCollected();
};
Nasza bohaterka:
class CHeroGiana
{
public:
ULONG m_X, m_Y;
LONG m_Direction;
LONG m_XSpeed, m_YSpeed;
LONG m_XAcc, m_YAcc;
VOID Move( LONG XDir, LONG YDir );
};
Teraz polecam dla każdego obiektu napisać odpowiednie procedury wewnątrz klas (tzw. metody), odpowiedzialne za przeróżne czynności i zachowanie danego obiektu. Na przykład dla klasy CTreasure określona została metoda IsCollected, która sprawdza czy przypadkiem w pobliżu nie znajduje się bohater, który może zebrać przedmiot. Jeśli w pobliżu znajduje się bohater, to przedmiot zostaje wzięty, egzemplarz klasy zostaje usunięty z listy, a punktacja rośnie według rodzaju wziętego obiektu. Dla klasy CBaddie (wrogi stworek) zostały określone metody: IsHarming() i IsDying(). Pierwsza sprawdza czy przypadkiem w pobliżu nie znajduje się bohater, którego stworek może zranić, a druga czy przypadkiem bohater nie spada na głowę naszemu stworkowi zabijając go i kompletując punkty.
Teraz jak nasza gra będzie wyglądać? Po stworzeniu takiego zestawu klas i metod dalsza praca staje się o wiele prostsza. Więc tak: dana jest nam cała zainicjowana klasa CGianaWorld ze wszystkimi platformami, skarbami i potworami obecnymi na planszy. Trzeba wszystko ożywić i wprawić w ruch.
Zatem jedno wykonanie pętli naszego programu wyglądałoby tak:
BOOL SingleStep( CGianaWorld ourworld )
{
CTreasure *treasure;
CObstacle *obstacle;
CBaddie *baddie;
CPlatform *platform;
BOOL GianaDead=FALSE;
for (treasure = ourworld.m_FirstTreasure; treasure != NULL; treasure = treasure->m_NextTreasure)
{
if (treasure->IsCollected())
{
Remove(&ourworld, treasure);
points += reward[ treasure->m_Kind ];
}
}
for (baddie = ourworld.m_FirstBaddie; baddie != NULL; baddie = baddie->m_NextBaddie)
{
baddie->Move();
if (baddie->IsHarming())
{
energy--;
if (energy == 0)
GianaDead = TRUE;
}
if (baddie->IsDying())
{
Remove(&ourworld, baddie);
}
}
ourworld.m_Hero.Move( GetJoystickX(), GetJoystickY() );
return (GianaDead);
}
void PlayGianaSisters( CGianaWorld ourworld)
{
while (!SingleStep( ourworld ));
return;
}
I to by był w praktyce cały silnik prostej platformówki. Oczywiście brakuje tutaj implementacji szeregu funkcji, ale te mogę opisać w następnym poście. Wszelkie procedury rysowania i skrolowania ekranu byłyby "zatajone" przed samym programistą za pomocą implementacji. I czy w C++ nie pisze się naprawdę łatwo i przyjemnie? ;) Należy pamiętać o sortowaniu współrzędnych w celu zmaksymalizowania wydajności algorytmów. No i potrzeba użyć dobrego kompilatora. Pozdrawiam i mam nadzieję że, ten przykład napisania prostej gry platformowej przyda się osobom, które taką grę pragną napisać. Jest to tylko przykład (piszę go na bieżąco z głowy), bo taką grę można napisać na naprawdę wiele sposobów.