Moi!
Minulla on eräs ongelma tehtailun alla olevan pelini kanssa. Ongelmana on se, että kun 2D-pelissäni yhden kentän kuva on 8000 pikseliä leveä ja lataan sen kentän alussa kokonaan muistiin (SDL käytössä ja käytän ImageLoad-funktiota, joka lataa, optimoi näytölle ja lopuksi vapauttaa kuvan (SDL_FreeSurface()), niin peli on älyttömän hidas. Jo ennen kuin kenttä alkaa rullata näytöllä, liikkuu päähenkilösprite todella hitaasti.
2,8 GHz:n prosessorilla varustetussa koneessa se kyllä pyörii, mutta tällainen 2D-peli olisi tarkoitus olla myös saatavilla huonommillekin koneille.
Tekniikkana käytän pelkästään sitä, että rullaan koko kenttää vasemmalle, kun päähenkilösprite menee eteenpäin (oikealle siis). Miten olisi hyvä ladata noin suuri kuvatiedosto ja liikuttaa sitä, kun tuo käyttämäni tekniikka näyttää vievän liian paljon resursseja? Tile-pohjaiseen kenttätyyppiin en kyllä ala.
Näytönohjain koneessani on nVidia GeForce2 MX/MX 400, muistia 320 MB ja prosessorin taajuus 500 MHz. Käyttöjärjestelmänä on Ubuntu 7.10 Linux ja ohjelmointikielenä C++, API:na SDL.
niin kuinkas korkea se 8000 pikseliä leveä kuva onkaan?
Aivan, unohdin mainita tuon, eli 352 pikseliä korkea.
Enpä tiedä varmaksi, kun en C++:n syövereihin ole suuremmin tutustunut, mutta sanoisin, että tileihin pohjautuvaksi kartta on käytännön pakosta muutettava. Vai sisältääkö pelisi niin paljon erilaisia kohteita taustalla, että homma olisi ylivoimainen tileillä hoidettavaksi?
En tosiaankaan ole itse ikinä kokeillut tehdä ns. art-based -peliä, mutta olisiko mahdollista, jos lataat kuvan muistiin pienempinä paloina. Vaikkapa 1000 pikselin pätkissä ja kun ensimmäisen palan loppu alkaa lähestyä ladataan seuraava muistiin ja piirretään näytölle. Tosin tästä ei tile-toteutuskaan enää olisi kaukana.
Korjatkaa toki, jos SDL on yleisesti kykenevä käsittelemään noin isoja kuvia, mutta en usko, että tuolla tyylillä kovin nopeaan ja sulavaan toteutukseen päädytään - etenkään vanhemmilla koneilla.
Sitten vielä kiinnostaa sekin, miten olet törmäystarkistuksen hoitanut? Onko sinulla toinen kuva, jossa merkkaat esimerkiksi mustalla pikselit, joihin ukko ei saa mennä? Jos näin, joudut ilmeisesti liikuttamaan sitäkin, kun ukko juoksee eteenpäin, mikä myös syö muistia tai sitten selaat koordinaatteja kuvassa. Jokatapauksessa kuva on ladattava muistiin. Tilepohjaisessa kartassa on sekin hyvä puoli, että törmäyksen tarkistaminen on myös melko helppoa. Mikä on syy tilevastaisuuteen, vai onko koodin porttaamisessa tilejä tukevaksi liian suuri homma?
Voit myös tietysti piirtovaiheessa määrittää alueen joka kuvasta piirretään siten, että pelaajan näkymän ulkopuolelle ei jää mitään ylimääräistä.
int sijainti, sijaintiy; sijaintix++; sijaintiy++; SDL_Rect rect; rect.w = sijaintix + 640; // pelaajan näkymän leveys rect.h = sijaintiy + 480; // pelaajan näkymän korkeus // piirrä
Ethän vain lataa kuvaa aina uudestaan framen alussa? :] Ja mitä tarkoitit tuolla kuvan optimoinnilla, miten se tapahtuu/mitä se tekee?
^Mmm, SDL:n piirtofunkkarit tekee ton leikkelyn ihan ite.
Mobel kirjoitti:
Vai sisältääkö pelisi niin paljon erilaisia kohteita taustalla, että homma olisi ylivoimainen tileillä hoidettavaksi?
Oikeastaan asia on juuri noin, eli taustalla on niin paljon grafiikkaa, että tile-pohjainen kenttätoteutus on poissa vaihtoehdoista.
Mobel kirjoitti:
En tosiaankaan ole itse ikinä kokeillut tehdä ns. art-based -peliä, mutta olisiko mahdollista, jos lataat kuvan muistiin pienempinä paloina. Vaikkapa 1000 pikselin pätkissä ja kun ensimmäisen palan loppu alkaa lähestyä ladataan seuraava muistiin ja piirretään näytölle. Tosin tästä ei tile-toteutuskaan enää olisi kaukana.
Tuo on hyvä idea ja kuulostaakin siltä, että se voisi toimia. Täytyy kokeilla tuota tekniikkaa.
Mobel kirjoitti:
Sitten vielä kiinnostaa sekin, miten olet törmäystarkistuksen hoitanut? Onko sinulla toinen kuva, jossa merkkaat esimerkiksi mustalla pikselit, joihin ukko ei saa mennä?
Oikeastaan täytyy tässä vaiheessa myöntää, että törmäystarkistuspuoli on vasta puoliksi suunniteltu, mutta ajattelin, että jokaisen vihollis-spriten liikkeen mukana kulkee x-arvo koodissa, johon osuessa pelaaja menettää energiaa. Jotain tuollaista, mutta se on vielä mietinnän alla.
Model kirjoitti:
Mikä on syy tilevastaisuuteen, vai onko koodin porttaamisessa tilejä tukevaksi liian suuri homma?
Jos tile-tyyliä joudun lopulta käyttämään - miten sen sitten ikinä hoidankaan - niin ei homma ainakaan koodaamisen suuruuteen kaadu.
matpit kirjoitti:
Ethän vain lataa kuvaa aina uudestaan framen alussa? :]
Nyt tuli kyllä tenkkapoo. Asia taitaa muuten olla noin, koska kuvanlatausfunktio vapauttaa kuvan sen jälkeen, kun se on ladattu. Erittäin hyvä kysymys. Täytyypä huomenna tutkiskella tuota. Kiitos.
matpit kirjoitti:
Ja mitä tarkoitit tuolla kuvan optimoinnilla, miten se tapahtuu/mitä se tekee?
Tuolla optimoinnilla optimoidaan kuva näytölle sopivaksi eli esim. 16-bittisten värien mukaiseksi. ImageLoad-funktio on tässä:
SDL_Surface *ImageLoad(char *tiedostonimi) { SDL_Surface *ladattukuva, *optimoitukuva; ladattukuva = SDL_LoadBMP(tiedostonimi); optimoitukuva = SDL_DisplayFormat(ladattukuva); SDL_FreeSurface(ladattukuva); return optimoitukuva; }
Kuvahan pitäisi ladata muistiin (ImageLoad) ohjelman alussa, ja poistaa muistista (SDL_FreeSurface) ohjelman lopussa kun sitä ei yleensä enään tarvita. Luulisin, että tuo ImageLoad syö tuplamäärän muistia, ja kuvan koosta, ja koneen muistin määrästä riippuen myös viedä kriittisesti muistia. Toisaalta tuo on vain tilapäinen tila koska se poistaa kuvan (SDL_FreeSurface) heti muistista. Asian voisi tehdä myös näin käyttäen yhtä muuttujaa:
SDL_Surface *ImageLoad(char *tiedostonimi) return SDL_DisplayFormat(SDL_LoadBMP(tiedostonimi));
Jäi kaksi muuttujaa pois kokonaan. Viisaammat voivat sitten taas korjailla. :]
@Sera:
Sen sijaan, että muutat grafiikkasi tile-systeemiksi, voit myös pilkkoa ison kuvan pienemmiksi. En kyllä tiedä, auttaisiko se tähän ongelmaan.
Lisäksi SDL-postilistan arkistoista voi löytää samanlaisia kysymyksiä. Ehkä tässä säikeessä on jotain ideaa sinullekin:
http://listas.apesol.org/pipermail/sdl-libsdl.org/2003-September/037660.html
klikkaa Messages sorted by thread, niin voit lukea vastaukset.
matpit, auheutit juuri ohjelmaan muistivuodon. Tuo alkuperäinen ImageLoad sen sijaan toimii täsmälleen oikein. Senkin palauttama kuva pitää tosin muistaa vapauttaa ohjelman lopussa. Eli jottei nyt jäisi väärinkäsityksiä, niin homman pitää toimia tuolla alkuperäisellä ImageLoad-funktiolla ja näyttää suunnilleen tältä:
tausta = ImageLoad("..."); ukko = ImageLoad("..."); while (pelataan) { // Silmukka, piirtämiset sun muut } // Game over SDL_FreeSurface(tausta); SDL_FreeSurface(ukko);
En usko, että noilla muillakaan ehdotetuilla optimoinneilla on ratkaisevaa merkitystä nopeudessa. Ennemmin hidastavat vain ylimääräisillä laskuilla. Kuvan koon voi tarkistaa bitmapiksi muunnetusta kuvatiedostosta, ja jos se mahtuu hyvin muistiin, niin mitään ongelmia ei pitäisi olla. Tuollainen kuva vie pahimmillaan 11 megaa, mikä ei suinkaan ole paljon nykykoneille. SDL:lle voisi vihjata potentiaalisesta laitteistokiihdytyksestä näytön alustuksessa lipulla SDL_HWSURFACE, mutta tuo ei luultavasti vaikuta mihinkään paitsi ehkä Windowsissa.
Minulla kyllä SDL:lla toteutettu matopeli toimii 333 MHz koneella ihan siedettävällä nopeudella (22 FPS). Tässäkin tausta piirretään joka kerta uudestaan optimoidulta taustapinnalta ruudulle, kokona on 640x480. Muuta piirrettävää on tosin hyvin vähän. Mitään muuta kikkoja en ole käyttänyt kuin näytön asetuksissa kaksoispuskurointia ja taustan tapauksessa tuota SDL_DisplayFormat-funktiota. Muissa piirrettävissä osissa on jopa alfakanava mukana, joten piirto ei tosiaan mene ihan suoralla kopioinnilla vain. Alfakanavan lisääminen taustaankin hidastaa ohjelman 17 kuvaan sekunnissa. Pöytäkoneella nopeus onkin jo noin kymmenkertainen. Taustakuvan venyttäminen leveäksi ei vaikuttanut nopeuteen lainkaan, kuten oli odotettavissakin.
Tarinan tarkoituksena oli todeta, että on aika vaikea tuosta noin vain osoittaa, missä kohti menee pieleen, kun kuvaukseltaan jokseenkin vastaavanlainen ratkaisu toimii kuitenkin aivan hyvin. Voisit kuitenkin kokeilla kääntämistä optimoinnin kanssa (-O2) ja profiloida ohjelman, että näet, missä aika oikeasti kuluu.
Aihe on jo aika vanha, joten et voi enää vastata siihen.