Hylkäsin SDL:n ja otin käyttöön SFML:n, kun sitä on niin paljon kehuttu. Latasin paketin, asensin sen MinGW:hen, mutta koodi ei toimi. Kääntäjä antaa ensin virheen:
C:\>gcc sfml.c -o sfml.exe -lcsfml-graphics -lcsfml-window -lcsfml-system Info: resolving _sfBlack by linking to __imp__sfBlack (auto-import) c:/ohjelmointi/mingw/bin/../lib/gcc/mingw32/4.5.0/../../../../mingw32/bin/ ld.exe: warning: auto-importing has been activated without --enable-auto-import specified on the command line. This should work unless it involves constant data structures referencing symbols from auto-imported DLLs.
mutta, kun -enable-auto-import-vivun antaa gcc:lle kääntäessä, onnistuu kääntäminen virheettä. (mihin tuota auto importia tarvitsee ja mitä se tekee?)
Ohjelma ei kuitenkaan lähde kääntämisen jälkeen käyntiin. Se ilmestyy tehtävienhallintaan sfml.exenä, mutta ei reagoi eikä tee, mitä koodin mukaan pitäisi tapahtua. Koodi on napattu suoraan SFML:n doc-tiedoston etusivulta. Otin vain audio- ja font-pätkät pois.
#include <stdio.h> #include <SFML/Graphics.h> int main() { sfWindowSettings Settings = {24, 8, 0}; sfVideoMode Mode = {800, 600, 32}; sfRenderWindow* App; sfImage* Image; sfSprite* Sprite; sfEvent Event; /* Create the main window */ App = sfRenderWindow_Create(Mode, "SFML window", sfResize | sfClose, Settings); if (!App) return EXIT_FAILURE; /* Load a sprite to display */ Image = sfImage_CreateFromFile("cute_image.jpg"); if (!Image) return EXIT_FAILURE; Sprite = sfSprite_Create(); sfSprite_SetImage(Sprite, Image); /* Start the game loop */ while (sfRenderWindow_IsOpened(App)) { /* Process events */ while (sfRenderWindow_GetEvent(App, &Event)) { /* Close window : exit */ if (Event.Type == sfEvtClosed) sfRenderWindow_Close(App); } /* Clear the screen */ sfRenderWindow_Clear(App, sfBlack); /* Draw the sprite */ sfRenderWindow_DrawSprite(App, Sprite); /* Update the window */ sfRenderWindow_Display(App); } /* Cleanup resources */ sfSprite_Destroy(Sprite); sfImage_Destroy(Image); sfRenderWindow_Destroy(App); return EXIT_SUCCESS; }
Katso debuggerilla tai printtailemalla, mihin asti ohjelmassa päästään. Onko kuva paikallaan? Jotenkin kuvittelisin, että C:ssä tuo ikkuna pitäisi osata tuhota virhetilanteessakin itse.
Kyllä suosittelen kovasti, että vaihdat C:n modernimpaan C++:aan. Ei varmaan tuotakaan ongelmaa olisi.
Noh, nyt tosiaan voisi olla hyvä aika perehtyä C++:aan. Latasinkin siis C++-version SFML:stä ja asensin sen sijoittamalla include-kansioon headerit, lib-kansioon .a-tiedostot (miksikäs näitä kutsutaan?) ja dll:t biniin. Menin sfml-dev.orgin tutorials-kohtaan ja valitsin sieltä displaying a sprite -otsikon, jonka takaa löytyi allaoleva koodi.
#include <iostream> #include <SFML/Graphics.hpp> int main() { // Create the main rendering window sf::RenderWindow App(sf::VideoMode(800, 600, 32), "SFML Graphics"); // Load the sprite image from a file sf::Image Image; if (!Image.LoadFromFile("image.png")) return EXIT_FAILURE; // Create the sprite sf::Sprite Sprite(Image); // Change its properties Sprite.SetColor(sf::Color(0, 255, 255, 128)); Sprite.SetPosition(200.f, 100.f); Sprite.SetScale(2.f, 2.f); // Start game loop while (App.IsOpened()) { // Process events sf::Event Event; while (App.GetEvent(Event)) { // Close window : exit if (Event.Type == sf::Event::Closed) App.Close(); } // Get elapsed time float ElapsedTime = App.GetFrameTime(); /* Poistin keskustelun kannalta tarpeetonta näppäinkäsittelykoodia tästä */ // Clear screen App.Clear(); // Display sprite in our window App.Draw(Sprite); // Display window contents on screen App.Display(); } return EXIT_SUCCESS; }
Täysin sama ongelma kuin C-version kanssa. sfml.exe ilmestyy tehtävienhallintaan, mutta mitään muuta ei tapahdu. Ei virheitä, ei tulosteita, ei mitään. Kokeilin debugata ohjelmaa sijoittamalla tulostuksia eri kohtiin koodia, mutta täysin turhaan. Edes ne eivät tulostu.
Kääntö komentoriviltä:
g++ sfml.cpp -o sfml.exe -lsfml-graphics -lsfml-window -lsfml-system -enable-auto-import
Hieman jatkotutkimusta.
Kopioin seuraavan koodin sfml-dev.orgista ja se pelittää ongelmitta.
#include <SFML/System.hpp> #include <iostream> int main() { sf::Clock Clock; while (Clock.GetElapsedTime() < 5.f) { std::cout << Clock.GetElapsedTime() << std::endl; sf::Sleep(0.5f); } return 0; }
Eli kyseessä on ilmeisesti App-pohjan virhe?
Voisit edelleenkin katsoa debuggerilla, mihin kohti suoritus pääsee. Toki on mahdollista, että SFML ei syystä tai toisesta toimi koneellasi. Kannattaa siinä tapauksessa kokeilla myös keskeneräisen SFML 2:n kehitysversiota, jossa on korjattu ainakin eräs kauan kummitellut ATI-bugi.
Minulla ei ole kauheasti kokemusta ohjelmien debuggaamista erillisillä ohjelmilla, mutta pikaisen googletuksen jälkeen päädyin GNU Debuggerin (gdb) pariin, joka löytyi vielä kaiken lisäksi kätevästi MinGW-paketista.
Ajoin komentoriviltä gdb sfml.exe
ja run -v
.
Reading symbols from C:\ohjelmointi\harjoitukset/sfml.exe...done. (gdb) run -v Starting program: C:\ohjelmointi\harjoitukset/sfml.exe -v [New Thread 1992.0xf94] [New Thread 1992.0x8d8]
Ja tähän debuggaus pysähtyy. Se ei anna kaatumisilmoitusta tai mitään. Odottaa vain siinä, kunnes suljen ohjelman. Jos painan esim. ctrl+c tai ctrl+break, niin debugger rekisteröi ne uusilla threadeilla. Tarkoittaako tämä sitä, että koodin näppäinkäsittelyosa, jonka leikkasin ylläolevasta viestistäni pois, toimii aivan oikein? Eli ainoastaan ohjelmaikkuna ja kuva ovat rikki?
Kokeilen ladata version 2.0 ja kirjoitan myöhemmin, mitä sain aikaan.
EDIT:
Ai niin, kun lopulta suljen sfml.exen tehtävienhallinnasta, ilmoittaa debugger sen sulkeutuneen "with program code 01". Puhutaanko tässä main-funktion palautusarvosta, eli EXIT_FAILURE:sta?
Sinun pitäisi ensin kääntää ohjelma debug-asetuksilla (valitsin -g
) ja mielellään ilman mittavia optimointeja (enintään -O1
). Kun sitten pysäytät ohjelman ctrl+c:llä, komento backtrace (tai bt) kertoo, missä mennään. Aloita lukeminen lopusta. Tässä on erään tulosteen loppuosa:
(gdb) bt ... #6 0x00007ffff0a4a3a6 in _mesa_PopMatrix () from /usr/lib/libdricore.so #7 0x00007ffff7112f98 in sf::RenderTarget::Draw(sf::Drawable const&) () from /tmp/testi/ext/lib/libsfml-graphics.so.1.6 #8 0x0000000000427cbd in GUI::GameHandler::drawGame (this=0xd18d10, window=...) at src/gui/game/GameHandler.cpp:81 #9 0x0000000000428065 in GUI::GameHandler::draw (this=0xd18d10, window=...) at src/gui/game/GameHandler.cpp:170 #10 0x0000000000415c20 in GUI::main (argc=<optimized out>, argv=<optimized out>) at src/gui/main.cpp:77 #11 0x0000000000415e71 in main (argc=<optimized out>, argv=<optimized out>) at src/gui/main.cpp:42
Ok, tässä on nyt optimointikin käytössä, mutta joka tapauksessa tulosteesta näkyy, että src/gui/main.cpp:ssä rivillä 42 on kutsuttu GUI::main, josta on rivillä 77 kutsuttu GUI::GameHandler::draw jne. Sitten päädytään SFML:n funktioihin, joissa ei näy rivinumeroita, ja sieltä hypätään jo OpenGL-kirjaston puolelle eli peruskoodarin ulottumattomiin.
Pysäytyksen jälkeen komento continue (tai c) jatkaa suoritusta.
Kun tapat ohjelman tehtävienhallinnasta, luultavasti paluuarvo ei tule omasta koodistasi, vaan käyttöjärjestelmä sulkee ohjelman väkisin ja asettaa paluuarvoksi jonkin tavallisen virhekoodin. Jos ohjelmasi sulkeutuisi itsestään, asia olisi juuri noin.
EXIT_SUCCESS ja EXIT_FAILURE ovat aivan turhia, minusta on selvempää käyttää suoraan arvoja 0 ja 1 (tai tarvittaessa useampaa erilaista virhekoodia).
Ongelma tuossa menetelmässä on, ettei ohjelma kaadu ctrl+c:llä eikä millään muullakaan tavalla ilman tehtävienhallintaa. Käänsin ohjelman g-vivulla ja ajoin sen sekä gdb:n sisältä että komentoriviltä suoraan, mutta ctrl+c sekä ctrl+break ovat täysin pois käytöstä. Jos painan ctrl+c gdb:ssä, lisää se vain yhden threadin ja jatkaa looppaamista.
En saanut versiota 2.0 toimimaan, vaikka mielestäni toimin täysin sfml-dev.orgin Cmake-oppaan mukaisesti. Ehkä illemmalla yritän uudestaan.
Staattinen linkittäminen muistaakseni auttoi siihen ATI bugiin, joten sitä voisit kokeilla.
Mikä ongelma kakkosen kanssa oli? Jos saat sen toimimaan, niin kannattaa käyttää mielummin sitä. SFML:n kehittäjäkin on sanonut, että kakkonen on jo nyt valmiimpi kuin 1.6.
CMake ei generoinut tarvittavia tiedostoja. lib-kansiot jäivät tyhjäksi jne. Ainoastaan include-kansio sai täytettä, mutta sehän löytyy jo valmiista snapshotista.
Latasin siis SFML 2.0 snapshotin: http://sfml-dev.org/download.php
ja noudatin Compiling SFML with CMake -tutorialia http://sfml-dev.org/tutorials/2.0/compile-with-cmake.php
Itselläni toimi ihan moitteetta, kun äsken kokeilin. Tosin kokeilin Visual Studio 2010:llä.
Ilmoittiko CMake mitään virheitä vai menikö kaikki hyvin ja silti mitään ei ilmestynyt?
Sain CMaken toimimaan oikein eilen illalla, ulos pulpahti lib- ja dll-tiedostojakin. Mutta nyt koodi ei edes käänny. Tutorialin valmiskoodi antaa virheitä enkä osaa korjata niitä.
/include/SFML/Graphics/Sprite.hpp:63:14: note: candidates are: sf::Sprite::Sprite(const sf::Texture&) /include/SFML/Graphics/Sprite.hpp:55:5: note: sf::Sprite::Sprite() /include/SFML/Graphics/Sprite.hpp:46:1: note: sf::Sprite::Sprite(const sf::Sprite&) sfml.cpp:38:20: error: 'class sf::RenderWindow' has no member named 'GetEvent'
Tekee hieman mieli palata takaisin SDL:ään, mutta en luovuta vielä.
SFML 2.0:ssa osa funktioista on muuttunut. Katso mallikoodeja SFML 2.0:n dokumentaatiosta.
Vau, hienoa, tosiaan! Niinhän se olikin muuttunut. Lisäksi linkkeritiedostot piti vaihtaa.
Nyt esimerkkikoodi toimii, mutta latautuu oudon hitaasti. Ikkunan avaamiseen menee kolmisen sekuntia, mutta eipä siitä kauheasti haittaa ole harjoittelun kannalta. Kiitos avusta!
Aihe on jo aika vanha, joten et voi enää vastata siihen.