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. }
Hieno koodi!
Olin itsekin koodaamassa tulta vb:lle.
Hitauden kanssa tosin tuli ongelmia.
onkos niitä muunkinlaisia tuliakin kuin palava vai? :P
Jos nyt pilkkua viilataan niin miten tuli voi palaa?
Löytyiskö exeä?
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.
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ä.
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...
Hemmetin tyylikäs efekti.
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.
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
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ä.
Hieno esimerkki ja hyvin kommentoitu kirjoitusvirheistä huolimatta.
hyvältä näyttää
Tuonne väliin vois heittää SDL_Delay(1):n, tuntuu varsin nopealta omalla koneella, muuten kyllä helvetin hieno.
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.
Hieno.
kpzpt: gcclle pitää antaa parametri -lSDL.