/* balls.c SDL Example A simple, pachinko-style game Bill Kendrick 1/2000 */ #include <stdio.h> #include <stdlib.h> #include <SDL/SDL.h> #include <mixer.h> /* Constraints: */ #define MAX_BALLS 5 #define MAX_PEGS 32 /* Typedefs: */ typedef struct ball_type { int alive; int x, y; int xm, ym; } ball_type; typedef struct peg_type { int alive; int x, y; } peg_type; /* Global variables: */ ball_type balls[MAX_BALLS]; peg_type pegs[MAX_PEGS]; /* Local function prototypes: */ SDL_Surface * load_and_convert(char * file); void addball(int x, int y); void addpeg(int x, int y); void clearballs(void); void clearpegs(void); /* --- MAIN --- */ int main(int argc, char * argv[]) { SDL_Event event; SDLKey key; SDL_Surface * screen, * ball, * peg; SDL_Rect dest; int i, j, done, paused; Uint32 last_time; Mix_Chunk * tink; /* Init SDL: */ if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Init: %s\n", SDL_GetError()); exit(1); } /* Open display: */ screen = SDL_SetVideoMode(320, 240, 16, 0); if (screen == NULL) { fprintf(stderr, "Video: %s\n", SDL_GetError()); exit(1); } /* Set window title: */ SDL_WM_SetCaption("SDL Demo: Balls", "Balls"); /* Load graphics: */ ball = load_and_convert("ball.bmp"); peg = load_and_convert("peg.bmp"); /* Initialize Mixer: */ if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 512) < 0) { fprintf(stderr, "Can't open audio: %s\n", SDL_GetError()); exit(1); } /* Load sounds: */ tink = Mix_LoadWAV("tink.wav"); if (tink == NULL) { fprintf(stderr, "Can't open tink.wav: %s\n", SDL_GetError()); exit(1); } /* Initialize balls and pegs: */ clearballs(); clearpegs(); /* --- MAIN LOOP: --- */ done = 0; paused = 0; do { /* Get the time at the beginning of this iteration: */ last_time = SDL_GetTicks(); /* Handle all queued events: */ while (SDL_PollEvent(&event) > 0) { if (event.type == SDL_QUIT) { /* Quit request - quit! */ done = 1; } else if (event.type == SDL_KEYDOWN) { /* Keypress: */ key = event.key.keysym.sym; if (key == SDLK_ESCAPE) { /* Escape - quit! */ done = 1; } else if (key == SDLK_SPACE) { /* Space - Un/pause! */ paused = !paused; } else if (key == SDLK_TAB) { /* Tab - Clear pegs: */ clearpegs(); } } else if (event.type == SDL_MOUSEBUTTONDOWN) { if (event.button.button == 1) { /* Left click! Add a ball! */ addball(event.button.x, event.button.y); } else { /* Not left! Add a peg! */ addpeg(event.button.x, event.button.y); } } } /* Move all balls: */ if (!paused) { for (i = 0; i < MAX_BALLS; i++) { if (balls[i].alive) { /* Apply gravity: */ balls[i].ym++; /* Keep speeds in bounds: */ if (balls[i].ym > 24) balls[i].ym = 24; else if (balls[i].ym < -24) balls[i].ym = -24; if (balls[i].xm > 24) balls[i].xm = 24; else if (balls[i].xm < -24) balls[i].xm = -24; /* Move ball: */ balls[i].x = (balls[i].x + balls[i].xm); balls[i].y = (balls[i].y + balls[i].ym); /* If it dropped off the screen, kill it: */ if (balls[i].y >= 240) balls[i].alive = 0; /* See if it hit a peg: */ for (j = 0; j < MAX_PEGS; j++) { if (pegs[j].alive && balls[i].x >= pegs[j].x - 24 && balls[i].x <= pegs[j].x + 40 && balls[i].y >= pegs[j].y - 16 && balls[i].y <= pegs[j].y + 24) { /* Bounce! */ balls[i].ym = -abs(balls[i].ym - 1); balls[i].xm = ((balls[i].x - pegs[j].x) / 4) * ((abs(balls[i].xm) + 4) / 4); /* Play sound: */ if (abs(balls[i].ym) > 1) Mix_PlayChannel(-1, tink, 0); } } } } } /* Erase entire screen: */ SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255)); /* Draw all balls: */ for (i = 0; i < MAX_BALLS; i++) { if (balls[i].alive) { dest.x = balls[i].x; dest.y = balls[i].y; dest.w = 32; dest.h = 32; SDL_BlitSurface(ball, NULL, screen, &dest); } } /* Draw all pegs: */ for (i = 0; i < MAX_PEGS; i++) { if (pegs[i].alive) { dest.x = pegs[i].x; dest.y = pegs[i].y; dest.w = 32; dest.h = 32; SDL_BlitSurface(peg, NULL, screen, &dest); } } /* Update the entire screen: */ SDL_Flip(screen); /* Pause until it's time for the next frame: */ if (SDL_GetTicks() < last_time + 20) { SDL_Delay(last_time + 20 - SDL_GetTicks()); } } while (done == 0); /* Close up and quit: */ SDL_Quit(); return(0); } /* Load and convert a bitmap: */ SDL_Surface * load_and_convert(char * file) { SDL_Surface * temp, * surf; /* Load: */ temp = SDL_LoadBMP(file); if (surf == NULL) { fprintf(stderr, "Can't load %s: %s\n", file, SDL_GetError()); exit(1); } /* Convert: */ surf = SDL_DisplayFormat(temp); if (surf == NULL) { fprintf(stderr, "Can't convert %s: %s\n", file, SDL_GetError()); exit(1); } /* Make 100% white transparent: */ if (SDL_SetColorKey(surf, (SDL_SRCCOLORKEY), SDL_MapRGB(surf->format, 255, 255, 255)) < 0) { fprintf(stderr, "Can't set colorkey %s: %s\n", file, SDL_GetError()); exit(1); } /* Free: */ SDL_FreeSurface(temp); /* Return: */ return(surf); } /* Add a ball: */ void addball(int x, int y) { int i, found; /* Find an empty slot in the array: */ found = -1; for (i = 0; i < MAX_BALLS && found == -1; i++) { if (balls[i].alive == 0) found = i; } /* Fill in the slot: */ if (found != -1) { balls[found].alive = 1; balls[found].x = x - 16; balls[found].y = y - 16; balls[found].xm = 0; balls[found].ym = 0; } } /* Add a peg: */ void addpeg(int x, int y) { int i, found; /* Find an empty slot in the array: */ found = -1; for (i = 0; i < MAX_PEGS && found == -1; i++) { if (pegs[i].alive == 0) found = i; } /* Fill in the slot: */ if (found != -1) { pegs[found].alive = 1; pegs[found].x = x - 16; pegs[found].y = y - 16; } } /* Clear all balls: */ void clearballs(void) { int i; for (i = 0; i < MAX_BALLS; i++) balls[i].alive = 0; } /* Clear all pegs: */ void clearpegs(void) { int i; for (i = 0; i < MAX_PEGS; i++) pegs[i].alive = 0; } |