Kirjautuminen

Haku

Tehtävät

Koodit: C++: Palava tuli SDL:llä

Kirjoittaja: tn

Kirjoitettu: 26.05.2004 – 26.05.2004

Tagit: grafiikka, koodi näytille, vinkki

Perinteinen tuli C++ :lla SDL-grafiikkakirjastoa käyttäen. En ole muuten ikinä kommentoinut mitään koodia puoliksikaan noin hyvin... ;)

#include <SDL/SDL.h>
#include <cstdlib>      // Tarvitaan satunnailukugeneraattoria.
#include <ctime>        // Satunnaslukugeneraattori täytyy myös alustaa satunnaisesti.


// näytön resoluutio
const int RES_X = 640;
const int RES_Y = 480;

// tuli-ikkunan leveys ja korkeus
const int LEVEYS = 200;
const int KORKEUS = 300;

const int VAHENNYS = 5;     // Tulen "lämpötilasta" vähennetään tämä arvo joka kierroksella.
                            // Mitä suurempi arvo on, sitä matalampi on tuli.

// Tulen eri kohtien "lämpötilat" tallennetaan taulukkoon. Reunoille jätetään rivi tyhjää,
// ja alapulelle kaksi riviä hiillokselle.
int tuli[LEVEYS+2][KORKEUS+2];

unsigned int vari[512][3];      // talukko, johon tallennetaan väriarvot "kuumuuden" funktiona
                                // Ensimmäinen arvo on kuumuus, toisella valitaan punainen,
                                // vihreä tai sininen (0=R, 1=G, 2=B).
                                // vari[10][2] sisältää siis 10-lämpötilaisen tulen sinisen
                                // osavärin arvon.


// Funktio arpoo uuden rivin "lämpötiloja", eräänlaisen hiilloksen, tulen alapuolelle, mistä
// ne sitten kohoavat ylöspäin.
void ArvoHiillos()
{
    for( int x=1; x<=LEVEYS; ++x )
    {
        tuli[x][KORKEUS] = tuli[x][KORKEUS+1];      // Nostetaan aiempi alempi hiillos ylemmäs.
        tuli[x][KORKEUS+1] = rand()%(256+128+64)+64;    // Arvotaan uusi alempi hiillos.
    }                                                   // Lämpöarvot arvotaan välille 64-511.
}


// Funktion päivittään nimensä mukaisesti tulen.
void PaivitaTuli()
{

    // Siirretään tulta ylöspäin ja pehmennetään sitä samalla laskemalla uudet lämpötilat
    // parin alapuolla (myös viistosti) olevan lämpötilan keskiarvona. Lisäksi lasketaan lämpötilaa
    // vähentämälla siitä vakio VAHENNYS laskun yhteydessä. Reunojen ylimääräisiä pikselirivejä
    // tarvitaan pehmennyksessä.
    for( int y=0; y<KORKEUS; ++y )
        for( int x=1; x<=LEVEYS; ++x )
        {
            tuli[x][y] = (tuli[x][y+1] + tuli[x+1][y+1] + tuli[x-1][y+1] +
                    tuli[x][y+2] - VAHENNYS) / 4;
            if( tuli[x][y] < 0 )   // Jos lämpötila pääsee vuotamaan alle nollan, palautetaan se.
                tuli[x][y] = 0;
        }
}

// Funktion tarkoitus lienee päivänselvä.
void PiirraRuutu(SDL_Surface *surface)
{
    if( SDL_MUSTLOCK(surface) )                 // Lukitaan ruutu, jos tarpeellista.
        SDL_LockSurface(surface);
    int xAlku = (RES_X-LEVEYS)/2 - 1;           // tuli-ikkunan vasemman yläkulman x-koordinaatti
    int yAlku = (RES_Y-KORKEUS)/2 - 1;          // ...ja y-koordinaatti
    int bpp = surface->format->BytesPerPixel;   // tavujen määrä pikseliä kohden
    int leveys = surface->w;                    // kuvaruudun leveys pikseleinä
    Uint8* buffer = (Uint8*) surface->pixels;   // näyttöpuskuri, jonne kuva sijoitetaan
    Uint8* buf;                                 // osoitin piirrettävään väriarvoon

    // Piirretään tuli näytölle. Tekee saman kuin seuraava koodi:
    //      for( int y=0; y<KORKEUS; ++Y )
    //          for( int x=1; x<=LEVEYS; ++x )
    //              PiirraPikseli(x, y, vari[tuli[x][y]][0], vari[tuli[x][y]][1],
    //                      vari[tuli[x][y]][2]);
    // ,missä PiirraPikseli(x, y, r, g, b), piirtää kohtaan (x,y) kyseisen RGB-värin.
    for( int y=0; y<KORKEUS; ++y )                          // Silmukka ylhäältä alas
    {
        buf = buffer + (((y+yAlku)*leveys)+xAlku)*bpp - 1;  // Siirrytään näytöllä tuli-ikkunan
                                                            // vasempaan laitaan.
        for( int x=1; x<=LEVEYS; ++x, ++buf )               // Silmukka vasemmalta oikealle
        {                                                   // ( "++buf" hyppää alfa-arvon yli)
            #if SDL_BYTEORDER == SDL_LIL_ENDIAN
                *(++buf) = vari[tuli[x][y]][2];     // Haetaan tulen lämpöarvon avulla sininen, ...
                *(++buf) = vari[tuli[x][y]][1];     // ... vihreä, ...
                *(++buf) = vari[tuli[x][y]][0];     // ... ja punainen ...
            #else                                   // (tai jos kone hauluaa ne toisinpäin ...
                *(++buf) = vari[tuli[x][y]][0];     // ... punainen ...
                *(++buf) = vari[tuli[x][y]][1];     // ... vihreä, ...
                *(++buf) = vari[tuli[x][y]][2];     // ... ja sininen) väriarvo taulukosta, ja
            #endif                                  // siirretään ne näyttöpuskuriin.
        }
    }
    if( SDL_MUSTLOCK(surface) )                 // Avataan lukittu ruutu.
        SDL_UnlockSurface(surface);
    SDL_Flip(surface);                          // Rojautetaan kuva näkyviin.
}


// Pääohjelma alkaa.
int main(int argc, char *argv[])
{
    // Aluksi alustetaan SDL ja asetetaan sopiva näyttötila kaksoispuskuroinnilla.
    if( SDL_Init(SDL_INIT_VIDEO) < 0 )
    {
        printf("Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }
    atexit(SDL_Quit);
    SDL_Surface *screen;
    screen = SDL_SetVideoMode(RES_X, RES_Y, 32, SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN);
    if( screen == NULL )
    {
        printf("Unable to set 640x480 video: %s\n", SDL_GetError());
        exit(1);
    }
    // SDL ja näyttötila alustettu

    srand(static_cast<unsigned>(time(0)));      // alustetaan satunnaislukugeneraattori

    // Tuli-ikkuna tyhjennetään aluksi (lämpötilat nollataan).
    for( int y=0; y<KORKEUS+2; ++y )
        for( int x=0; x<LEVEYS+2; ++x )
            tuli[x][y] = 0;

    // Lasketaan sopivat RGB-väriarvot eri lämpötiloille. Hyvät arvot löytyvä miettimällä ja
    // kokeilemalla.
    for( unsigned int i=0; i<128; ++i )     // viilein on harmaata savua
    {
        vari[i][0] = i*3/4;     // punainen
        vari[i][1] = i*3/4;     // vihreä
        vari[i][2] = i*3/4;     // sininen
    }
    for( unsigned int i=0; i<64; ++i )      // kuumetessa harmaa liukuu punertavaksi
    {
        vari[i+128][0] = 96+i/2;
        vari[i+128][1] = 96-i/2;//128-i;
        vari[i+128][2] = 96-i/2;//128-i;

        vari[i+192][0] = 128+i*4;           // punertava muuttuu keltaiseksi
        if( vari[i+192][0] > 255 )
            vari[i+192][0] = 255;
        vari[i+192][1] = 64+i*3;
        vari[i+192][2] = 63-i;
    }
    for( unsigned int i=0; i<256; ++i )     // kuumin tuli on lähes valkoista
    {
        vari[i+256][0] = 255;
        vari[i+256][1] = 255-i/4;
        vari[i+256][2] = i;
    }
    // Väriarvojen laskenta loppuu.

    SDL_ShowCursor(0);  // Piilotetaan hiiri. (mukavampi kun ei heilu tiellä)

    // Pääsilmukka
    bool valmis = false;
    while( !valmis )
    {
        // Tarkastetaan pitääkö ohjelma lopettaa.
        SDL_Event event;
        while( SDL_PollEvent(&event) )
        {
            if( event.type == SDL_QUIT )
                valmis = true;
            if( event.type == SDL_KEYDOWN )
                if( event.key.keysym.sym == SDLK_ESCAPE )
                    valmis = true;
        }

        // Päivitetään tuli ja piirretään se näytölle.
        ArvoHiillos();
        PaivitaTuli();
        PiirraRuutu(screen);
    }
    return EXIT_SUCCESS;    // Lopetetaan ohjelma oikeaoppisesti.
}

Kommentit

peki [27.05.2004 15:07:39]

#

Hieno koodi!
Olin itsekin koodaamassa tulta vb:lle.
Hitauden kanssa tosin tuli ongelmia.

Gwaur [27.05.2004 15:09:22]

#

onkos niitä muunkinlaisia tuliakin kuin palava vai? :P

kaviaari [27.05.2004 15:33:08]

#

Jos nyt pilkkua viilataan niin miten tuli voi palaa?

Linkku [27.05.2004 19:21:26]

#

Löytyiskö exeä?

tn [31.05.2004 22:25:15]

#

No ehkäpä vaikka "liekehtivä tuli" olisi ollut parempi nimi, mutta siitä voisi saivarrella varmaankin vaikka kuinka pitkään. Exeä ei valitettavasti ole julkisesti saatavilla.

Koipio-ohjelma [06.07.2004 14:15:35]

#

periatteessa tuli voi palaa koska tuli on eri atomeja (pääasiassa happi ja hiili) suuressa (no suuri ja suuri) lämpötilassa, mikä saa atomin elektronit virittäytymään ja sen jälkeen vapauttamaan fotonin joka taas on valoa.siis liekit ovat vain atomeja jotka vapauttavat fotoneja eli valoa joten liekit ovat ainetta joka palaa ja liekit ovat osa tulta eli tuli palaa.lämpö saadaan kun tulitikun päässä olevaan rikkiin saadaan lämpöä kitkasta joka saadaan hankaamalla tulitikun rikki osaa askin raapaisu pintaan jolloin rikki syttyy ja luovuttaa lämpöä hapen kanssa yhdistyessään.riittävässä lämmössä hiili ja happi yhdistyvät (hiili siksi koska sitä on kaikessa elollisessa) kemiallisessa reaktiossa jota kutsutaan palamiseksi.

tais tulla liikaa tietoa tuohon...
aika hyvin 8.luokkalaiselta.

korjatkaa jos oon väärässä tuossa selityksessä.

Fisher [03.10.2004 16:12:00]

#

Siis tuli on tavallaan palavaa ilmaa? Mutta miten se ei sytytä muuta ympärillä olevaa? Vai onko se vain että lämpötila on siellä pienempi...

Deewiant [08.10.2004 21:14:50]

#

Hemmetin tyylikäs efekti.

Koipio-ohjelma [19.10.2004 20:02:17]

#

Joo ilma on viileempää muualla... Liekki ei ole tarpeeksi voimakas kuumentaakseen kaikkea ilmaa ympärillään.
Ja palamiseen tarvitaan myös aine joka yhdistyy hapen kanssa, jolloin liekin ympärillä on muita yhdisteitä jotka estävät syttymisen (esim. CO2(hiilidioksidi, 2 pitäs olla pienempi)).

Ja jos totta puhutaan niin tuo oli lähinnä asioita joita kehittelin ja yritin kirjoittaa mahollisimman pitkästi tai kehitellä siihen jotain... No en uskonutkaan olevani oikeassa.

Koipio-ohjelma [19.10.2004 20:08:29]

#

Muuten tn voisi opetella kirjoittamaan satunnais oikein:

lainaus:

... // Tarvitaan satunnailukugeneraattoria. ...
...// Satunnaslukugeneraattori täytyy myös alustaa satunnaisesti. ...

No olihan se siellä oikein kirjoitettuna kerran! :D

moptim [03.07.2006 20:45:59]

#

lainaus:

lämpö saadaan kun tulitikun päässä olevaan rikkiin saadaan lämpöä kitkasta joka saadaan hankaamalla tulitikun rikki osaa askin raapaisu pintaan jolloin rikki syttyy ja luovuttaa lämpöä hapen kanssa yhdistyessään.

Viilataanpas vielä vähän pilkkua (äsken se oli aika karkea): Nykyään tulitikuissa ei ole rikkiä.

olympos [01.10.2006 16:28:20]

#

Hieno esimerkki ja hyvin kommentoitu kirjoitusvirheistä huolimatta.

Dain [30.07.2007 16:43:29]

#

hyvältä näyttää

Claw [28.01.2008 01:57:17]

#

Tuonne väliin vois heittää SDL_Delay(1):n, tuntuu varsin nopealta omalla koneella, muuten kyllä helvetin hieno.

kpzpt [01.06.2008 06:56:30]

#

Seuraavaa vääntää..
Ubuntu8.04 g++ NetBeans 6.01..

Running "/usr/bin/make  -f Makefile CONF=Debug" in /home/jtapio/NetBeansProjects/Application_4

/usr/bin/make -f nbproject/Makefile-Debug.mk SUBPROJECTS= .build-conf
make[1]: Entering directory `/home/jtapio/NetBeansProjects/Application_4'
mkdir -p dist/Debug/GNU-Linux-x86
g++     -o dist/Debug/GNU-Linux-x86/application_4 build/Debug/GNU-Linux-x86/newmain.o
build/Debug/GNU-Linux-x86/newmain.o: In function `PiirraRuutu(SDL_Surface*)':
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:62: undefined reference to `SDL_LockSurface'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:94: undefined reference to `SDL_UnlockSurface'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:95: undefined reference to `SDL_Flip'
build/Debug/GNU-Linux-x86/newmain.o: In function `main':
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:103: undefined reference to `SDL_Init'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:105: undefined reference to `SDL_GetError'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:108: undefined reference to `SDL_Quit'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:110: undefined reference to `SDL_SetVideoMode'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:113: undefined reference to `SDL_GetError'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:153: undefined reference to `SDL_ShowCursor'
/home/jtapio/NetBeansProjects/Application_4/newmain.cc:161: undefined reference to `SDL_PollEvent'
collect2: ld returned 1 exit status
make[1]: *** [dist/Debug/GNU-Linux-x86/application_4] Error 1
make[1]: Leaving directory `/home/jtapio/NetBeansProjects/Application_4'
make: *** [.build-impl] Error 2

Build failed. Exit value 2.

Dude [20.07.2008 22:14:40]

#

Hieno.
kpzpt: gcclle pitää antaa parametri -lSDL.

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta