Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: SDL_Flip(screen);

Touho [13.10.2004 22:13:39]

#

<katso viestin loppu ensin>

Taidan kaivata tarkempaa tietoa tuosta Flipistä ja puskuroinnista.

Ensin teen hiirmusesti kuvia taustaan.
(80*60 kertaa 10*10pikselinen kuva. vie hirmusesti aikaa.)

for (x=0;x<80;x++)
for (y=0;y<60;y++)
{
	switch(bricks[x][y])
	{
	case 1:
		{
			brick = SDL_LoadBMP("Bricks/1.bmp");
			break;
		}
	}
	if(bricks[x][y]>0)
	{
		SDL_Rect dest;
		dest.x = x*10;
		dest.y = y*10;
		SDL_BlitSurface(brick, NULL, screen, &dest);


	}
}

Seuraavaksi tulee looppi, josta kutsutaan seuraavaa pätkää:
(piirretään pieni musta alue ja pieni ukko.. eli ei vie juuri yhtään aikaa)

Slock();
for(x=ukko_x-3;x<ukko_x+4;x++)
for(y=ukko_y-9;y<ukko_y+8;y++)
{
	Uint32 *bufp;
	bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
	*bufp = SDL_MapRGB(screen->format, 0, 0, 0);
}
Sulock();

DrawIMG(ukko, ukko_x, ukko_y);
SDL_Flip(screen);

Loopin ollessa käynnissä ruutu välkkyy kokoajan! Välkkyminen korjaantuu, jos laitan ruutujenpiirtokoodin looppiin, mutta tämä vie niin paljon aikaa, että peliä ei voi saada pyörimään sen jälkeen.

Miksi koko ruutu välkkyy, vaikka piirretäänkin vain pieni ukko yhteen nurkkaan? Ja mitä SDL_Flip(screen); tekee, kun pitää niin ison urakan tehdä? kysymyksiä riittää ja paljon.. Miten saa SDL_Flip:n piirtämään pelkästään sen pienen ukon sinne nurkkaan eikä kaikkea puskurin historiaa?

Osaisiko joku auttaa?

EDIT: Se ukko on buginen ja kaikkea, mutta sen saan kuntoon, jos yritän;välkkymistä en.

PS: Otin tuplapuskuroinnin pois ja koko välkkyminen meni pois.
Olen pari päivää yrittänyt korjata. heti, kun laitoin tän putkaan, niin selvisi.

Mutta mitä tämä tuplapuskuroiminen johtuu, kun se niin bugittaa koko ohjelman?

Metabolix [13.10.2004 22:56:43]

#

Ensiksi haluaisin ihmetellä tuota hassua Read-funktiota, eihän se voi toimia noin! Jos taulukko on int bricks[80][60], se tarkoittaa, että taulukon viimeinen alkio on bricks[79][59]. Muutenkaan et voi palauttaa taulukkoa tuolla tavalla. Sen sijaan jos Read-funktio olisi void Read(int ** bricks), voisit muokata tuota bricks-muuttujaa suoraan aivan normaalina taulukkona, eikä palautusarvoa tarvittaisi.

Sitten houmauttaisin, että keys = SDL_GetKeyState(NULL); ja kaikki siihen liittyvät asiat löytyvät nyt koodista kahteen kertaan, kerran if-lauseen kanssa ja heti perään ilman sitä. Pitäisikö se ensimmäinen esiintymä ehkä poistaa?

Nyt päästäänkin jo Slock()-funktioon. Mitä ihmeen järkeä on lauseessa if ( SDL_LockSurface(screen) < 0 ) return;, kun funktiolla ei ole palautusarvoa ja funktio päättyy joka tapauksessa tuon jälkeen?

Sitten onkin vuorossa DrawScene-funktio. Ehdottaisin, että määrittely Uint32 *bufp; siirrettäisiin loopin ulkopuolelle.

Tuplapuskuroinnin tarkoitus on se, että saadaan koko ruutu päivitettyä kerralla. Graafisesti vähänkään isommissa asioissa tuon merkityksen huomaa, ja ilman tuplapuskurointia grafiikka itse asiassa välkkyy; tuplapuskurointi on käytössä muun muassa juuri sen estämiseksi. Lisäksi tarkoituksena on, että kaikki muutokset näkyisivät ruudulla samaan aikaan, eivätkä sitä mukaa, kun niitä piirretään. Kuvittelepa räiskintäpeli, jossa jokaisen uuden kuvan välillä siirtyy ensin yksi seinä, sitten toinen ja lopuksi vielä katto ja lattiakin. Sitten tyyppiä piirrettäessä ensin siirtyy pää, sitten toinen jalka... Aika jänskää.

Lopuksi vielä ihmettelen tuota switch(bricks[x][y])-kohdan koodia. Näyttäisit siellä lataavan aika moneen kertaan tuon Bricks/1.bmp -kuvan. Eikö SDL:ssä tunneta muistivuotoja? Joka tapauksessa kannattaisi ladata vain yksi iso kuva (tilemap), jossa kaikki eri palaset olisivat, jolloin voidaan vain valita, mikä kohta siitä piirretään.

tn [14.10.2004 09:42:32]

#

Ruutu välkkyy tuplapuskuroinnilla, koska se (kaksoispuskurointi) perustuu siihen, että on kaksi piirtopintaa, jotka näytetään kuvaruudulla vuorotellen (ei niin, että toisen sisältö kopioitaisiin aina toiseen). Kun siis piirrät jotain, niin se menee siihen puskuriin, joka ei sillä hetkellä näy näytöllä. Kun sen jälkeen kutsut SDL_Flippiä, vaihdetaan rooleja ja ryhdytäänkin näyttämään sitä, mille viimeksi piirrettiin, ja piirto kohdistuukin siihen toiseen kunnes taas vaihdetaan.

Koska piirsit taustan vain kertaalleen, jäi toiseen bufferiin pelkkä musta tausta. Kun sitten joka toinen kerta näytetään vain mustaa, niin kyllähän se ruutu välkkyy. Yksi mahdollisuushan on piirtää tausta aluksi kahteen kertaan, ja kutsua siinä välissä SDL_Flippiä. Järkevämpää tässä tapauksessa (ja yleensäkin, jos ei haluta piirtää koko ruutua uudestaan) lienee kuitenkin olla käyttämättä kaksoispuskurointia.

Touho [14.10.2004 16:01:20]

#

Metabolix:

Read-funktio:
minä en saanut tätä funktiota toimimaan sillä tavalla, että laitan funktion palauttamaan "bricks", mutta jostain syystä se toimii, kun se palauttaa "bricks[80][60]". Kyllä se palauttaa taulukon jokaisen arvon. pakko myöntää, että tämä on huono tyyli, ja en itsekään ymmärrä, miksi se toimii näin.

keys = SDL_GetKeyState(NULL); :
kopioin aluksi koko koodin toisesta pikku ohjelmasta, jossa tarvittiin kahteen kertaan tätä. En huomannut poistaa tätä.

Slock();, Sulock(); :
kopioin nämä kaksi funktiota tutorialista, enkä tiedä niiden toiminnasta.

bufp:
hyvä idea

tuplapuskurointi:
Kiitos teille molemmille tuplapuskuroinnin idean selittämisestä!

brick:
voisin laittaa jossain vaiheessa kaikki bricit yhteen. nyt niitä on vain yksi ja tämä oli ensimmäinen idea, joka tuli mieleen.

Metabolix [14.10.2004 17:28:19]

#

Touho kirjoitti:

Read-funktio:
minä en saanut tätä funktiota toimimaan sillä tavalla, että laitan funktion palauttamaan "bricks", mutta jostain syystä se toimii, kun se palauttaa "bricks[80][60]". Kyllä se palauttaa taulukon jokaisen arvon. pakko myöntää, että tämä on huono tyyli, ja en itsekään ymmärrä, miksi se toimii näin.

No etpä tosiaan taida ymmärtää. Funktion palautusarvolla ei ole mitään merkitystä. Funktion sisällä muokkaat juuri sitä taulukkoa, jonka olet saanut parametrinä. On ihan hyvää tuuriasi, että tuo palautusarvo ei kaada koko ohjelmaa, koska se todellakin palauttaa arvon taulukon ulkopuolelta. Muistaakseni tuon Readin palautusarvoksi oli määritelty int. Eihän se edes voi silloin palauttaa taulukkoa. Eli mitäpä, jos tekisit niin, että määrittelisit funktion: void Read(... ja mitä parametrejä sillä olikaan. Sitten kutsuisit sitä aivan samoilla parametreillä kuin ennenkin, mutta jättäisit kutsun edestä pois sen bricks[80][60] = -kohdan. Seuraavaksi etsi jokin C/C++-opas, jossa käsitellään taulukoita ja osoittimia, ja yritä ymmärtää, kuinka ne toimivat.

Touho [15.10.2004 13:07:36]

#

jos se olisi void funktio, miten alkuperäinen main:ssa tehty bricks taulukko voisi saada luetut arvot, kun eihän se taulukko ole globaali!

Metabolix [15.10.2004 14:17:07]

#

Koska annat sen parametrinä.
Tässä muutama perusasia taulukoista:

  1. Taulukko on osoitin taulukon ensimmäiseen arvoon.

  2. Moniulotteinen taulukko on osoitin osoittimiin, jotka osoittavat kunkin rivin ensimmäiseen alkioon.

  3. Tällä perusteella seuraavat rivit saavat aikaan saman asian:

    char Taulukko[10];
    char *Taulukko = new char[10];

    Erona on se, että jälkimmäinen toimii vain C++:ssa ja että se pitää tuhota erikseen:

    delete [] Taulukko;
  4. Myös seuraavat rivit saavat aikaan saman asian:

    char Muuttuja = Taulukko[5];
    char Muuttuja = *(Taulukko + 5);

Usko nyt, kun kokeneemmat kertovat. Jos et muuten usko, että tuo toimii, niin kokeile vaikka.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta