W poprzednim poście powierzchownie opisałem 4 rodzaje broni jakimi nasz robocik będzie dysponował. Narazie będzie miał niewyczerpalną amunicję ale z czasem się to zmieni...
Odrazu napiszę, że kody żródłowe z poprzednich wersji troszeczkę się będą różniły od siebie, ponieważ jak zaznaczyłęm na początku uczę się obiektowości i cały czas przerabiam klasy dodając lub przenosząc pola i metody do innych powstających klas.
Kody nie różnią się od siebie diametralnie, lecz różnice są zauważalne. Jak ktoś(o ile komuś się zechce :P) będzie analizował kod i nie będzie czegoś rozumiał lub miał pytania proszę o pytanue w komentarzu pod danym postem to rozwieję wątpliwości :)
Myślałem jak by zrobićklasę odpowiadającą za bronie i wymyśliłem coś takiego:
class Cshots
{
public:
int pozpoc_x, pozpoc_y;
void strzelaniee(int, int);
Cshots::Cshots ()
{
pozpoc_x=0;
pozpoc_y=0;
}
};
void Cshots::strzelaniee(int pozx, int pozy)
{
pozpoc_x=pozx+15;
pozpoc_y=pozy-15;
}
Klasa sama w sobie nic nie robi ustawia tylko początkową pozycję pocisku (x i y) dopiero w main zabawa się zaczyna :P
Tworzymy sobie 4 obiekty użyję 4 różnych kolorów(każdy kolor odpowada za dany obiekt) bo trochę jest tego kodu w main()
Cshots strzal_bazooka;
Cshots strzal_machinegun;
Cshots strzal_laser;
Cshots strzal_flamethrower;
Teraz pokażę jak się będzie zmieniało w grze bronie.
Deklarujemy i definiujemy sobie zmienną: int bron=1;
Liczby od 1 do 4 będą odpowiadały za poszczególne bronie:
1-bazooka
2-karabin maszynowy
3-laser
4-miotacz ognia
I analogicznie na klawiaturze będziemy zmieniali bronie za pomocą klawiszy 1,2,3,4
if(key[KEY_1])
{
bron=1;
}
if(key[KEY_2])
{
bron=2;
}
if(key[KEY_3])
{
bron=3;
}
if(key[KEY_4])
{
bron=4;
}
_________________________________________________________________
Strzelać będziemy spacją
if( key[KEY_SPACE])
{
if(bron==1)
{
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)
{
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);
}
}
if(bron==3)
{
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);
}
}
if(bron==4)
{
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);
}
}
}
Wytłumaczę tą część kodu. Strzelanie w grze będzie wyglądało w następujący sposób: po wybraniu broni (1,2,3,4) i naciśnięciu spacji z robocika wyleci pocisk z broni, którą mamy aktywowaną. wystrzelenie pocisku będzie możliwe jeżeli jego pozycja y będzie mniejsza od 0 lub równa 0 tzn jeżeli opuści ekran gry, lub jeżeli trafimy w jakiś cel. Na ekranie będzie mógł się znajdować tylko 1 pocisk z poszczególnej broni, aby wystrzelić kolejny pocisk musi wyjść poza ekran lub musimy w coś trafić...
Widzimy także np:
play_sample(flamethrow, 200,200,1000,0);
tutaj odtwarzamy jakis dźwięk akurat dobrałem takie, które przypominają wystrzały z tych broni.
Omówię jeszcze funkcję z klasy
void Cshots::strzelaniee(int pozx, int pozy)
{
pozpoc_x=pozx+15;
pozpoc_y=pozy-15;
}
Do tej funkcji przesyłamy 2 argumenty pozycję x i y robocika aby pocisk wystrzelony z robocika wyleciał nie ze środka robocika ale z jego "głowy" ładniej to wygląda :P
Tak więc tą funkcją nadajemy pozycję x i y pocisku troszeczkę zmodyfikowaną z pozycji robocika.
i wywołujemy tak:
strzal_flamethrower.strzelaniee(ludek.pozs_x, ludek.pozs_y );
_________________________________________________________________
Dobrze by było gdybyśmy wiedzieli którą broń mamy aktywowaną... Proponuję wrócić do poprzednich 2 postów, tam jest klasa Cmenu i i bitmapy, które teraz wykorzystam.
W prawym dolnym rogu będziemy wyświetlali naszą aktualną broń
if(bron==1)
{
masked_blit( menu_bazooka, bufor, 0,0, 674, 515, menu_bazooka->w, menu_bazooka->h);
}
else if(bron==2)
{
masked_blit( menu_machinegun, bufor, 0,0, 674, 515, menu_machinegun->w, menu_machinegun->h);
}
else if(bron==3)
{
masked_blit( menu_laser, bufor, 0,0, 665, 515, menu_laser->w, menu_laser->h);
}
else if(bron==4)
{
masked_blit( menu_flamethrower, bufor, 0,0, 665, 515, menu_flamethrower->w, menu_flamethrower->h);
}
_________________________________________________________________
musimy jeszcze wyświetlić nasze pociski:
if( (frame>=0) && (frame<=80) )
{
draw_sprite(bufor, mach_gun, strzal_machinegun.pozpoc_x, strzal_machinegun.pozpoc_y);
}
if( (frame>=0) && (frame<=80) )
{
draw_sprite(bufor, pocisk, strzal_bazooka.pozpoc_x, strzal_bazooka.pozpoc_y);
}
if( (frame>=0) && (frame<=80) )
{
draw_sprite(bufor, laser, strzal_laser.pozpoc_x, strzal_laser.pozpoc_y);
}
if( (frame>=0) && (frame<=80) )
{
draw_sprite(bufor, flame, strzal_flamethrower.pozpoc_x, strzal_flamethrower.pozpoc_y);
}
_________________________________________________________________
i wprawić nasze pociski w ruch tj. po każdym obiegu głównej pętli while( !key[KEY_ESC]) zmieniamy współrzędną y o pewną wartość. Im większa wartość tym szybciej będzie leciał pocisk. Uważam, że te wartości jak narazie są odpowiedznie, może z biegiem czasu ulegną zmianie :P
strzal_flamethrower.pozpoc_y=strzal_flamethrower.pozpoc_y-10;
strzal_laser.pozpoc_y=strzal_laser.pozpoc_y-30;
strzal_machinegun.pozpoc_y=strzal_machinegun.pozpoc_y-40;
strzal_bazooka.pozpoc_y=strzal_bazooka.pozpoc_y-5;
W następnym poście zrobię kolizję. Do pobrania kod wraz z plikami potrzebnymi do uruchomienia gry ver.1.02.
Jeżeli macie pytania, propozycje to piszcie w komentarzach, napewno odpowiem :)
Gra na tym etapie wygląda następująco:
Blog opisujący powstawanie gry od pierwszej linii kodu. Gra wykonana w C++/allegro
[POBIERZ] kod źródłowy i inne pliki potrzebne do uruchomienia gry [POBIERZ]
Zachęcam do komentowania :) Mile widziane sugestie i pytania, na które chętnie odpowiem
29 sie 2010
26 sie 2010
wstęp do broni w grze
Napiszę teraz dlaczego w prawie każdej bitmapie występuje kolor różowy.
Kolor różowy kod RGB(255,0,255) w allegro jest pomijany, tzn jeżeli mamy 2 obrazki:
1. z białym tłem, jeżeli wyświetlimy tą bitmapę w programie to kolor biały(otaczające tło) także zostanie wyświetlony.
2. z różowym tłem, jeżeli wyświetlimy tą bitmapę w programie to zostanie wyświetlona tylko bazooka, bez otaczającego ją różowego tła ponieważ kolor różowy kod RGB(255,0,255) jest pomijany.
Na początku bloga napisałem, że będą 4 rodzaje broni: bazooka, karabin maszynowy, laser i miotacz ognia. oto one:
1) bazooka:
Pocisk wystrzelony z tej broni będzie wyglądał tak:

2) karabin maszynowy:
Pocisk wystrzelony z tej broni będzie wyglądał tak (zwykła kropka w paincie :P):
3) laser:
Pocisk wystrzelony z tej broni będzie wyglądał tak (zwykła kreska w paincie :P):
4) miotacz ognia:
Pocisk wystrzelony z tej broni będzie wyglądał tak :
Oczywiście przy wystrzale z każdej broni będzie odtwarzany dźwięk, każda broń będzie inaczej się zachowywała, traciła mniej lub więcej żyć, a także planuję aby miotacz ognia pozwalał na niszczenie wrogich pocisków... Za jakiś czas wrzucę kod wraz z wszystkimi potrzebnymi plikami i jak zawsze napiszę nowego posta wyjaśniającego wybrane fragmenty kodu.
Kolor różowy kod RGB(255,0,255) w allegro jest pomijany, tzn jeżeli mamy 2 obrazki:
1. z białym tłem, jeżeli wyświetlimy tą bitmapę w programie to kolor biały(otaczające tło) także zostanie wyświetlony.
2. z różowym tłem, jeżeli wyświetlimy tą bitmapę w programie to zostanie wyświetlona tylko bazooka, bez otaczającego ją różowego tła ponieważ kolor różowy kod RGB(255,0,255) jest pomijany.
Na początku bloga napisałem, że będą 4 rodzaje broni: bazooka, karabin maszynowy, laser i miotacz ognia. oto one:
1) bazooka:
Pocisk wystrzelony z tej broni będzie wyglądał tak:
2) karabin maszynowy:
Pocisk wystrzelony z tej broni będzie wyglądał tak (zwykła kropka w paincie :P):
3) laser:
Pocisk wystrzelony z tej broni będzie wyglądał tak (zwykła kreska w paincie :P):
4) miotacz ognia:
Pocisk wystrzelony z tej broni będzie wyglądał tak :
Oczywiście przy wystrzale z każdej broni będzie odtwarzany dźwięk, każda broń będzie inaczej się zachowywała, traciła mniej lub więcej żyć, a także planuję aby miotacz ognia pozwalał na niszczenie wrogich pocisków... Za jakiś czas wrzucę kod wraz z wszystkimi potrzebnymi plikami i jak zawsze napiszę nowego posta wyjaśniającego wybrane fragmenty kodu.
23 sie 2010
Interfejs w grze
Kolej na obiecany interfejs...
Napewno pamiętacie grę doom, gdzie głowa głównego bohatera po stracie n-% żyć pokrywała sięcoraz bardzierj krwią... Chcę uzyskać podobny efekt, lecz będzie to niestety "kulawe graficznie" ponieważ, nie jestem grafikiem... W grze po stracie kolejnych 10% żyć robocik będzie zamalowywany coraz bardziej kolorem czerwonym....
tak więc na początek deklarujemy sobie 11 bitmap:
BITMAP *Statek_HP100 = NULL;
BITMAP *Statek_HP90 = NULL;
BITMAP *Statek_HP80 = NULL;
BITMAP *Statek_HP70 = NULL;
BITMAP *Statek_HP60 = NULL;
BITMAP *Statek_HP50 = NULL;
BITMAP *Statek_HP40 = NULL;
BITMAP *Statek_HP30 = NULL;
BITMAP *Statek_HP20 = NULL;
BITMAP *Statek_HP10 = NULL;
BITMAP *Statek_HP0 = NULL;
I dla Statek_HP100 bitmapa będzie wyglądała tak:
dla Statek_HP90
*
*
*
i w końcu dla Statek_HP0
W tym celu stworzyłem klasę Cmenu, w której będę umieszczał poszczególne elementy interfejsu gry... Oto ona:
class Cmenu
{
public:
int pozstathp_x, pozstathp_y;
int pozmenu_x, pozmenu_y;
int pos;
void wyswietl_obrazki();
Cmenu::Cmenu()
{
pozmenu_x=0;
pozmenu_y=480;
pozstathp_x=10;
pozstathp_y=515;
pos=0;
}
};
void Cmenu::wyswietl_obrazki()
{
masked_blit( menudolne, bufor,0,0,pozmenu_x,pozmenu_y,menudolne->w, menudolne->h);
textprintf_ex(bufor,font,2,488,makecol(0,200,200),-1,"stanzyc: %d%%",zycia);
masked_blit( Statek_HP100, bufor, 0,0, pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
if(czas_odt_muz >161)
{
czas_odt_muz=0;
}
if( frame>=40)
{
masked_blit( Statek_HP100, bufor, 0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w,Statek_HP100->h);
if( (zycia > 80) && (zycia<=90) )
{
masked_blit( Statek_HP90,bufor,0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
}
else if( (zycia > 70) && (zycia<=80) )
{
masked_blit( Statek_HP80, bufor, 0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
}
/*
i tak dalej az do zycia <=0
*/
else if (zycia <= 0)
{
masked_blit( Statek_HP0, bufor, 0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
}
}
}
W funkcji wyswietl_obrazki() chodzi o to aby od frame=0 do frame=40 wyswietlało nie zamalowanego robocika, a od frame=41 do frame=80 robocika z zamalowana czescia na czerwony kolor. (Niby miał to wyjść efekt popsutej poszczególnej części ale niestety nie mam talentu i wyszło jak wyszło...) Efekt jest taki: jesli mamy mniej niz 91% zyc czerwone czesci robocika zaczynaja nam migac.
w konstruktorze podałem współrzędne elementów interfejsu gry. Żeby było jasne menu_dolne ma wymiary 800*120 i w konstruktorze jego pozycja Y to pozmenu_y=480, bo Nasza gra ma rozdzielczość 600... a menu_dolne wygląda tak:
różowy kolor w bitmapie oznacza, że w grze będzie niewidoczny...
Skoro napisałem o deklarowaniu bitmap to napiszę jak wczytac taka bitmape do programu, a także o tym samym tylko dla dźwięku...
dla Statek_HP100:
podajemy nazwe wczesniej zadlklarowana czyli Statek_HP100 i za pomocą tej instrukcji w cudzyslowie "" podajemy ścieżkę do pliku
Statek_HP100=load_bmp("BMP/Statek_HP/Statek_HP100.bmp",default_palette);
musimy także pamiętać aby na końcu programu zwolnić używaną pamięć przez bitmapę instrukcją:
destroy_bitmap(Statek_HP100);
Warto w programie dodać taką instrukcję, uchroni nas przed jakimś poważnym błędem, a nawet zawieszeniem systemu. Stanie siętak jeśli po uruchomieniu programu zabraknie takiego pliku o tej nazwie we wskazanym przez Nas katalogu :
if (!Statek_HP100)
{
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_message("brak pliku .bmp");
allegro_exit();
return 0;
}
i to by było na tyle. Teraz kolej na dźwięk deklarujemy go w ten sposob:
SAMPLE *dzwiek = NULL;
definiujemy w podobny sposób jak bitmapy podając ścieżkę:
dzwiek = load_sample("wybuch.wav");
I teraz musimy zatrzymać ten dźwięk instrukcją:
stop_sample(dzwiek);
i zwolnić z pamięci:
destroy_sample(dzwiek);
i analogicznie ja kw bitmapach warto dodać instrukcję:
if (!dzwiek)
{
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_message("brak pliku .wav");
allegro_exit();
return 0;
}
Aha w klasie Cmenu są jeszcze wyświetlane życia za pomocą funkcji:
textprintf_ex(bufor,font,2,490,makecol(0,200,200),-1,"stan zyc: %d%%", zycia);
1-arg jest to gdzie wyświetlamy ten napis czylu u nas w buforze
2- czcionka
3 i 4 współrzędne
makecol(0,200,200) ustalamy kolor w systemie RGB
i nasz tekst: "stan zyc: %d%%", gdzie %d używamy z C :p i %% aby wyświetlić % (ponieważ % jest znakiem specjalnym i żeby go wyświetlićmusimy go powtórzyć)
-i na koniec zmienna integer u nas zycia;
To by było na tyle. W porównaniu do wersji 1.00 zrezygnowałem z nieefektownego elementu wybuchu, w jakiejś wersji dopracuję i dodam ponownie :). Do pobrania kod wraz z plikami potrzebnymi do uruchomienia gry ver.1.01.
Jeżeli macie pytania, propozycje to piszcie w komentarzach, napewno odpowiem :)
Gra na tym etapie wygląda następująco:
Napewno pamiętacie grę doom, gdzie głowa głównego bohatera po stracie n-% żyć pokrywała sięcoraz bardzierj krwią... Chcę uzyskać podobny efekt, lecz będzie to niestety "kulawe graficznie" ponieważ, nie jestem grafikiem... W grze po stracie kolejnych 10% żyć robocik będzie zamalowywany coraz bardziej kolorem czerwonym....
tak więc na początek deklarujemy sobie 11 bitmap:
BITMAP *Statek_HP100 = NULL;
BITMAP *Statek_HP90 = NULL;
BITMAP *Statek_HP80 = NULL;
BITMAP *Statek_HP70 = NULL;
BITMAP *Statek_HP60 = NULL;
BITMAP *Statek_HP50 = NULL;
BITMAP *Statek_HP40 = NULL;
BITMAP *Statek_HP30 = NULL;
BITMAP *Statek_HP20 = NULL;
BITMAP *Statek_HP10 = NULL;
BITMAP *Statek_HP0 = NULL;
I dla Statek_HP100 bitmapa będzie wyglądała tak:
dla Statek_HP90
*
*
*
i w końcu dla Statek_HP0
W tym celu stworzyłem klasę Cmenu, w której będę umieszczał poszczególne elementy interfejsu gry... Oto ona:
class Cmenu
{
public:
int pozstathp_x, pozstathp_y;
int pozmenu_x, pozmenu_y;
int pos;
void wyswietl_obrazki();
Cmenu::Cmenu()
{
pozmenu_x=0;
pozmenu_y=480;
pozstathp_x=10;
pozstathp_y=515;
pos=0;
}
};
void Cmenu::wyswietl_obrazki()
{
masked_blit( menudolne, bufor,0,0,pozmenu_x,pozmenu_y,menudolne->w, menudolne->h);
textprintf_ex(bufor,font,2,488,makecol(0,200,200),-1,"stanzyc: %d%%",zycia);
masked_blit( Statek_HP100, bufor, 0,0, pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
if(czas_odt_muz >161)
{
czas_odt_muz=0;
}
if( frame>=40)
{
masked_blit( Statek_HP100, bufor, 0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w,Statek_HP100->h);
if( (zycia > 80) && (zycia<=90) )
{
masked_blit( Statek_HP90,bufor,0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
}
else if( (zycia > 70) && (zycia<=80) )
{
masked_blit( Statek_HP80, bufor, 0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
}
/*
i tak dalej az do zycia <=0
*/
else if (zycia <= 0)
{
masked_blit( Statek_HP0, bufor, 0,0,
pozstathp_x,pozstathp_y,Statek_HP100->w, Statek_HP100->h);
}
}
}
W funkcji wyswietl_obrazki() chodzi o to aby od frame=0 do frame=40 wyswietlało nie zamalowanego robocika, a od frame=41 do frame=80 robocika z zamalowana czescia na czerwony kolor. (Niby miał to wyjść efekt popsutej poszczególnej części ale niestety nie mam talentu i wyszło jak wyszło...) Efekt jest taki: jesli mamy mniej niz 91% zyc czerwone czesci robocika zaczynaja nam migac.
w konstruktorze podałem współrzędne elementów interfejsu gry. Żeby było jasne menu_dolne ma wymiary 800*120 i w konstruktorze jego pozycja Y to pozmenu_y=480, bo Nasza gra ma rozdzielczość 600... a menu_dolne wygląda tak:
różowy kolor w bitmapie oznacza, że w grze będzie niewidoczny...
Skoro napisałem o deklarowaniu bitmap to napiszę jak wczytac taka bitmape do programu, a także o tym samym tylko dla dźwięku...
dla Statek_HP100:
podajemy nazwe wczesniej zadlklarowana czyli Statek_HP100 i za pomocą tej instrukcji w cudzyslowie "" podajemy ścieżkę do pliku
Statek_HP100=load_bmp("BMP/Statek_HP/Statek_HP100.bmp",default_palette);
musimy także pamiętać aby na końcu programu zwolnić używaną pamięć przez bitmapę instrukcją:
destroy_bitmap(Statek_HP100);
Warto w programie dodać taką instrukcję, uchroni nas przed jakimś poważnym błędem, a nawet zawieszeniem systemu. Stanie siętak jeśli po uruchomieniu programu zabraknie takiego pliku o tej nazwie we wskazanym przez Nas katalogu :
if (!Statek_HP100)
{
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_message("brak pliku .bmp");
allegro_exit();
return 0;
}
i to by było na tyle. Teraz kolej na dźwięk deklarujemy go w ten sposob:
SAMPLE *dzwiek = NULL;
definiujemy w podobny sposób jak bitmapy podając ścieżkę:
dzwiek = load_sample("wybuch.wav");
I teraz musimy zatrzymać ten dźwięk instrukcją:
stop_sample(dzwiek);
i zwolnić z pamięci:
destroy_sample(dzwiek);
i analogicznie ja kw bitmapach warto dodać instrukcję:
if (!dzwiek)
{
set_gfx_mode(GFX_TEXT,0,0,0,0);
allegro_message("brak pliku .wav");
allegro_exit();
return 0;
}
Aha w klasie Cmenu są jeszcze wyświetlane życia za pomocą funkcji:
textprintf_ex(bufor,font,2,490,makecol(0,200,200),-1,"stan zyc: %d%%", zycia);
1-arg jest to gdzie wyświetlamy ten napis czylu u nas w buforze
2- czcionka
3 i 4 współrzędne
makecol(0,200,200) ustalamy kolor w systemie RGB
i nasz tekst: "stan zyc: %d%%", gdzie %d używamy z C :p i %% aby wyświetlić % (ponieważ % jest znakiem specjalnym i żeby go wyświetlićmusimy go powtórzyć)
-i na koniec zmienna integer u nas zycia;
To by było na tyle. W porównaniu do wersji 1.00 zrezygnowałem z nieefektownego elementu wybuchu, w jakiejś wersji dopracuję i dodam ponownie :). Do pobrania kod wraz z plikami potrzebnymi do uruchomienia gry ver.1.01.
Jeżeli macie pytania, propozycje to piszcie w komentarzach, napewno odpowiem :)
Gra na tym etapie wygląda następująco:
Subskrybuj:
Posty (Atom)