Miksiköhän tämä funktio ei vähennä vihollisen energiaa, vaan energia pysyy aina saman. Pelaajan energia vähennetään samanlaisella funktiolla, mutta se toimii. :S
void enemy::DecreaseEnergy(int maara) { //Debuggausta varten tulostuksia... std::cout<<"Vähennetään vihollisen ennergiaa"<<std::endl; std::cout<<"Määrä ennen vähennystä"<<this->energy<<std::endl; //Vähennetään vihollisen energiaa... this->energy-=maara; std::cout<<"tallennetaan vihollisen verta"<<std::endl; vX.push_back(this->x); vY.push_back(this->y); vLaskuri++; std::cout<<"Vihollisen energia vähennetty"<<std::endl; std::cout<<"ENERGIA on nyt: "<<energy<<std::endl; std::cout<<"ENERGIAA vahennettiin :"<<maara<<std::endl; }
Teet jotain muuta väärin. On aivan selvää, että tuo funktio toimii kyllä.
Edit: Alempana lisää koodia, josta saattais löytyä virhe.
Tossa pätkä siitä tiedostosta:
Määrä ennen vähennystä40 tallennetaan vihollisen verta Vihollisen energia vähennetty ENERGIA on nyt: 30 ENERGIAA vahennettiin :10 Vähennetään vihollisen ennergiaa Määrä ennen vähennystä40 tallennetaan vihollisen verta Vihollisen energia vähennetty ENERGIA on nyt: 30 ENERGIAA vahennettiin :10 Vähennetään vihollisen ennergiaa Määrä ennen vähennystä40 tallennetaan vihollisen verta Vihollisen energia vähennetty ENERGIA on nyt: 30 ENERGIAA vahennettiin :10
Lisää koodia...
void CheckCollinsion() { for(int j=0;j<AMMUKSIA;j++) { for(int i=0;i<ENEMIES;i++) { if(viholliset[i].GetState()==true) { TarkistaYksi(viholliset[i], j); } } } } void TarkistaYksi(enemy a, int j) { if(TormaysPelaaja(a, ukko)) { ukko.DecreaseEnergy(1); } if(TormaysPanos(a, ammukset[j])) { a.DecreaseEnergy(10); ammukset[j].SetX(-1); ammukset[j].SetY(-1); ammukset[j].SetSpeed(0); } }
void TarkistaYksi(enemy a, int j)
Funktion kutsuminen luo siis aina uuden vihollisen. Opettelisit käyttämään niitä viittauksia (tai edes osoittimia, vaikka ne ovatkin huonommin sopivia).
Lisää debug-tulostus luokan muodostimeen ja tuhoajaan, niin huomaat.
enemy() { cout << "enemy() osoitteessa " << this << endl; } ~enemy() { cout << "~enemy() osoitteessa " << this << endl; }
Mahdatko ymmärtää tuon silmukkarakenteesi seurauksia? Tarkistat ukon ja vihollisen törmäyksen kerran jokaista ammusta kohden, vaikkei se ammus liity millään tavalla asiaan.
EDIT: peli jökkää jostain syystä satunnaisesti vihollisia tapettaessa, yleensä kun tappaa 2 vihollista ja tämän jälkeen ampuu kerran vihollista päin koko homma kaatuu... :S
vehkis91 kirjoitti:
Edit: teeknö sitten toisen silmukan missä tarkastan törmäykset pelaajaan? eikös se hidasta pelin kulkua jos on hirveesti eri silmukoita?
Mietipä itse, kumpi on hitaampi:
AMMUKSIA kertaa (AMMUKSIA): ENEMIES kertaa (ENEMIES): tarkista(ukko, vihollinen[i]); // AMMUKSIA * ENEMIES kertaa tarkista(ammus[j], vihollinen[i]); // AMMUKSIA * ENEMIES kertaa // yhteensä A*E + A*E tarkistusta, esim. A = 100, E = 10 tekee jo 2000
ENEMIES kertaa (ENEMIES): tarkista(ukko, vihollinen[i]); // ENEMIES kertaa AMMUKSIA kertaa (AMMUKSIA): tarkista(ammus[j], vihollinen[i]); // AMMUKSIA * ENEMIES kertaa // yhteensä E + A*E tarkistusta, esim. A = 100, E = 10 tekee vain 1010, noin puolet
Ylimääräistä silmukkaakaan ei tarvittu, mutta sekään ei juuri vaikuttaisi asioihin. Yleensä silmukan sisällä tehtävät asiat (tässä tarkista-funktio) vievät paljon enemmän aikaa kuin itse silmukka. Olennaista on siis opetella laskemaan, montako kertaa jotain oikeasti tehdään. Silmukat kannattaa suunnitella järjen kanssa niin, että kaikki tehdään vain kerran. Esimerkiksi vihollisten keskinäisissä törmäyksissä on turha tarkistaa erikseen tapauksia 1-2 ja 2-1, kannattaa tarkistaa vain ne, joita ei ole vielä tarkistettu: 1-2, 1-3, 1-4, ..., 2-3, 2-4, ..., 3-4, ... jne.
joka viholliselle Vi: tarkista ukko, Vi joka ammukselle Ai: tarkista ukko, Ai joka viholliselle Vi: joka viholliselle Vj (kun j > i): tarkista Vi, Vj joka ammukselle Ai: tarkista Vi, Ai
Edit. Opettele myös käyttämään debuggeria, se osaa kertoa, millä rivillä ohjelma kaatuu, ja voit sitten tutkiskella arvoista, mikä ehkä meni pieleen.
No debuggasin niin tulee vaan jotain muistipaikkoja ja ?-merkkejä. :S
Edit: tai siis funktion kohdalla on vaan ??(). :S
Et varmaankaan ole asettanut debug-infoa päälle. Jos käännät GCC:llä komentorivillä, ota optimoinnit (-O) pois ja lisää debug-info (-g).
Juu eli debuggasin tätä ja debuggerista tuli kaikkea ulos, mutt tämä pisti silmään...
#0 6812850c SDL_UpperBlit() (I:/..../SDL.dll:??)
tarkoittaako tämä, että sdl.dll tiedostossa on se vika? Kaatuminen on aika satunnaista, mutt yleensä kaatuu juuri kun ampuu vihollista. :S
Ei, tuo vain kertoo että jossain välissä käytät SDL_BlitSurfacea, joka on tuon UpperBlitin "kopio", ja että se löytyy tiedostosta SDL.dll
Tuo tarkoittaa, että kyseisessä funktiossa tapahtuu lopullinen kaatuminen. Tarkemmalla tutkimisella voit kuitenkin selvittää, miten sinne päädyttiin ja millaisia arvoja se sai parametrinaan. Tässä on pieni esimerkki, jossa ohjelma kaatuu, pyydetään tiedot aiemmista kutsuista (bt, backtrace), siirrytään tutkittavaan kohtaan omassa ohjelmassa (frame 1 bt:n tulosteen mukaisesti) ja tulostetaan sieltä joitakin arvoja (print C++-ilmaus):
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7d2f6c0 (LWP 3659)] 0xb7ee4d61 in SDL_UpperBlit () from /usr/lib/libSDL-1.2.so.0 (gdb) bt #0 0xb7ee4d61 in SDL_UpperBlit () from /usr/lib/libSDL-1.2.so.0 #1 0x08048638 in main () at koe.c:15 (gdb) frame 1 #1 0x08048638 in main () at koe.c:15 15 SDL_BlitSurface(ruutu, 0, kuva, 0); // piirretään (gdb) print ruutu $1 = (SDL_Surface *) 0xa01e750 (gdb) print kuva $2 = (SDL_Surface *) 0xa02d1b0 (gdb) print *ruutu $3 = {flags = 0, format = 0xa023f78, w = 640, h = 480, pitch = 2560, pixels = 0xb7954000, offset = 0, hwdata = 0x0, clip_rect = {x = 0, y = 0, w = 640, h = 480}, unused1 = 0, locked = 0, map = 0xa021830, format_version = 2, refcount = 1} (gdb) print *kuva Cannot access memory at address 0xa02d1b0
Viimeisestä ilmoituksesta selviää siis, että SDL_Surface *kuva osoittaa muistiin, jota ei voida käyttää. Se on siis ehkä jo vapautettu. Sen sijaan ruutu oli aivan kelvollinen SDL-pinta, josta saatiinkin hyvin tietoa irti. Tulostettavaksi kelpaavat C++:n normaalit muuttujat ja merkinnät eli esimerkiksi luokka->taulujasen[i+j]
.
Siis tulostetaanko niitä tietoja komennolla: print? vai? :O Pitää näyttävästi tutkia, että vapautanko muistin jossain paikoissa liian aikaisin... :S
Tässä vielä se koko debug-printti:
#0 6812850C SDL_UpperBlit() (I:\School\Ohjelmointi\\bin\Debug\SDL.dll:??) #1 004018F6 enemy::Piirra(this=0x44a530, index=0, X=459, Y=197) (I:/School/Ohjelmointi/Enemy.cpp:184) #2 00403DA6 PiirraKuva() (I:/School/Ohjelmointi/main.cpp:343) #3 00403989 SDL_main(argc=1, argv=0x9512b0) (I:/School/Ohjelmointi/main.cpp:221) #4 00404A77 console_main(argc=1, argv=0x9512b0) (./src/main/win32/SDL_win32_main.c:217) #5 00404C55 WinMain(hInst=0x400000, hPrev=0x0, szCmdLine=0x291da6 "", sw=10) (./src/main/win32/SDL_win32_main.c:353) #6 004044D4 main() (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/iostream:77)
Jos te saisitte siitä enemmän selkoa kun minä, en ole meinaa hirveesti softia debugannut. :S
Backtraceissa normaalisti mielenkiintoisin osa on ylin omaan koodiin viittaava kohta, tuossa siis Enemy.cpp:n rivi 184. (Tuo siis tulkitaan alhaalta ylöspäin niin, että main on kutsunut WinMainia, joka on kutsunut console_mainia, joka on kutsunut SDL_Mainia, joka on kutsunut PiirraKuvaa jne.)
Tuon perusteella voisi olettaa, että tuolla kutsuttavalle SDL_BlitSurfacelle (joka nyt näkyy tuossa SDL_UpperBlittinä, oletan että et kutsu tämän nimistä funktiota suoraan koodistasi) annetaan parametrina rikkinäinen surface (esim. jo vapautettu tai joku on ylikirjoittanut sen tietoja) lähde- tai kohdeparametriksi.
Täysin varmaa ei kuitenkaan ole, että virhe tulee juuri tuossa kohdassa, sillä aiemmin sattunut virhe voi kaataa ohjelman vasta vähän myöhemmin.
Edit:: Öö, kopioin wikipediasta itoa funktion, mikä muuttaa char taulukon int:ksi.
Huomasin vain että se on hirveän raskas, joten onko c++ mitään omaa tyyliä tähän. eli tarkoitus olisi muuttaa pelaajan energian määrä char-taulukoksi tai stringiksi, että voin tulostaa sen sdl_ttf:llä esiin.
Tässä kopioimani funkkarit:
void reverse(char s[]) { int c, i, j; for (i = 0, j = strlen(s)-1; i<j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } } void itoa(int n, char s[]) { int i, sign; if ((sign = n) < 0) // record sign n = -n; // make n positive i = 0; do { /* generate digits in reverse order */ s[i++] = n % 10 + '0'; /* get next digit */ } while ((n /= 10) > 0); /* delete it */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); }
#include <sstream> #include <iostream> #include <string> void int2str(int i, std::string &s) { std::ostringstream os; os << i; s = os.str(); } std::string int2str2(int i) { std::ostringstream os; os << i; return os.str(); } int main() { int a = 84; int q = 823; std::string b; int2str(a, b); std::cout << b << std::endl; std::cout << int2str2(q) << std::endl; return 0; }
Tuon homman saa C:ssä hoidettua sprintf-funktiolla ja c++:ssa stringstreameillä:
#include <stdio.h> ... char str[64]; int luku=25; sprintf(str, "%d", luku);
#include <sstream> #include <string> ... std::ostringstream os; int luku=25; os << luku; std::string str = os.str();
Juu kiitos, tuo ostringstream toimii paljon luotettavammin kuin tuo itoa funkkari. :D
Omallakin funktiolla tuon voi tehdä tehokkaammin takaperin:
std::string format_integer(int n, bool aina_etumerkki = false) { char buf[15], etumerkki = aina_etumerkki ? '+' : 0; int i = sizeof(buf); // lopetusmerkki ja erikoistapaukset (0 ja negatiiviset) buf[--i] = 0; if (n < 0) { etumerkki = '-'; n = -n; } // hoidetaan luku alhaalta alkaen do { buf[--i] = '0' + (n % 10); } while (n /= 10); // lisätään etumerkki alkuun if (etumerkki) { buf[--i] = etumerkki; } return std::string(&buf[i]); }
Toki standardikirjaston välineet ovat paljon paremmat, kun voi helposti säätää halutessaan kaikenlaisia formatointitemppuja kuten etumerkkiä, tasausta jne.
Juu nuo viat saatu korjattua. Nyt vasta outo vika tulikin, kun tossa Code::Blockissa on silleen että saa valita että kääntääkö release version vai debug version, niin kun kääntää debug version niin kaikki pelaa hyvin, mutta kun kääntää release version niin tuo peli ukkon nopeus on tyyliin 100pxl vaikka sen pitäis olla 5. :S
Edit: Ja tyypin liikkuma-alue pienenee, eli tyyppi ei voi liikkua ku n1/2 siitä alueesta mitä se voi liikkua debug versiossa. :S
Jotain olet sitten tehnyt väärin, välineissä harvoin on vikaa. Miten rajoitat liikenopeutta, miten säilytät koordinaatit, miten hoidat tuon alueen reunaan törmäämisen? Ei auta kuin selvittää, missä menee pieleen. Tulostele vaikka ukon koordinaatteja ja vertaa, ovatko ne erilaiset ja muuttuvatko ne eri tavalla eri versioissa vai onko vika kuitenkin jossain muualla.
Siis en ole muuttanut koodia ollenkaan, se toimii kun kääntä "debug" version, mut release versio ei toimi. :( No pitääpä tutkia...
Tässä ukon ohjausfunkkari, missä on samassa se törmäystarkistus seiniin.
void player::Move() { if(player::state==true) { // Liikutetaan pelaajaa, jos mahdollista if(this->keyboard[SDLK_LEFT] && this->x - this->speed >= 0) { this->suunta=1; this->x -= speed; } else if(this->keyboard[SDLK_RIGHT] && (this->x + IMAGE_SIZE) + this->speed < SCREEN_WIDTH) { this->suunta=2; this->x += speed; } else if(this->keyboard[SDLK_UP] && this->y - this->speed >= 0) { this->suunta=3; this->y -= speed; } else if(this->keyboard[SDLK_DOWN] && (this->y + IMAGE_SIZE) + this->speed < SCREEN_HEIGHT) { this->suunta=4; this->y += speed; } } } //Pelaajan luonti player ukko(1000,400,300,5); //player pelaanannimi(energia,x,y,nopeus);
No se alkoi toimiin ku käänsin win xp:llä vistan sijasta. :S aika outoo...
Edit: Samalla tuli 0.6 versio ulos. Osoite on mun profiilissa.
onpas mahdoton peli :)
oikein hermot meni kun ne ötökät tulee niin nopiaa päälle että elinikä aina max 10sek ;/
Ei lainkaan mahdoton :), vaikka muutama minuutti läpipääsyyn vaadittiinkin. Toisaalta peli ei edes lopu vaikka kaikki viholliset tappaa, olisihan se kiva että jotenkin pelaamisesta palkittaisiin :/. Muutenkin peli olisi kiva aloittaa alusta ilman että se sulkeutuu välissä, sen lisäksi olisi kiva ehtiä reagoimaan alussa, ts. ettei peli käynnistyisi heti.
Eli, seuraavaan versioon tulee menu. Olen miettinyt, että miten voisin rajoittaa vihollisten iskunopeutta. Olen kyll yrittänytkin sitä, mutta se ei toiminut. Eli ehdotuksia saa laittaa... :D
Edit: Tuolla on "keskustelua" pelistä: http://www.suomipelit.com/index.php?c=keskusteluviestit&id=9315&s=1
Aihe on jo aika vanha, joten et voi enää vastata siihen.