EatTheBlocks

Präsentation und Organisation von eigenen Projekten
nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

EatTheBlocks

Beitrag von nufan » Mo Jan 05, 2009 1:44 pm

So, bevor ich morgen wegfahre, möchte ich euch noch mein Mini-Projekt vorstellen.
EatTheBlocks (bitte fragt mich nicht, wie ich auf diesen Namen gekommen bin... war schon ziemlich spät gestern ;) ) ist ein Snake-Klon. Es geht darum mit der Schlange von Blöcken den anderen Block zu "fressen".
Ich hab das Spiel zu 100% selbst programmiert und dabei auch mein neues SDL-Wissen verwendet. Auch die Bilder hab ich selbst "gegimpt" (sogar den weißen 10*10 Pixel Block :o :D ).
Programmiert hab ich bis jetzt ca. 4 Stunden, davon ca. 1 Stunde Fehlersuche ;)

Bis vorhin hatte ich noch einen Bug (der eigentlich gar keiner war). Die Blöcke werden immer an die Position des vorhergehenden gerückt. Das Programm blitete aber so schnell, dass schließlich nur noch ein Block zu sehen war. Das Problem bin ich jetzt umgangen, indem ich die Geschwindigkeit höher gestellt habe ;)

Ich möchte euch nicht nur bitten Verbesserungsvorschläge zum Spiel, sondern auch zu meinem Programmierstil abzugeben. Diese globalen statischen Variablen mag ich auch nicht, die werden in der nächsten Version verschwinden. Im Buch wurden sie aber überall verwendet...

Was ich noch ändern will/werde:
* die Surface besser anpassen (gameover richtig platzieren usw.)
* Prüfung ob das Fenster groß genug eingestellt ist (-h, -w)
* "wachsende" Schlange
* steigende Geschwindigkeit
* zufälligere Zufallszahlen ;) (sind immer gleich, keine Ahnung warum)
* einen Counter der die Punkte zählt und in eine Datei schreibt *
* Fullscreen support
* die ganzen Arrays in Listen umwandeln, da jetzt noch ziemlich viel Speicher verschwendet wird **
* ausführliche englische Dokumentierung

* Kann man ASCII-Zeichen auf ein Surface schreiben?? Oder muss ich dann immer ein Bild erstellen?
** valgrind meldet bei mir einen Speicher-Leak (16 Byte). Ich hab keine Ahnung was das sein könnte. Die Bilder hab ich ja alle freigegeben. Kann es sein, dass das von einer SDL-Lib verursacht wird?

Hier ist der Code:

Code: Alles auswählen

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define VERSION 0.1
#define MAXLENGTH 15
#define MAXSPEED 1

#define UP 0
#define RIGHT 1
#define DOWN 2
#define LEFT 3


typedef struct 
{
  int direction;
  int x, y;
} block_info;

typedef struct
{
  int x, y;
  int eaten;
} fruit_struct;


static block_info snake[MAXLENGTH];
static SDL_Surface *screen, *block, *fruit_pic;
static fruit_struct fruit;
static int length = 3;
static float speed = 0.75;


void parameters (int *w, int *h, int argc, char *argv[]);
void draw_snake (int direction[], int newx[], int newy[]);
void draw_fruit ();
void new_fruit ();
void check_input (SDL_Event event);
void check_border_score ();
void move_snake (int direction[], int newx[], int newy[]);
void display_help ();  


int main (int argc, char *argv[])
{

  SDL_Surface *temp, *background;
  SDL_Rect src, dest;
  SDL_Event event;
  int w = 800, h = 600, direction[MAXLENGTH], newx[MAXLENGTH], newy[MAXLENGTH];
  char *path_block = "./pics/block.bmp", *background_path = "./pics/background.bmp", *fruit_path = "./pics/fruit.bmp";
  
  
  parameters (&w, &h, argc, argv);
  
  if (SDL_Init (SDL_INIT_VIDEO) != 0)
  {
  
    printf ("Unable to initialize SDL: %s\n", SDL_GetError());
    
    return 1;
  
  }
  
  atexit (SDL_Quit);
  
  
  screen = SDL_SetVideoMode (w, h, 16, SDL_DOUBLEBUF);
  
  if (screen == NULL)
  {
  
    printf ("Unable to set video mode: %s\n", SDL_GetError());
    
    return 1;
  
  }
  
  
  background = IMG_Load (background_path);
  
  if (background == NULL)
  {
  
    printf ("Unable to load background.\n");
    
    return 1;
  
  }
  
  
  fruit_pic = IMG_Load (fruit_path);
  
  if (fruit_pic == NULL)
  {
  
    printf ("Unable to load picture.\n");
    
    return 1;
  
  }
   
  
  src.x = 0;
  src.y = 0;
  src.w = screen -> w;
  src.h = screen -> h;
  
  dest = src;
  
  SDL_BlitSurface (background, &src, screen, &dest);
  

  temp = IMG_Load (path_block);
  
  if (temp == NULL)
  {
  
    printf ("Unable to load picture.\n");
    
    return 1;
  
  }
  
  
  block = SDL_DisplayFormat (temp);
  SDL_FreeSurface (temp);
  
  
  snake[0].x = (float) screen -> w / 2;
  snake[0].y = (float) screen -> h / 2;
  snake[0].direction = LEFT;
  
  snake[1].x = (float) snake[0].x + block -> w;
  snake[1].y = (float) snake[0].y;
  snake[1].direction = LEFT;
  
  snake[2].x = (float) snake[1].x + block -> w;
  snake[2].y = (float) snake[1].y;
  snake[2].direction = LEFT;
  
  fruit.eaten = 0;
  new_fruit ();
  
  SDL_Delay (1000);
  
  
  while (1)
  {
  
    draw_snake (direction, newx, newy);
    
    draw_fruit ();
  
    SDL_PollEvent (&event);
    
    check_border_score ();
  
    switch (event.type)
    {
    
      case SDL_KEYDOWN: check_input (event);
                        break;
                        
      case SDL_QUIT: exit (0);
    
    }
    
    SDL_BlitSurface (background, &src, screen, &dest);
    
    move_snake (direction, newx, newy);
  
  }
  
  
  SDL_FreeSurface (background);
  SDL_FreeSurface (block);

  return 0;

}



void parameters (int *w, int *h, int argc, char *argv[])
{

  int i;
  
  for (i = 0; i < argc; i++)
  {
  
    if (strcmp (argv[i], "-w") == 0)
      *w = atoi (argv[i + 1]);
      
    else if (strcmp (argv[i], "-h") == 0)
      *h = atoi (argv[i + 1]);
      
    else if (strcmp (argv[i], "--help") == 0)
    {
      display_help ();  
      exit (0);
    }
  
  }

}



void display_help ()
{

  printf ("\nEatTheBlocks V%.1f\n", VERSION);
  printf ("\nOptions:\n\t-w\t=\tspecify windows width\n\t-h\t=\tspecifiy window hight\n\t--help\t=\tshow this help\n");

}



void draw_snake (int direction[], int newx[], int newy[])
{

  int i;
  SDL_Rect src, dest;
  
  src.x = 0;
  src.y = 0;
  src.w = block -> w;
  src.h = block -> h;  
  
  dest.w = block -> w;
  dest.h = block -> h;
  
  for (i = 0; i < length; i++)
  {
    
    dest.x = snake[i].x;
    dest.y = snake[i].y;
    
    SDL_BlitSurface (block, &src, screen, &dest);
  
  }
  
  SDL_Flip (screen);
  
  for (i = 0; i < length; i++)
  {
    direction[i] = snake[i].direction;
    newx[i] = snake[i].x;
    newy[i] = snake[i].y;
  }   

}



void draw_fruit ()
{

  SDL_Rect src, dest;
  
  src.x = 0;
  src.y = 0;
  src.w = fruit_pic -> w;
  src.h = fruit_pic -> h;
  
  dest.x = fruit.x;
  dest.y = fruit.y;
  dest.w = fruit_pic -> w;
  dest.h = fruit_pic -> h;
  
  SDL_BlitSurface (fruit_pic, &src, screen, &dest);
  
  SDL_Flip (screen);

}



void new_fruit ()
{

  fruit.x = rand () % screen -> w;
  fruit.y = rand () % screen -> h;

}



void check_input (SDL_Event event)
{

  SDL_keysym key = event.key.keysym;

  if (key.sym == SDLK_UP && snake[0].direction != DOWN)
    snake[0].direction = UP;
    
  else if (key.sym == SDLK_RIGHT && snake[0].direction != LEFT)
    snake[0].direction = RIGHT;
    
  else if (key.sym == SDLK_DOWN && snake[0].direction != UP)
    snake[0].direction = DOWN;
  
  else if (key.sym == SDLK_LEFT && snake[0].direction != RIGHT)
    snake[0].direction = LEFT;      
    
  else if (key.sym == SDLK_ESCAPE)
    exit (0);  

}



void check_border_score ()
{

  SDL_Surface *gameover;
  SDL_Rect src, dest;
  
  if ((snake[0].x < 0) || ((snake[0].x + block -> w) > screen -> w) || (snake[0].y < 0) || ((snake[0].y + block -> h) > screen -> h))
  {
  
    printf ("Game over.\n");
  
    gameover = IMG_Load ("./pics/gameover.bmp");
    
    if (gameover == NULL)
    {
    
      printf ("Unable to load picture.\n");
      
      exit (0);
    
    }
    
    src.x = 0;
    src.y = 0;
    src.w = gameover -> w;
    src.h = gameover -> h;
    
    dest.x = screen -> w / 3;
    dest.y = screen -> h / 3;
    dest.w = gameover -> w;
    dest.h = gameover -> h;
    
    SDL_BlitSurface (gameover, &src, screen, &dest);
    SDL_FreeSurface (gameover);
    
    SDL_Flip (screen);
    
    SDL_Delay (5000);
    
    exit (0);
  
  }
  
    
  if  ((snake[0].x < (fruit.x + fruit_pic -> w) && snake[0].x > (fruit.x - fruit_pic -> w)) && (snake[0].y < (fruit.y + fruit_pic -> h) && snake[0].y > (fruit.y - fruit_pic -> h))) 
    new_fruit ();
    
}



void move_snake (int direction[], int newx[], int newy[])
{

  int i;
  
  
  for (i = 0; i < length; i++)
  {  
    
    if (i == 0)
    {
    
      if (snake[0].direction == UP)
        snake[0].y -= (speed * (block -> h));
      
      else if (snake[0].direction == RIGHT)
        snake[0].x += (speed * (block -> w));
      
      else if (snake[0].direction == DOWN)
        snake[0].y += (speed * (block -> h));
      
      else if (snake[0].direction == LEFT)
        snake[0].x -= (speed * (block -> w));
    
    }
    
      else
      {
        snake[i].direction = direction[i - 1]; 
        snake[i].x = newx[i - 1];
        snake[i].y = newy[i - 1];
      }
  
  }

}

Kompilieren mit:

Code: Alles auswählen

gcc -o eat EatTheBlocks.c -Wall `sdl-config --cflags --libs` -lSDL_image
Per Parameter kann man auch die Fenstergröße beliebig einstellen (siehe --help).

Eigene Bilder einfach in den Ordner ./pics kopieren und entsprechend umbenennen. Ich habe 16 Bit RGB (565) Bilder verwendet.

Das Programm hab ich bis jetzt nur unter Ubuntu getestet, für Windows muss ich dann noch die ganzen Libs runterladen... :roll:

Bevor ichs vergesse: das Spiel ist entweder aus, wenn man gegen den Bildrand fährt, Escape gedrückt wird oder auf Schließen geklickt wird.

Hier noch ein Link zum Code inklusive Bilder:
*klick*
Von 2 MB auf 6.6 Kb gezippt (für alle mit langsamen Internet :) )

Zurzeit liegt das Archiv noch auf meinem Webspace meiner ehemaligen Homepage (besteht inzwischen nur mehr aus 1 weißen Seite). Ich sollte aber noch von meinem ISP 500 MB Webspace gratis bekommen... muss ich mir mal genau ansehen.

Zum rechtlichen... :roll:
Das Programm darf frei weiterverbreitet und verändert werden. Ich übernehme keine Haftung für eventuell entstehende Schäden. Kann jedoch bestätigen, dass das Programm bei mir ohne Probleme funktioniert. Blabla...

Ok, das wars :)
Achja, wenn ich heute nicht mehr antworte, dann höchstwahrscheinlich die ganze nächste Woche nicht :)

Benutzeravatar
+Fuss+
Beiträge: 385
Registriert: Fr Nov 14, 2008 8:16 pm

Re: EatTheBlocks

Beitrag von +Fuss+ » Mo Jan 05, 2009 2:04 pm

Muss man da noch zusätzliche Pakete herunterladen?
Oder kann es sein das beim Kompilieren etwas nicht stimmt?

GCC sagt, dass er "SDL/SDL_image.h" nicht findet.
SDL/SDL.h ist kein Problem...

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: EatTheBlocks

Beitrag von nufan » Mo Jan 05, 2009 2:09 pm

+Fuss+ hat geschrieben:Muss man da noch zusätzliche Pakete herunterladen?
Oder kann es sein das beim Kompilieren etwas nicht stimmt?

GCC sagt, dass er "SDL/SDL_image.h" nicht findet.
SDL/SDL.h ist kein Problem...
Sorry, vergessen zu sagen.
libsdl-image1.2 dürfte das Paket sein. libsdl1.2-dev sollte auch installiert sein.

EDIT:
Neuer Punkt auf der Liste:
* Neue Blöcke nicht auf die Schlange setzen...

Benutzeravatar
+Fuss+
Beiträge: 385
Registriert: Fr Nov 14, 2008 8:16 pm

Re: EatTheBlocks

Beitrag von +Fuss+ » Mo Jan 05, 2009 2:16 pm

Die beiden Pakete sind bei mir schon in der neusten Version vorhanden.
im Ordner /usr/include/SDL gibt es aber SDL_image.h nicht.

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: EatTheBlocks

Beitrag von nufan » Mo Jan 05, 2009 2:24 pm

+Fuss+ hat geschrieben:Die beiden Pakete sind bei mir schon in der neusten Version vorhanden.
im Ordner /usr/include/SDL gibt es aber SDL_image.h nicht.
Hmmm....

/* edit by Kerli: Bitte keine Pakete ohne Verwendung des Paketmanagers installieren. Siehe dazu auch diesen Beitrag. */

dann das runterladen und mit dem Paket "alien" in ein .deb konvertieren.
Also

Code: Alles auswählen

$ alien SDL_image-1.2.7-1.src.rpm
Und dann einfach Doppelklick auf die .deb-Datei.

EDIT:
wenn das nicht geht, dann dieses
http://www.libsdl.org/projects/SDL_imag ... 1.i386.rpm
und wenn das auch nicht geht, dann das:
http://www.libsdl.org/projects/SDL_imag ... 1.i386.rpm
;)

Ich glaube es ist das erste vom EDIT.

Benutzeravatar
+Fuss+
Beiträge: 385
Registriert: Fr Nov 14, 2008 8:16 pm

Re: EatTheBlocks

Beitrag von +Fuss+ » Mo Jan 05, 2009 2:30 pm

1. sudo vergessen
2. GCC findet SDL_image.h immernoch net

EDIT: mal sehen was die anderen Pakete sagen...
EDIT2: mit dem 1 Paket in deinem Edit funktioniert es!

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: EatTheBlocks

Beitrag von nufan » Mo Jan 05, 2009 2:41 pm

+Fuss+ hat geschrieben:1. sudo vergessen
Nicht wenn du als root eingelogg bist :D
Ne, bin ich nicht, habs vergessen :)
+Fuss+ hat geschrieben:EDIT2: mit dem 1 Paket in deinem Edit funktioniert es!
Ich hab jetzt schon einige SDL-Pakete... da vergisst man schon mal, was man woher hat. :)

Benutzeravatar
+Fuss+
Beiträge: 385
Registriert: Fr Nov 14, 2008 8:16 pm

Re: EatTheBlocks

Beitrag von +Fuss+ » Mo Jan 05, 2009 2:44 pm

* steigende Geschwindigkeit
Noch schneller?
Also ich finde das so schon schnell genug!!!
Da hängt man ja schon 3 mal an der Wand bevor man reagieren kann und eine Taste gedrückt hat...

Aber sons ganz in Ordnung!
Ich hab mal meine Reaktion getestet und ein neuer grüner block hängt so halb in der Wand??
Soll ich das Fenster größer machen oder wie?

Edit: kannes sein, das die Geschwindigkeit im Spiel schwankt?

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: EatTheBlocks

Beitrag von nufan » Mo Jan 05, 2009 2:55 pm

+Fuss+ hat geschrieben:Noch schneller?
Naja es soll langsam anfangen und dann steigern.
+Fuss+ hat geschrieben:Da hängt man ja schon 3 mal an der Wand bevor man reagieren kann und eine Taste gedrückt hat...
Bei mir dauerts ohne lenken bis zum Crash 3 Sekunden. Sollte doch reichen ;)
+Fuss+ hat geschrieben:Soll ich das Fenster größer machen oder wie?
Version 0.1a ;)

Es hat sich nur diese Funktion geändert:

Code: Alles auswählen

void new_fruit ()
{

  fruit.x = rand () % (screen -> w - fruit_pic -> w - 10) + 5;
  fruit.y = rand () % (screen -> h - fruit_pic -> h - 10) + 5;

}
Jetzt ist der Block immer mindestens 5 Pixel vom Rand entfernt.

Habs neu raufgeladen. Gleicher Link, diesmal sogar vorkompiliert ;)

EDIT:
+Fuss+ hat geschrieben:Edit: kannes sein, das die Geschwindigkeit im Spiel schwankt?
Sollte nicht sein.
Ich teste noch ein bisschen...

Benutzeravatar
+Fuss+
Beiträge: 385
Registriert: Fr Nov 14, 2008 8:16 pm

Re: EatTheBlocks

Beitrag von +Fuss+ » Mo Jan 05, 2009 3:36 pm

Ich sitze gerade an einem anderen Rechner.
Den Header "SDL_image.h" habe ich schon hinzugefügt! Aber es fehlen alle anderen SDL-Header! Ich hab auf dem Rechner vorgestern Ubuntu installiert, und zwar von der selben DVD mit der ich Ubuntu auf meinem Rechner installiert hab. Ich wüsste nicht, warum hier die SDL-Header fehlen.
Hat zufällig einer gerade nen Link?

Antworten