SuomiGameHUB

Maailma tarvitsee pelejä

C++/SDL2 ja kuvien näyttämiseen

Pelimoottorin kehittämisessä on tärkeää ymmärtää ruudun päivityksen ja grafiikan käsittelyn periaatteet. Tämän ymmärtämiseksi käymme läpi, miten peliruudun päivittäminen ja grafiikan piirtäminen, eli “blittaaminen”, toimivat käytännössä. Peliruudun visuaalisen ilmeen ajantasaisuus on avainasemassa miellyttävän pelikokemuksen luomisessa. Tästä syystä on tärkeää, että peliruutu päivitetään säännöllisesti (esimerkiksi 60 kertaa sekunnissa), jotta pelissä tapahtuvat muutokset heijastuvat välittömästi pelaajan näkemään kuvaan.

Peliruudun päivittäminen jokaisella pelisilmukan iteraatiolla varmistaa, että kaikki pelin elementit, kuten hahmot ja objektit, päivittyvät oikein. Ilman säännöllistä päivitystä, muutokset pelin tilassa eivät näy visuaalisesti. Pelaajan liikuttaessa hahmoa tai tapahtuessa muita pelimekaniikkaan vaikuttavia toimintoja, pelin graafinen representaatio on päivitettävä vastaamaan näitä muutoksia reaaliaikaisesti. Tämä saavutetaan päivittämällä screenSurfacejokaisen pelisilmukan aikana, mikä mahdollistaa sujuvan ja dynaamisen pelikokemuksen.

“Blittaaminen” on prosessi, jossa grafiikka siirretään muistista näytölle. Blittaaminen mahdollistaa tehokkaan grafiikan käsittelyn, sillä se sallii pelinkehittäjän päivittää vain tarvittavat osat peliruudusta, sen sijaan että koko ruutu piirrettäisiin uudelleen jokaisella iteraatiolla. Käytännössä tämä tarkoittaa, että pelinkehittäjä voi piirtää pelielementit, kuten hahmot ja taustat, ensin off-screen -puskuriin, joka on välimuistialue. Kun kaikki elementit on piirretty, koko kuva “blitataan” kerralla näytölle. Tämä prosessi vähentää näkyvää pätkimistä ja tekee pelin grafiikasta sulavampaa.

SDL-kirjasto tarjoaa SDL_BlitSurface-funktion, joka on keskeinen työkalu blittaamisen toteuttamisessa. Tämän funktion avulla kehittäjä voi siirtää grafiikkaa yhdestä pinnasta toiseen, määritellen lähteen ja kohteen sekä niiden alueet.

Kehittäessämme peliä, voimme kohdata tilanteita, joissa olemme laittaneet grafiikkatiedostot väärään sijaintiin, mikä estää niiden oikeanlaisen lataamisen ja näyttämisen pelissä. Kuitenkin, haluaisimme, että ohjelma löytää grafiikat samasta tiedostossa, missä exe-tiedosto on. Esimerkiksi, jos käytössä on Windows-käyttöjärjestelmä, voimme hyödyntää windows.h-kirjaston tarjoamia toimintoja saadaksemme selville suoritettavan tiedoston (exe) sijainnin, jolloin voimme varmistaa, että grafiikkatiedostot ovat oikeassa paikassa suhteessa suoritettavaan tiedostoon.

Windowsin vakio MAX_PATH on asetettu arvon 260, joka pohjautuu Windows-käyttöjärjestelmän tiedostopolun enimmäispituuteen, tarjoten kehittäjille selkeän rajan, jonka puitteissa toimia. Tämä raja on tärkeä, sillä se varmistaa, että polkujen käsittely ei ylitä käyttöjärjestelmän asettamia rajoituksia, mikä voisi johtaa virhetilanteisiin tai jopa ohjelman kaatumiseen.

Seuraavaksi otamme käyttöön funktion GetModuleFileName, jonka tehtävänä on hakea ajossa olevan sovelluksen suoritettavan tiedoston polku. Tämä funktio mahdollistaa ohjelmistokehittäjille pääsyn sijaintiin, josta ohjelma on käynnistetty. Tämän tiedon avulla voidaan muodostaa suhteellisia polkuja muihin tarvittaviin tiedostoihin, mikä on erityisen hyödyllistä monimutkaisemmissa sovelluksissa, jotka saattavat sisältää suuren määrän resursseja.

Kun suoritettavan tiedoston polku on saatu, seuraava askel on muuntaa tämä polku merkkijono-objektiksi (string), jota voidaan käsitellä helpommin. Tämä muunnos mahdollistaa merkkijonon käsittelyn standardien ohjelmointikielten tarjoamilla työkaluilla, kuten alamerkkijonon etsiminen tai korvaaminen.

Yksi tyypillinen toimenpide on ohjelma.exe-tiedostonimen poistaminen ja korvaaminen toisenlaisella nimellä, esimerkiksi kuvatiedostolla. Tämä saavutetaan etsimällä viimeisen kenoviivan sijainti merkkijonossa ja leikkaamalla polku tähän kohtaan, jotta voidaan liittää uusi tiedostonimi. Tämä prosessi on yksinkertainen, mutta se osoittaa ohjelmistokehityksen joustavuuden ja ohjelmoijien kyvyn mukautua erilaisiin tarpeisiin dynaamisesti.

Lopuksi, kun uusi tiedostonimi on lisätty polkuun, se muunnetaan takaisin muotoon, jota käyttöjärjestelmä ja sovellus voivat käyttää. Tämä esimerkki kuvastaa laajemmin ohjelmistokehityksen haasteita ja ratkaisuja, joita kehittäjät kohtaavat työssään. Eri käyttöjärjestelmillä on omat erityispiirteensä ja rajoituksensa, jotka vaativat erilaisia lähestymistapoja. Windowsissa käytetty menetelmä voi olla erilainen kuin Linuxissa tai macOS:ssä.

Tämä esimerkki osoittaa, kuinka yksinkertaiselta vaikuttava tehtävä, kuten tiedostopolun määrittäminen ja muokkaaminen, voi sisältää useita vaiheita ja vaatia huolellista suunnittelua. Se kuvastaa ohjelmistokehityksen prosessin luovaa luonnetta, jossa kehittäjien on ymmärrettävä sekä ohjelmointikielten tarjoamat työkalut että käyttöjärjestelmien asettamat rajoitukset. Kehittyessään ja kohdatessaan uusia haasteita ohjelmoijat oppivat soveltamaan tietämystään monipuolisesti, mikä edistää heidän kykyään tuottaa toimivia ohjelmistoratkaisuja.

#include <SDL.h>
#include <SDL_image.h>
#include <string>

int main(int argc, char* argv[])
{
  SDL_Init(SDL_INIT_VIDEO);
  SDL_Window* window = NULL;
  SDL_Surface* screenSurface = NULL;
  SDL_Surface* kuva = NULL;
  SDL_Surface* o_kuva = NULL;
  window = SDL_CreateWindow("SGH SDL Esimerkki", 50, 50, 1280, 720, SDL_WINDOW_SHOWN);

  int imgFlags = IMG_INIT_PNG;
  IMG_Init(imgFlags);

  screenSurface = SDL_GetWindowSurface(window);
  SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));


  char path[MAX_PATH];
  GetModuleFileNameA(NULL, path, MAX_PATH);
  std::string exePath(path);
  std::string dirPath = exePath.substr(0, exePath.find_last_of("\\/"));

  std::string kuva_osoite = dirPath + "\\kuva.png";

  kuva = IMG_Load(kuva_osoite.c_str());
  o_kuva = SDL_ConvertSurface(kuva, screenSurface->format, 0);

  SDL_Event e;
  bool quit = false;

  while (quit == false)
  {
    while (SDL_PollEvent(&e))
    {
      if (e.type == SDL_QUIT) quit = true;
    }
    
    SDL_BlitSurface(o_kuva, NULL, screenSurface, &kuvaRect);
    SDL_UpdateWindowSurface(window);
  }

  SDL_FreeSurface(kuva);
  SDL_FreeSurface(screenSurface);
  SDL_DestroyWindow(window);
  SDL_Quit();

  return 0;
}

Edellinen osa: C++/SDL2-pelimoottorin valmistaminen kuvien näyttämiseen

Keskustelu

Aloita uusi keskustelu