Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C: Yksinkertainen 3D-sokkelo, SDL

Sivun loppuun

sqwiik [11.04.2007 23:18:19]

#

No niin, tuolla VB-puolella onkin jo tästä enemmän selostettu versio. Kun siirsin ko. koodin C-maailmaan, koodi koki muutamilta osin suuria muutoksia koska:
* SDL:ssä ei ole suoraan viiva/piste-funktioita
* Piirtorajapintoja ei saakaan yhtä helposti kuin VB:ssä
* Yms. yms. ...

Eli: viivanpiirtorutiini täytyi tehdä itse, mikä tuli tämän kanssa tutuksi piirtorajapinnan lukitsemisen kanssa; samoin tuli miettiä miten suorittaa ruudun päivitys syötteen lukemisen lomassa.

VB:hen parannuksena mukaan tuli hyvin, hyvin yksinkertainen oliosysteemi monine bugeineen. Tässä versiossa siis lahdataan mömmöjä luolastossa; grafiikat löytyvät suoritettavan EXE:n kanssa (jossa mukana jopa musiikki; poistettu tästä versiosta - erillisenä vinkkinä C-osiolla) tämän linkin takaa.

Ja sitten itse koodiin. Pitkälti tämä tosin on miltei samaa VB-version kanssa, paitsi olio-osuus. Sankarin ei tarvitse olla kuin yksi kuva; Sen sijaan kaikki muut viholliset tarvitsevat Syvyys-muuttujan verran kuvia eri kokoisina, koko muuttuen syvyyden neliön käänteisenä (puolet, neljännes, kahdeksannes...). Tämän huomaa paketissa olevasta kuvasta.

Edit 20.4.2007: Tapettu pari tpyota.

#include <SDL/SDL.h>

static char * Caption = "LUOLA by Sqwiik";

#define MaxX          16
#define MaxY          16
#define Syvyys        4


#define YlaSeina      1
#define AlaSeina      4
#define OikeaSeina    2
#define VasenSeina    8
/* Värejä... */
#define MAX_COL           4
# define COL_SEINA         0
# define COL_VSEINA        1
# define COL_LATTIA        2
# define COL_R1            3
#define MAX_R_COL         4

#define MAXOLIO       50


void TeeKentta();
void DoExit(void);
Sint16 DoStart();
void Pelaa();
void Piirra3D(SDL_Surface*);
void Liiku(Sint16, Sint16);
void Kaanny(Sint16);
void Hyokkaa(Sint16, Sint16);
void TaytaVert(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Sint16, Uint32);
void AI(); /* Tämän kaikkeuden typerin AI */

/* Piirtopinnat */
SDL_Surface * screen = NULL, * alue = NULL, * CrGraph[2] = {NULL};

/* Eri piirtojärjestykset */
typedef struct{
  Sint16 j[4];
}JARJ;

/* Hohoo, olio o__o */
typedef struct{
  Sint16 gr;  /* Grafiikka (CrGraph-taulukko) */
  Sint16 x, y, hipat;
}OLIO;

/* Kenttä + 'pelin' oliot */
Sint16 Kentta[MaxX][MaxY];
OLIO Oliot[MAXOLIO];

/* KAIKKI eri piirtojärjestykset */
JARJ PiirJar[8] = {
  /* Vasemmalla */
  {YlaSeina, VasenSeina, OikeaSeina, AlaSeina},
  {OikeaSeina, YlaSeina, AlaSeina, VasenSeina},
  {AlaSeina, OikeaSeina, VasenSeina, YlaSeina},
  {VasenSeina, AlaSeina, YlaSeina, OikeaSeina},
  /* Oikealla (peilikuva) */
  {YlaSeina, OikeaSeina, VasenSeina, AlaSeina},
  {OikeaSeina, AlaSeina, YlaSeina, VasenSeina},
  {AlaSeina, VasenSeina, OikeaSeina, YlaSeina},
  {VasenSeina, YlaSeina, AlaSeina, OikeaSeina},
};

/* Värejä - 4 erilaista hauskan pintakuvion aikaansaamiseksi */
Uint32 Varit[MAX_COL][MAX_R_COL];
/* Tarpeellisia muuttujia - syvyyden neliöt, sankarin sijainti ja katselusuunta */
Sint16 Maara[Syvyys] = {1, 2, 4, 8}, HX, HY, Suunta;

/* Tyhjän ruutun luonti ENDIAN:n mukaan */
SDL_Surface *CreateSurface(Sint16 w, Sint16 h, Sint16 bpp) {
  /* Maskit */
  Uint32 r, g, b, a;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
  r=0xff000000;
  g=0x00ff0000;
  b=0x0000ff00;
  a=0x000000ff;
#else
  r=0x000000ff;
  g=0x0000ff00;
  b=0x00ff0000;
  a=0xff000000;
#endif
  return SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, r, g, b, a);
}

/* Rujoa grafiikkaa! Kärsikää! Täyttää nelikulmion (palikan seinä) tietyllä värillä. Väreistä käytetään seinää, koska tällä ei piirretä kuin seiniä. Katto/lattia vaatisi oman funktion, mutten jaksanut tehdä. */
void TaytaVert(SDL_Surface * s, Sint16 x1, Sint16 x2, Sint16 y1, Sint16 y2, Sint16 h1, Uint32 col){
double ym;
Sint16 x, xm, w, yy, yym;
  /* Esilaskenta */
  ym = (double)(abs(y2 - y1)) / (double)(x2 - x1);
  xm = ((x2 < x1)?(-1):(1));
  w = (x2 - x1) + xm;
  /* Lukitus */
  if(SDL_MUSTLOCK(s)) {
    if(SDL_LockSurface(s) < 0) {
      fprintf(stderr, "Ruudun lukitus ei onnistu: %s\n", SDL_GetError());
      return;
    }
  }
  /* Rumuus piirroksi. Piirretään siis säännöllinen nelikulmio (seinä). */
  for(x = 0; x != w; x += xm){
    yym = y1 + h1 + (Sint16)(x * ym);
    if(x + x1 < 0 || x + x1 > s->w); else
    for(yy = y1 - (Sint16)(x * ym); yy <= yym; yy++){
      if(yy < 0 || yy >= s->h); else
      *(Uint32 *)((Uint8 *)s->pixels + (yy * s->pitch) + ((x + x1)<<2)) = Varit[COL_SEINA][rand()%4];
    }
  }
  if(SDL_MUSTLOCK(s))SDL_UnlockSurface(s);
}

/* Täyttää nelikulmion. */
void TaytaBox(SDL_Surface * s, SDL_Rect * r){
Sint16 x, y;
  if(SDL_MUSTLOCK(s)) {
    if(SDL_LockSurface(s) < 0) {
      fprintf(stderr, "Ruudun lukitus ei onnistu: %s\n", SDL_GetError());
      return;
    }
  }
  for(y = r->y; y < r->y + r->h; y++){
    for(x = r->x; x < r->x + r->w; x++){
      if(x < 0 || x >= s->w || y < 0 || y >= s->h); else
      *(Uint32 *)((Uint8 *)s->pixels + (y * s->pitch) + (x<<2)) = Varit[COL_SEINA][rand()%4];
    }
  }
  if(SDL_MUSTLOCK(s))SDL_UnlockSurface(s);
}

/* Taitaa olla lyhin main-funktioni >_> */
int main(int argc, char ** args){
  if(DoStart())return -1;
  Pelaa();
  exit(0);
}

/* Alustuksia */
Sint16 DoStart(){
Sint16 a, b;

  if(SDL_Init(SDL_INIT_VIDEO) < 0){
    printf("Moka SDL:n alustuksess (%s)!\n", SDL_GetError());
    return -1;
  }
  /* Automaatio muistin vapauttamiseksi */
  atexit(DoExit);

  SDL_WM_SetCaption(Caption, NULL);

  screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
  if(!screen){
    printf("Ei muistia ruudulle!\n");
    return -1;
  }

  alue = CreateSurface(320, 320, 32);
  if(!alue){
    printf("Ei muistia puskurille!\n");
    return -1;
  }

  /* Oliografiikat */
  CrGraph[0] = SDL_LoadBMP("hahmo.bmp");
  if(!CrGraph[0])return -1;
  SDL_SetColorKey(CrGraph[0], SDL_SRCCOLORKEY, SDL_MapRGB(CrGraph[0]->format, 0, 0, 0));
  CrGraph[1] = SDL_LoadBMP("vihu.bmp");
  if(!CrGraph[1])return -1;
  SDL_SetColorKey(CrGraph[1], SDL_SRCCOLORKEY, SDL_MapRGB(CrGraph[1]->format, 0, 0, 0));

  /* Alusta värit... seinä on kauniin sininen. Harmaalla saisi synkkyyttä. */
  Varit[COL_SEINA][0] = SDL_MapRGB(alue->format, 0, 0, 255);
  Varit[COL_SEINA][1] = SDL_MapRGB(alue->format, 0, 0, 128 + rand()%128);
  Varit[COL_SEINA][2] = SDL_MapRGB(alue->format, 0, 0, 64 + rand()%196);
  Varit[COL_SEINA][3] = SDL_MapRGB(alue->format, 0, 0, rand()%255);

  return 0;
}

void DoExit(){
Sint16 a;
  if(screen)SDL_FreeSurface(screen);
  if(alue)SDL_FreeSurface(alue);
  if(CrGraph[0])SDL_FreeSurface(CrGraph[0]);
  if(CrGraph[1])SDL_FreeSurface(CrGraph[1]);
  SDL_Quit();
}

/* Itse pelaaminen kontrolleineen */
void Pelaa(){
Uint8 paalla = 1, update = 1, turn = 0;
Uint16 a;
/* Pari ennalta laskettua väriä. */
Uint32 black = SDL_MapRGB(alue->format, 0, 0, 0), puna = SDL_MapRGB(alue->format, 255, 0, 0);
SDL_Event e;
/* Kestopistepalkkia varten */
SDL_Rect hipa = {0, 0, 40, 20};

  TeeKentta(); /* Kenttä... */

  while(paalla){

    /* Jos siirto on tehty, niin A.I.:n vuoro. */
    if(turn){
      AI();
      turn = 0;
      update = 1;
    }

    /* Grafiikka päivitetään vain ja vain jos on pakko. */
    if(update){
      SDL_FillRect(alue, NULL, black); /* Tyhjäys */
      Piirra3D(alue); /* Piirtous */
      /* Hipat */
      hipa.x = (alue->w /2) - ((Oliot[0].hipat * (hipa.w + 20)) >> 1);
      for(a = 0; a < Oliot[0].hipat; a++, hipa.x += 60){
        SDL_FillRect(alue, &hipa, puna);
      }
      /* Piirretyn alueen siirto screen:lle & flippaus */
      SDL_BlitSurface(alue, NULL, screen, NULL);
      SDL_Flip(screen);
      update = 0;
    }

    /* Tapahtumahorisontti */
    while(SDL_PollEvent(&e)){
      switch(e.type){
        case SDL_QUIT: paalla = 0; break;
        case SDL_KEYDOWN:
          switch(e.key.keysym.sym){
            /* Ohjaus ja yleinen */
            case SDLK_ESCAPE: paalla = 0; break;
            case SDLK_UP: Liiku(0, Suunta); update = 1; turn = 1; break;
            case SDLK_LEFT: Kaanny(-1); update = 1; break;
            case SDLK_RIGHT: Kaanny(1); update = 1; break;
            /* Idle */
            case SDLK_COMMA: turn = 1; update = 1; break;
            /* MUKS! */
            case SDLK_LCTRL: Hyokkaa(0, Suunta); update = 1; turn = 1; break;
          };
          break;
      };
    }
  }
}

/* Käännähdys */
void Kaanny(Sint16 dir){
  Suunta += dir;
  if(Suunta < 0)Suunta = 3; if(Suunta > 3)Suunta = 0;
}

/* Mömmö o humauttaa suuntaan s. */
void Hyokkaa(Sint16 o, Sint16 s){
Sint16 xm, ym, ol;
  xm = 0; ym = 0;
  switch(s){
    case 0: ym = -1; break;
    case 1: xm = 1;  break;
    case 2: ym = 1;  break;
    case 3: xm = -1; break;
  };
  /* Määritetään lyönnin oikeaoppisuus. */
  /* Ei seinää edessä? */
  if(Kentta[Oliot[o].x][Oliot[o].y] & (1 << s))return;
  /* Sijainnit OK? */
  if(Oliot[o].x+xm < 0 || Oliot[o].x+xm >= MaxX ||
    Oliot[o].y+ym < 0 || Oliot[o].y+ym >= MaxY)return;
  /* Onkos lyönnin edessä kohdetta? */
  for(ol = 0; ol < MAXOLIO; ol++){
    /* Onhan siinä... */
    if(Oliot[o].x+xm == Oliot[ol].x && Oliot[o].y+ym == Oliot[ol].y && ol != o)break;
  }
  if(ol >= MAXOLIO)return; /* Ei kohdetta */
  Oliot[ol].hipat --;
  if(Oliot[ol].hipat < 1){
    /* Kuoli pois - heivaus på helvetti. */
    Oliot[ol].x = -10;
  }else{
    /* Lämänotto */
  }
}

/* Liikauttaa oliota o suuntaan s. */
void Liiku(Sint16 o, Sint16 s){
Sint16 xm, ym, aSuunta, ol;
  xm = 0; ym = 0;
  /* aSuunta = vastasuunta */
  switch(s){
    case 0: ym = -1; aSuunta = 2; break;
    case 1: xm = 1;  aSuunta = 3; break;
    case 2: ym = 1;  aSuunta = 0; break;
    case 3: xm = -1; aSuunta = 1; break;
  };
  /* Seinä? */
  if(Kentta[Oliot[o].x][Oliot[o].y] & (1 << s))return;
  /* Rajat? */
  if(Oliot[o].x+xm < 0 || Oliot[o].x+xm >= MaxX ||
    Oliot[o].y+ym < 0 || Oliot[o].y+ym >= MaxY)return;
  /* Ei estesinää _toiselta_ puolelta? */
  if(Kentta[Oliot[o].x+xm][Oliot[o].y+ym] & (1 << aSuunta))return;
  for(ol = 0; ol < MAXOLIO; ol++){
    /* Olio käytäväntukkeena? */
    if(Oliot[o].x+xm == Oliot[ol].x && Oliot[o].y+ym == Oliot[ol].y){
      /* Autetaan AI:ta -_- */
      if(o > 0 && ol == 0)Hyokkaa(o, s);
      return;
    }
  }
  /* The liike */
  Oliot[o].x += xm; Oliot[o].y += ym;
  if(o == 0){
    HX += xm; HY += ym;
  }
}

/* Keinoäly juhlii */
void AI(){
Sint16 a, s;
  for(a = 1; a < MAXOLIO; a++){
    /* Suunta joko kohti sankaria tai random */
    if(abs(HX - Oliot[a].x) < 2 && abs(HY - Oliot[a].y) < 2){
      if(abs(HX - Oliot[a].x) >= 2){
        s = (HX < Oliot[a].x)? (3):(1);
      }else{
        s = (HY < Oliot[a].y)? (0):(2);
      }
    }else s = rand()%4;
    Liiku(a, s);
  }
}

/* Teh 3D-piirto. VB-versiosta tuttu, mutta nyt piirretään vapaan kokoiselle pinnalle. Rautalankamallille ei tällä erää mahdollisuutta. */
void Piirra3D(SDL_Surface * ss){
Sint16 x, y, xx, yy, xx2, yy2, xm, ym , w, h, a, kx, ky, mw, mh, mw2, mh2, b, pala, w2, h2, kier;
Sint16 ox, oy, olc;
Uint32 col;
SDL_Rect rect, orec;
  xm = 0; ym = 0;
  col = SDL_MapRGB(ss->format, 128, 128, 128);
  switch(Suunta){
    case 0: ym = -1; break;
    case 1: xm = 1;  break;
    case 2: ym = 1;  break;
    case 3: xm = -1; break;
  };
  /* Alkumuuttujia... */
  w = ss->w / 16;
  h = ss->h / 16;
  w2 = w / 2; h2 = h / 2;
  kx = ss->w / 2; ky = ss->h / 2;
  /* Rivit (takaa eteen) */
  for(a = Syvyys - 1; a >= 0; a--){
    /* X/Y-jako */
    if(ym){
      y = HY + (a * ym); x = HX;
    }else{
      y = HY; x = HX + (a * xm);
    }
    /* Laske leveydet ja korkeudet */
    mw = w * (1 << (Syvyys - a - 1)); mh = h * (1 << (Syvyys - a - 1));
    mw2 = w * (1 << (Syvyys - a)); mh2 = h * (1 << (Syvyys - a));
    yy = ky - (h2 * (1 << (Syvyys - a - 1)));
    yy2 = ky - (h2 * (1 << (Syvyys - a)));
    /* Käy läpi 'näkyvät' tilet */
    for(b = -Maara[a]; b <= Maara[a]; b++){
      /* Onko ruutu kentällä? */
      if((b + x >= 0 && b + x < MaxX && y >= 0 && y < MaxY && ym) || (b + y >= 0 && b + y < MaxY && x >= 0 && x < MaxX && xm)){
        /* Tarvittavia muuttujia */
        xx = kx - (w2 * (1 << (Syvyys - a - 1)));
        xx2 = kx - (w2 * (1 << (Syvyys - a)));
        /* Peilaus */
        if(ym < 0 || xm > 0){
          xx += (b * mw);
          xx2 += (b * mw2);
        }else{
          xx -= (b * mw);
          xx2 -= (b * mw2);
        }
        if(ym){ox = b + x; oy = y;} else{ox = x; oy = b + y;}
        pala = Kentta[ox][oy];
        /* Kierretään seinät järjestyksessä: taka, vasen, oikea, etu. */
        for(kier = 0; kier < 4; kier ++){
          if(pala & PiirJar[Suunta + ((xx>kx)?(4):(0))].j[kier]){
            switch(kier + ((xx>kx)?(4):(0))){
              case 0: case 4:
                rect.x = xx; rect.y = yy; rect.w = mw; rect.h = mh;
                TaytaBox(ss, &rect);
                break;
              case 1: case 6:
                  TaytaVert(ss, xx, xx2, yy, yy2, mh, col);
                break;
              case 2: case 5:
                  TaytaVert(ss, xx + mw, xx2 + mw2, yy, yy2, mh, col);
                break;
              case 3: case 7:
                rect.x = xx2; rect.y = yy2; rect.w = mw2; rect.h = mh2;
                if(a)TaytaBox(ss, &rect);
                break;
            };
          }
          /* Tässä vaiheessa täytyy testata oliot */
          if(kier == 1){
            for(olc = 0; olc < MAXOLIO; olc++){
             /* Piirrä mokoma */
              if(Oliot[olc].x == ox && Oliot[olc].y == oy){
                /* Laske sijainti laatikon pohjan keskipisteen mukaan */
                rect.w = (CrGraph[Oliot[olc].gr]->w) >> (a);
                rect.h = (CrGraph[Oliot[olc].gr]->w) >> (a);
                rect.x = ((xx + xx2 + mw2) >> 1) - (rect.w);
                rect.y = ((yy + mh + yy2 + mh2) / 2) - rect.h;
                orec.w = rect.w; orec.h = rect.h;
                orec.x = (CrGraph[Oliot[olc].gr]->w - orec.w) >> 1;
                orec.y = a * CrGraph[Oliot[olc].gr]->w + ((CrGraph[Oliot[olc].gr]->w - rect.h) >> 1);
                /* Piirto paikkaansa */
                SDL_BlitSurface(CrGraph[Oliot[olc].gr], &orec, ss, &rect);
              }
            }
          }
        } /* for kier */
      }/* Kentällä */
    } /* for b */
  } /* for a */
}


/* Kaunis kenttä. */
void TeeKentta(){
Sint16 kk[MaxX][MaxY] = {
  { 9, 1, 5, 5, 5, 5, 1, 3, 1, 9, 5, 5, 5, 7, 1, 3},
  { 8, 0, 2, 0, 0, 0, 2,10, 0, 0, 0, 0, 0, 0, 0, 2},
  { 8, 0, 2, 0, 0, 2, 2,10,12, 4, 4, 5, 5, 5, 7, 2},
  { 8, 0, 2, 0, 0, 2, 2,10, 0,10, 0, 0,10, 0, 0, 2},
  { 8, 4, 6, 6,11,14, 2,10, 0, 2, 0, 5, 2, 0, 0, 2},
  { 9, 4, 4, 4, 4, 4, 6,10, 0,10, 0, 0,10, 0, 0, 2},
  {12, 5, 5, 5, 1, 1, 3,10,12,10, 4, 4,10, 4, 4, 6},
  { 8, 1, 1, 3, 0, 0, 2, 4, 5, 4, 5, 5, 4, 5, 1, 3},
  {12, 4, 4, 2, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0,10, 2},
  {13, 5, 5, 4, 4, 4, 6, 0, 0, 8, 0, 0, 0, 0,10, 2},
  { 8, 0, 0, 3, 0, 0, 0, 0, 8, 5, 5, 5, 5, 7,10, 6},
  { 8, 0, 0, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 5, 0, 2},
  { 8, 0, 0, 5, 5, 4, 1, 7, 8, 1, 1, 1, 5, 5, 5, 3},
  { 8, 0, 0, 2, 0, 0,10, 0, 9, 1, 3,10, 1, 1, 1, 2},
  { 8, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2,10, 0, 0, 0, 2},
  {12, 4, 4, 6, 4, 4, 4, 4, 4, 4, 6,10,12, 4, 4, 6}}, x, y,
  sivut[4] = {1, 2, 4, 8}, sivut2[4] = {4, 8, 1, 2}, a,
  xm[4] = {0, 1, 0, -1}, ym[4] = {-1, 0, 1, 0};

  for(y = 0; y < MaxY; y++)for(x = 0; x < MaxX; x++)
    Kentta[x][y] = kk[y][x];

  /* Koska olen laiska paska, hoitakoon kone kentän korjaamisen -_-: tarkistetaan seinien yhtenevyys eri tilejen reunoilla */
  for(y = 0; y < MaxY; y++)for(x = 0; x < MaxX; x++){
    for(a = 0; a < 4; a++){
      if(Kentta[x][y] & sivut[a]){
        if(x + xm[a] >= 0 && x + xm[a] < MaxX && y + ym[a] >= 0 && y + ym[a] <= MaxY){
          Kentta[x + xm[a]][y + ym[a]] |= sivut2[a];
        }
      }
    }
  }

  /* Oliot pois. */
  for(x = 0; x < MAXOLIO; x++){
    Oliot[x].x = -10;
  }
  /* 'Sankari' */
  Oliot[0].x = 4; Oliot[0].y = 4; Oliot[0].gr = 0;
  Oliot[0].hipat = 6;
  /* Muita olioita */
  for(x = 1; x < MAXOLIO; x++){
    Oliot[x].x = rand()%MaxX; Oliot[x].y = rand()%MaxY; Oliot[x].gr = 1;
    Oliot[x].hipat = rand()%3 + 1;
  }
  HX = Oliot[0].x; HY = Oliot[0].y; Suunta = 0;
}

moptim [18.04.2007 18:05:49]

#

sqwiik, olet elite.

sqwiik [20.04.2007 18:32:09]

#

Tack.

nomic [23.04.2007 14:23:48]

#

Tämä on kyllä hauska. :)

Jakke1 [22.12.2007 21:16:04]

#

moptim kirjoitti:

sqwiik, olet eläin.

JAMSUO93 [04.02.2009 15:08:07]

#

KAUHEAA MITEN PITKÄÄ KOODIA!!!!!! huhhuhuh.... =)

JAMSUO93 [04.02.2009 15:08:08]

#

KAUHEAA MITEN PITKÄÄ KOODIA!!!!!! huhhuhuh.... =)

JAMSUO93 [04.02.2009 15:11:06]

#

KAUHEAA MITEN PITKÄÄ KOODIA!!!!!! huhhuhuh.... =)


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta