SuomiGameHUB

Maailma tarvitsee pelejä

Kontrollit C++/SDL2-pelimoottoriin

SDL-kirjasto tarjoaa rikkaan valikoiman työkaluja käyttöliittymän käsittelyyn, mukaan lukien käyttäjän syötteen käsittely. Ennen kuin voimme vastaanottaa ja käsitellä näppäimistön painalluksia, meidän on suoritettava alustavia asetuksia. Tämä sisältää ruudulle piirrettävän kuvan sijainnin määrittämisen. SDL:ssä kuvien piirtäminen tapahtuu “blittauksen” avulla, jossa kuvalle määritellään sijainti käyttämällä SDL_Rect-rakennetta, joka sisältää x- ja y-koordinaatit (kuvaajan sijainti ruudulla) sekä leveyden ja korkeuden. Esimerkiksi, jos haluamme piirtää kuvan ruudun vasempaan yläkulmaan, käyttäisimme koordinaatteja (0, 0). Muuttamalla näitä arvoja, voimme siirtää kuvaa haluamaamme sijaintiin ruudulla.

Kuvan liikuttaminen reaaliajassa vaatii syötteiden, kuten näppäimistön painallusten, käsittelyä. SDL:ssä tämä tapahtuu tapahtumajärjestelmän kautta, joka kuuntelee erilaisia syötteitä, kuten näppäimistöltä ja hiireltä tulevia tapahtumia. Ohjelmassa tapahtumien käsittely alkaa pääsilmukan sisällä, missä ohjelma tarkistaa jatkuvasti, onko eventtejä tapahtunut. Kun näppäimistön painallus havaitaan, se ilmoitetaan eventtinä, jota ohjelma voi sitten käsitellä.

Tämän tapahtuman käsittelyyn käytetään SDL_Event-rakennetta. Esimerkiksi, jos haluamme reagoida näppäimistön nuolinäppäinten painalluksiin, ohjelma tarkistaa tapahtumatyyppiä SDL_KEYDOWN, joka osoittaa, että näppäin on painettu alas. Tämän jälkeen voidaan käyttää switch-lauseketta erottamaan eri näppäinten painallukset toisistaan. Kukin case vastaa eri näppäintä, esimerkiksi SDLK_LEFT vasenta nuolinäppäintä (katso näppäinkoodit täältä). Tämän rakenteen avulla voidaan määrittää, mitä toimintoja suoritetaan, kun tietty näppäin on painettu.

On tärkeää lisätä break-lause jokaisen tapauksen loppuun, jotta estetään ohjelman jatkaminen seuraavaan tapaukseen, mikä voisi aiheuttaa odottamattomia toimintoja.

Tämä lähestymistapa mahdollistaa monimutkaisten käyttöliittymien ja pelimekaniikkojen toteuttamisen. Esimerkiksi, hahmon liikuttaminen ruudulla vasemmalle, kun vasenta nuolinäppäintä painetaan, voidaan toteuttaa päivittämällä hahmon x-koordinaattia pienemmäksi, ja oikealle liikkuminen päivittämällä x-koordinaattia isommaksi. Ylös ja alas liike puolestaan tapahtuu päivittämällä y-koordinaattia.

Kun hahmo liikkuu ruudulla, saatat huomata, että se jättää jälkeensä “vanhat” kuvansa, luoden epätoivotun jälkikuvan efektin. Tämä johtuu siitä, että ruutua ei tyhjennetä ennen uuden kuvan piirtämistä. Voit ratkaista tämän ongelman tyhjentämällä ruudun jokaisen päivityksen yhteydessä, esimerkiksi täyttämällä koko ruudun valkoisella värillä ennen hahmon uuden sijainnin piirtämistä. Tämä varmistaa, että vain hahmon nykyinen kuva näkyy ruudulla, ja edelliset sijainnit eivät jää näkyviin.

Liikkeen nopeuden säätäminen on yksinkertaista: voit määrittää nopeusmuuttujan, joka kertoo, kuinka monta pikseliä hahmo liikkuu kerrallaan. Aseta sitten muuttuja switchin sisälle jokaisen koordinaatin muutoksen sisään. Jos haluat nopeamman liikkeen, kasvata nopeusmuuttujan arvoa. Pienempi arvo taas johtaa hitaampaan liikkeeseen. Huomaa kuitenkin, että suuret muutokset nopeusmuuttujassa voivat aiheuttaa töksähtelevää liikettä, kun hahmo “hyppii” suurempia matkoja kerrallaan. Tässä tapauksessa voit tutkia erilaisia tapoja tehdä liikkeestä sulavampaa.

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

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);

  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_Rect kuvaRect = { 100, 100, 100, 100 };

  SDL_Event e;
  bool quit = false;
  int nopeus = 20;

  while (quit == false)
  {
    SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));
    while (SDL_PollEvent(&e))
    {
      if (e.type == SDL_QUIT) quit = true;
      else if (e.type == SDL_KEYDOWN)
      {
        switch (e.key.keysym.sym)
        {
        case SDLK_LEFT:
          kuvaRect.x -= nopeus;
          break;
        case SDLK_RIGHT:
          kuvaRect.x += nopeus;
          break;
        case SDLK_UP:
          kuvaRect.y -= nopeus;
          break;
        case SDLK_DOWN:
          kuvaRect.y += nopeus;
          break;
        }
      }
    }

    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 ja kuvien näyttämiseen

Keskustelu

Aloita uusi keskustelu