SDL:n kanssa muuttujien arvon tulostaminen on eittämättä hankalampaa, kuin komentoriviohjelmissa. Olen rakentamassa järjestelmää, jolla tämä asia olisi helpompaa. Olen tällä hetkellä saanut systeemin toimimaan yhdellä muuttujalla. Alla esimerkki toiminnasta.
#ifdef DEBUG Piirto::dout() << PII; #endif
Yllä oleva koodi toimii juuri niin kuin pitääkin. Se siis tulostaa ruudulle tuon PII muuttujan arvon. Seuraava koodinpätkä ei toimi halutusti.
#ifdef DEBUG Piirto::dout() << PII << aika_nyt; #endif
Molemmat muuttujat kyllä tulostuvat ruudulle, mutta ne alkavat molemmat samasta kohdasta ruutua. Tämä on ihan oikein niin pitääkin alkaa, koska niin se on ohjelmoitu tästä ei tarvitse muistuttaa, mutta miten tuon uuden paikan laskeminen kannattaa tehdä?
class Piirto{ public: template <class T> Piirto operator <<(T muuttuja){ std::string s; s = muunna_tekstiksi(muuttuja); debug(s); return dout(); } static Piirto &dout(){ static Piirto p; return p; } };
Piirtämistä varten pieni luokka nimi ei ole paras mahdollinen, mutta sitä voin miettiä myöhemminkin.
template <class T> std::string muunna_tekstiksi(T a){ std::string b; std::stringstream tmp; tmp << a; tmp >> b; return b; }
Muunna tekstiksi on yksinkertainen, joskaan tämän kannalta ei välttämättä kauhean tärkeä asia enää.
void debug(std::string mita){ SDL_Surface *teksti; SDL_Rect minne = uusipaikka(30, 30); teksti = TTF_RenderText_Solid(fontti, mita.c_str(), vari); SDL_BlitSurface(teksti, NULL, ruutu, &minne); SDL_Flip(ruutu); } SDL_Rect uusipaikka(int x, int y){ SDL_Rect tmp = {x, y}; return tmp; }
Lopuksi vielä itse piirtäminen ja uuden paikan luominen. Muutujien piirto ruudulle tapahtuu pääsilmukassa, joten tuolle Piirto::dout() oliolle menevien muuttujien määrä pitäisi saada selville. Toivottavasti tästä sekavasta viestistä saa jotakin tolkkua. Selvennän tarvittaessa.
Sain tehtyä tuollaisen mahdollisesti purkkaratkaisun, eli laittamalla tuonne Piirto-luokkaan yhden laskurin. Kutsussa laitetaan viimeiseksi muutujaksi teksti "loppu".
class Piirto{ public: int kpl; template <class T> Piirto operator <<(T muuttuja){ std::string s; if(s == "loppu"){ this->kpl = 0; }else{ this->kpl++; } s = muunna_tekstiksi(muuttuja); debug(s); return dout(); } static Piirto &dout(){ static Piirto p; this->kpl = 0; return p; } };
Sitten vain lasketaan kuinka pitkä merkkijono tulostetaan ja kuinka isolla fontilla kirjoitetaan.
void debug(std::string mita, int kpl){ SDL_Surface *teksti; int pituus = mita.length(); int x = pituus * kpl * fontin_koko; SDL_Rect minne = uusipaikka(x, 30); teksti = TTF_RenderText_Solid(fontti, mita.c_str(), vari); SDL_BlitSurface(teksti, NULL, ruutu, &minne); SDL_Flip(ruutu); }
Ainakin palautat tulosta <<-operaattorista virheellisesti Piirto-olion dout(), kun pitäisi palauttaa viittaus (Piirto&) *this. Esittämässäsi "ratkaisussa" on ilmiselvä virhe: et voi staattisessa funktiossa käyttää this-sanaa, koska mitään oliota ei ole.
Kyseiset kohdat korjattuina:
Piirto& operator << (/*...*/) { //... return *this; } static Piirto& dout() { static Piirto p; return p; }
Säilytä piirto-luokassa tietoa x-koordinaatista johon tekstiä pitäisi seuraavaksi piirtää ja anna tämä arvo parametriksi debug-funktiolle. Kasvata tätä koordinaattia joka piirron jälkeen aina debug-funktion luoman tekstisurfacen leveyden verran.
Huomaa muuten että debug-funktiosi vuotaa tällä hetkellä muistia sillä et vapauta TTF_RenderText_Solid-funktion luomaa pintaa.
Lisähuomautus: funktiosi muunna_tekstiksi on nyt vähän ongelmallisesti toteutettu. Esimerkiksi muunna_tekstiksi("abc kissa kävelee") palauttaa vain merkkijonon "abc", mikä tuskin on toivottu lopputulos. Parempi toteutus:
template<class T> std::string muunna_tekstiksi(const T& a) { std::ostringstream tmp; tmp << a; return tmp.str(); }
Sisuaski minulla SDL:n alustusfunktiossa atexit(SDL_Quit), jonka pitäisi vapauttaa automagisesti pinnat. Muutoin kiitoksia korjauksista. En itse asiassa kokeillut tuota tapusta, jossa merkkijonossa on välejä. Tämä on tehty lähinnä lukuja varten.
Teuro kirjoitti:
minulla SDL:n alustusfunktiossa atexit(SDL_Quit), jonka pitäisi vapauttaa automagisesti pinnat
Tämä ei kelpaa ratkaisuksi. Pintoja kasaantuu muistiin ajon aikana. Käytännössä tämä aiheuttaa ongelmia vain, jos tulostat paljon tekstiä (esimerkiksi pelissä joka framella), mutta resurssien käsittely tuolla tavalla on joka tapauksessa huono lähestymistapa / ohjelmointivirhe, varsinkin, kun voisit vapauttaa SDL-pinnan heti sen käytön jälkeen.
Tajusin juu tosiaan pitää vapauttaa nuo pinnat.
Teuro kirjoitti:
SDL:n kanssa muuttujien arvon tulostaminen on eittämättä hankalampaa, kuin komentoriviohjelmissa.
En tiedä, onko mahdollista tai miten onnistuu muilla käyttöjärjestelmillä, mutta OS/2:lla on yksinkertaisen tempun avulla mahdollista jättää konsoli-ikkuna auki, kun SDL-sovellus aukeaa PM-ikkunaan.
STDOUT ja STDERR kannattaa asettaa puskuroimattomiksi. Tämän jälkeen konsoli-ikkunaan voi kirjoitella debuggaus viestejä vaikka printf():llä.
Jos kyse on tosiaan debug-tulosteista, jalskin ehdotus kannattaa huomioida. Windowsissa SDL oletusarvoisesti ohjaa tulosteen tiedostoihin stdout.txt ja stderr.txt, mutta version 1.2.14 myötä ominaisuuden saa pois asettamalla ympäristömuuttujan SDL_STDIO_REDIRECT=0 ennen ohjelman ajamista. Useissa kehitysympäristöissä muuttujan voi lisätä projektin asetuksiin, komentorivillä muuttujia asetetaan komennolla SET muuttuja=arvo
.
Aihe on jo aika vanha, joten et voi enää vastata siihen.