W grze mając do dyspozycji jakieś bronie ważym elementem jest ich amunicja. W mojej grze jak wcześniej pisałem występują 4 rodzaje broni:
1-bazooka
2-karabin maszynowy
3-laser
4-miotacz ognia
na blogu jak we wcześniejszych postach będę się posługiwał tymi obiektami z poniższymi kolorami:
Cshots strzal_bazooka;
Cshots strzal_machinegun;
Cshots strzal_laser;
Cshots strzal_flamethrower;
Na początku w pliku klasy.h deklarujemy sobie zmienne, które będą przechowywały stan amunicji i definiujemy je w main() przykładowymi wartościami:
ammo_bazo=100;
ammo_machgun=30;
ammo_laser=20;
ammo_flame=10;
W grze maksymalny stan amunicji będzie wynosił 100. Poniżej przedstawiam znany fragment kodu odpowiedzialny za strzał poszczególną bronią. Widzimy nowe linijki:
ammo_bazo--;
ammo_machgun--;
ammo_laser=--;
ammo_flame=--;
Oczywiście oznaczają one zmniejszenie zmiennej o 1, gdy wystrzelimy pocisk.
Zmieniłem także 4 instrukcje warunowe if np:
if( (bron==1) && (ammo_bazo>0) )
Oznacza, że możemy oddać strzał jeżeli mamy wybraną broń bazooka(klawisz 1) i poziom amunicji jest dodatni.
if( key[KEY_SPACE])
{
if( (bron==1) && (ammo_bazo>0) )
{
if( (strzal_bazooka.pozpoc_y<0) || (strzal_bazooka.pozpoc_y==0) )
{
strzal_bazooka.strzelaniee(ludek.pozs_x, ludek.pozs_y );
play_sample(dzwiek, 200,200,1000,0);
ammo_bazo--;
}
}
if( (bron==2) && (ammo_machgun>0) )
{
if( (strzal_machinegun.pozpoc_y<0) || (strzal_machinegun.pozpoc_y==0) )
{
strzal_machinegun.strzelaniee(ludek.pozs_x, ludek.pozs_y );
play_sample(machingunn, 200,200,1000,0);
ammo_machgun--;
}
}
if( (bron==3) && (ammo_laser>0) )
{
if( (strzal_laser.pozpoc_y<0) || (strzal_laser.pozpoc_y==0) )
{
strzal_laser.strzelaniee(ludek.pozs_x, ludek.pozs_y );
play_sample(laserr, 200,200,1000,0);
ammo_laser--;
}
}
if( (bron==4) && (ammo_flame>0) )
{
if( (strzal_flamethrower.pozpoc_y<0) ||(strzal_flamethrower.pozpoc_y==0) )
{
strzal_flamethrower.strzelaniee(ludek.pozs_x, ludek.pozs_y );
play_sample(flamethrow, 200,200,1000,0);
ammo_flame--;
}
}
}
Zmianie uległ(co pewnie nikogo nie dziwi :p) interfejs gry:
Widzimy jakies 4 znaczki. Onaczać będą amunicję w grze. Od góry:
bazooka, karabin maszynowy, laser i miotacz ognia.
Celowo widzimy biały pasek, ponieważ ten pasek będzie pokryty czerwonym zależnie od poziomu amunicji poszczególnej broni.
Odpowiadać za to będzie funkcja:
void poziom_ammo(int poz_ammo, BITMAP* bitmapa, int wysokosc)
{
for(int j=0; j<=poz_ammo ; j++)
{
if(poz_ammo!=0)
{
draw_sprite(bufor, bitmapa, 109+j, wysokosc);
}
}
}
1- argumentem w funkcji jest przesyłana zmienna zawierająca stan amunicji
2- argumentem w funkcji jest wskaźnik do bitmapy
3- argumentem w funkcji jest wysokość na jakiej ma być wyświetlany pasek dla poszczególnej broni.
Jak już wspomiałem będziemy rysować czerwne linie na białym pasku w interfejsie:
draw_sprite(bufor, bitmapa, 109+j, wysokosc);
109 -tyle pikseli od lewej rozpoczyna się biały pasek i mierzy on 100 pikselidługości i 2 szerokości.
109+j będziemy pasek zwiększali(lub zmiejszali) o j-pikseli tzn. o tyle ile będzie miała przesyłana zmienna poz_ammo.
W main wywołujemy ją tak:
poziom_ammo(ammo_bazo, menudolne_poz_ammo, 523);
poziom_ammo(ammo_machgun, menudolne_poz_ammo, 543);
poziom_ammo(ammo_laser, menudolne_poz_ammo, 562);
poziom_ammo(ammo_flame, menudolne_poz_ammo, 583);
Ten element dodaje sensu grze, lecz nie jest do końca dopracowany (jeżeli chodzi o kod). Nie miałem pomysłu jak to lepiej zrobić i zrobiłem ten element funkcyjnie, a nie obiektowo ale znając życie kod przejdzie NAPEWNO modyfikację i będzie obiektowo. Narazie ważne aby działało i motywowało do dalszej pracy :)
W grze dodałem też kolizję pocisku robocika(miotacza ognia) z pociskiem wroga co umożliwia robocikowi jakąś obronę. Nie będę po raz kolejny pisał i objaśniał kodu na blogu, ponieważ jest do ściągnięcia wraz z plikami potrzebnymi do uruchomienia gry (ver 1.04).
Gra na tym etapie wygląda następująco:
Ktoś przerobi na obiektowo... oczywiście :P bardzo proszę ;)
OdpowiedzUsuńWg mnie najlepszym rozwiązaniem jest zrobić tak jak już wcześnie pisałem :
- Stworzyć enum TypBroni i w nim dać bazooke,jakieś miotacze itd
- Stworzyć Listę/Tablicę wszystkich broni
- w Main stworzyć pole aktywnaBron, która będzie typu (enum)TypBroni
- całą metode ze sprawdzeniem i odjęciem amunicji przenieść do ciała klasy
Wtedy jak wcześnie pisałem kod będzie bardzo prosty :
if(KEY[SPACE])
{
ListaBroni[(int)aktywnaBron].Strzel();
}
kawałek kodu z klasy Bron :
class Bron
{
private int _poziomAmunicji = 50;
public void Strzel()
{
...odtwórz dźwięk
if(this._poziomAmunicji > 0) this._poziomAmunicji--;
..inne funkcje dotyczące trzału
}
}
Jak widać wszystko zależy od rozplanowania. Możesz wymyślić sobie, że np. klasa Bazooka dziedziczy z klasy Bron, bo np. Metoda Strzel w Bazooce wygląda trochę inaczej niż w np. MiotaczuOgnia, ale każda z broni ma pole z liczbą amunicji. Wtedy możemy zadanie rozwiązać na dwa sposoby.
-----wtrącenie-------
W skrócie Bazooka:Bron lub MiotaczOgnia:Bron, wtedy w bazooce można na stałe przypisać wartość do pola z Broni, nie trzeba tego robić przez np. konstruktor
-----//wtracenie------
Sposób 1. tworzymy dodatkową metodę za pomocą której odejmiemy amunicję, minimalnie więcej pisania
class Bazooka
{
private int _poziomAmunicji = 40;
public void OdejmijAmunicje()
{
if(this._poziomAmunicji > 0)
this._poziomAmunicji--;
}
}
class Bazooka:Bron
{
bla bla bla bla
}
SPOSÓB WYWOŁANIA
if(KEY[SPACE])
{
ListaBroni[(int)aktywnaBron].Strzel();
ListaBroni[(int)aktywnaBron].OdejmijAmunicje();
//bądź w funkcji strzel bazooki wywolujesz OdejmijAmunicje, co jest chyba bardziej logiczne
}
_________________________________________________
Opcja druga troszkę ciekawsza jeśli obiekt klasy Bron nie istnieje jako tako, powinno się klasę oznaczyć jako abstract, co daje nam pewne rozszerzenie ;]
abstract class Bron
{
private int _poziomAmunicji = 40;
public virtual void Strzel()
{
if(this._poziomAmunicji > 0)
this._poziomAmunicji--;
}
}
Teraz klasa Bazooka dziedziczy z Bron czyli class Bazooka:Bron
{
public override void Strzel()
{
zrób metody specyficzne dla Bazooki
base.Strzel(); // rowna się jakby Bron.Strzel();
}
}
wtedy
if(KEY[SPACE])
{
ListaBroni[(int)aktywnaBron].Strzel();
//kod zostaje ten sam ;)
}
_________________________________________________
To w sumie tyle i to jest moja interpretacja przedstawionych metod. Obiektowość jest ciekawa i chciałem Cie zachęcić do jej dalszego poznawania, wbrew pozorom jest to ładne, lecz nie zaprzeczam, potrzeba trochę czasu na oswojenie się ze wszystkim. Z góry przepraszam jesli w c++ robi się coś inaczej niż w c#, jedyna chyba róznica, to że trzeba zastąpić C# znak . na znak ->