/*************************************************************************** * Copyright (C) 2005 by Michal Turek - Woq * * WOQ (zavinac) seznam.cz * * * * Program rozsiruje ukazkovy priklad ze 16. dilu (hra ve stylu * * Pacmana). Do sceny jsou pridany objekty, ktere ma hrac za ukol * * sbirat (reset pomoci R) a nejake ty zvuky. Hudba je volitelna, * * staci odkomentovat jedno define a nastavit cestu k libovolnemu * * souboru. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include <stdio.h> #include <string.h> #include <time.h>// Kvuli srand() #include <stdlib.h> #include <SDL.h> #include <SDL_image.h>// -lSDL_image #include <SDL_mixer.h>// -lSDL_mixer /* * Symbolicke konstanty */ #define SDL_SUBSYSTEMS SDL_INIT_VIDEO|SDL_INIT_TIMER #define WIN_WIDTH 320 #define WIN_HEIGHT 240 #define WIN_BPP 0 #define WIN_TITLE "Zvuky ve hre" // Natoceni objektu #define STOP 0 #define RIGHT 1 #define LEFT 2 #define UP 3 #define DOWN 4 // Uzivatelske udalosti casovace #define USR_EVT_MOVE 0 // Velikost hraci plochy #define WIDTH 20 #define HEIGHT 15 // Objekty #define NUM_OBJS 10 #define OBJ_WIDTH 16 #define OBJ_HEIGHT 16 #define MAX_OBJS_IN_SCENE 100 #define NO_OBJECT 0 // Hudba, staci odkomentovat a nastavit cestu... // #define MUSIC_PATH "music.ogg" /* * Funkcni prototypy */ Uint32 TimerMoveCallback(Uint32 interval, void* param); // Callback casovace bool Init(); // Inicializace void Destroy(); // Deinicializace void Draw(); // Vykresleni bool ProcessEvent(); // Osetruje udalosti int main(int argc, char *argv[]); // Vstup do programu void ResetPlayground(); // Resetuje objekty bool ToggleFullscreen(); // Zmena okno/fullscreen SDL_Surface *LoadImage(const char *filename, bool alpha = false); /* * Globalni promenne */ Uint8 g_win_flags = SDL_HWSURFACE|SDL_DOUBLEBUF; SDL_Surface *g_screen; // Surface okna SDL_Surface *g_bg; // Surface pozadi SDL_Surface *g_obj[NUM_OBJS]; // Surface objektu (hrac na indexu 0) Uint8 g_playground[WIDTH][HEIGHT]; // Hraci hriste int g_xpos = 0, g_ypos = 0; // Pozice hrace v hristi int g_dir = RIGHT; // Smer pohybu SDL_TimerID g_timer_move_id = NULL; // Casovac pohybu int g_interval = 200; // Interval [ms] // Zvuky Mix_Chunk *g_obj_snd = NULL; Mix_Chunk *g_move_snd = NULL; Mix_Chunk *g_stop_snd = NULL; #ifdef MUSIC_PATH Mix_Music *g_music = NULL; #endif /* * Inicializacni funkce */ bool Init() { // Inicializace generatoru nahodnych cisel srand((unsigned int)time((time_t*)NULL)); // Inicializace SDL if(SDL_Init(SDL_SUBSYSTEMS) == -1) { fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); return false; } // Nastaveni ikony SDL_Surface *icon = SDL_LoadBMP("./icon.bmp"); if(icon != NULL) { SDL_WM_SetIcon(icon, NULL); SDL_FreeSurface(icon); } // Vytvori okno s definovanymi vlastnostmi g_screen = SDL_SetVideoMode(WIN_WIDTH, WIN_HEIGHT, WIN_BPP, g_win_flags); if(g_screen == NULL) { fprintf(stderr, "Unable to set %dx%d video: %s\n", WIN_WIDTH, WIN_HEIGHT, SDL_GetError()); return false; } // Titulek okna SDL_WM_SetCaption(WIN_TITLE, NULL); // Audio if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) == -1) { printf("Unable to open audio: %s\n", Mix_GetError()); return false; } if((g_obj_snd = Mix_LoadWAV("obj.wav")) == NULL || (g_move_snd = Mix_LoadWAV("move.wav")) == NULL || (g_stop_snd = Mix_LoadWAV("stop.wav")) == NULL) { printf("Unable to load sound: %s\n", Mix_GetError()); return false; } Mix_VolumeChunk(g_move_snd, MIX_MAX_VOLUME / 3);// Moc hlasity #ifdef MUSIC_PATH if((g_music = Mix_LoadMUS(MUSIC_PATH)) == NULL) { printf("Unable to load music: %s\n", Mix_GetError()); return false; } Mix_PlayMusic(g_music, -1); #endif // Loading obrazku int i; // Cykly char tmp[20]; // Pomocny if((g_bg = LoadImage("bg.png", false)) == NULL)// Pozadi return false; for(i = 0; i < NUM_OBJS; i++) // Pro jistotu g_obj[i] = NULL; for(i = 0; i < NUM_OBJS; i++) { sprintf(tmp, "%d.png", i); if((g_obj[i] = LoadImage(tmp, true)) == NULL) return false; } ResetPlayground(); // Reset objektu // Spusteni casovace g_timer_move_id = SDL_AddTimer(g_interval, TimerMoveCallback, NULL); return true; } /* * Deinicializacni funkce */ void Destroy() { // Zastaveni casovace if(g_timer_move_id != NULL) SDL_RemoveTimer(g_timer_move_id); // Obrazky if(g_bg != NULL) SDL_FreeSurface(g_bg); for(int i = 0; i < NUM_OBJS; i++) { if(g_obj[i] != NULL) { SDL_FreeSurface(g_obj[i]); g_obj[i] = NULL; } } // Zvuky if(g_obj_snd != NULL) { Mix_FreeChunk(g_obj_snd); g_obj_snd = NULL; } if(g_move_snd != NULL) { Mix_FreeChunk(g_move_snd); g_move_snd = NULL; } if(g_stop_snd != NULL) { Mix_FreeChunk(g_stop_snd); g_stop_snd = NULL; } #ifdef MUSIC_PATH if(Mix_PlayingMusic()) { Mix_FadeOutMusic(1000); SDL_Delay(1000); } if(g_music) { Mix_FreeMusic(g_music); g_music = NULL; } #endif Mix_CloseAudio(); SDL_Quit(); } /* * Callback funkce casovace, posle uzivatelskou udalost */ Uint32 TimerMoveCallback(Uint32 interval, void* param) { SDL_Event event; event.type = SDL_USEREVENT; event.user.code = USR_EVT_MOVE; event.user.data1 = NULL; event.user.data2 = NULL; SDL_PushEvent(&event); return g_interval; } /* * Resetuje objekty na hracim hristi, vse nahodne */ void ResetPlayground() { int i, j; for(i = 0; i < WIDTH; i++) for(j = 0; j < HEIGHT; j++) g_playground[i][j] = NO_OBJECT; for(i = 0; i < MAX_OBJS_IN_SCENE; i++) { g_playground[rand() % WIDTH][rand() % HEIGHT] = (rand() % NUM_OBJS) + 1;// 1. obrazek je hrac } } /* * Vykresleni sceny */ void Draw() { SDL_Rect src_rect, dst_rect; int x, y; // Pozadi dlazdicove pres cele okno for(x = 0; x < g_screen->w; x += g_bg->w) { for(y = 0; y < g_screen->h; y += g_bg->h) { dst_rect.x = x; dst_rect.y = y; SDL_BlitSurface(g_bg, NULL, g_screen, &dst_rect); } } // Objekty for(x = 0; x < WIDTH; x ++) { for(y = 0; y < HEIGHT; y++) { if(g_playground[x][y] != NO_OBJECT) { dst_rect.x = x * OBJ_WIDTH; dst_rect.y = y * OBJ_HEIGHT; SDL_BlitSurface(g_obj[g_playground[x][y]], NULL, g_screen, &dst_rect); } } } // Hrac src_rect.x = g_dir * g_obj[0]->w / 5; src_rect.y = 0; src_rect.w = g_obj[0]->w / 5; src_rect.h = g_obj[0]->h; dst_rect.x = g_xpos * g_obj[0]->w / 5; dst_rect.y = g_ypos * g_obj[0]->h; SDL_BlitSurface(g_obj[0], &src_rect, g_screen, &dst_rect); // Prohozeni predniho a zadniho bufferu SDL_Flip(g_screen); } /* * Osetreni udalosti */ bool ProcessEvent() { SDL_Event event; while(SDL_WaitEvent(&event)) { switch(event.type) { case SDL_KEYDOWN: switch(event.key.keysym.sym) { // Pohyby case SDLK_UP: g_dir = UP; break; case SDLK_DOWN: g_dir = DOWN; break; case SDLK_LEFT: g_dir = LEFT; break; case SDLK_RIGHT: g_dir = RIGHT; break; // Zrychleni case SDLK_KP_PLUS: if(g_interval > 20) g_interval -= 10; break; // Zpomaleni case SDLK_KP_MINUS: g_interval += 10; break; // Reset objektu case SDLK_r: ResetPlayground(); break; case SDLK_ESCAPE: return false; break; case SDLK_F1: if(!ToggleFullscreen()) return false; break; default: break; } break; // Uzivatelske udalosti (timer) case SDL_USEREVENT: switch(event.user.code) { case USR_EVT_MOVE: if(g_dir != STOP) Mix_PlayChannel(-1, g_move_snd, 0); switch(g_dir) { case UP: if(g_ypos <= 0) { g_dir = STOP; Mix_PlayChannel(-1, g_stop_snd, 0); } else g_ypos--; break; case DOWN: if(g_ypos*g_obj[0]->h >= g_screen->h - g_obj[0]->h) { g_dir = STOP; Mix_PlayChannel(-1, g_stop_snd, 0); } else g_ypos++; break; case LEFT: if(g_xpos <= 0) { g_dir = STOP; Mix_PlayChannel(-1, g_stop_snd, 0); } else g_xpos--; break; case RIGHT: if(g_xpos*g_obj[0]->w/5 >= g_screen->w - g_obj[0]->w/5) { g_dir = STOP; Mix_PlayChannel(-1, g_stop_snd, 0); } else g_xpos++; break; default: break; } if(g_playground[g_xpos][g_ypos] != NO_OBJECT) { g_playground[g_xpos][g_ypos]= NO_OBJECT; Mix_PlayChannel(-1, g_obj_snd, 0); } break; default: break; } break; // Zmena velikosti okna case SDL_VIDEORESIZE: g_screen = SDL_SetVideoMode(event.resize.w, event.resize.h, WIN_BPP, g_win_flags); if(g_screen == NULL) { fprintf(stderr, "Unable to resize window: %s\n", SDL_GetError()); return false; } break; // Pozadavek na ukonceni case SDL_QUIT: return false; break; default: break; } Draw(); } return true; } /* * Vstup do programu */ int main(int argc, char *argv[]) { printf(WIN_TITLE); printf("\nPress ESC key to quit.\n"); // Inicializace if(!Init()) { Destroy(); return 1; } // Hlavni smycka programu bool done = false; while(!done) { done = !ProcessEvent(); Draw(); // Vykresleni } // Deinicializace a konec Destroy(); return 0; } //////////////////////////////////////////////////////////////// // "Standardni funkce" // //////////////////////////////////////////////////////////////// /* * Funkce se pokusi nahrat obrazek ze souboru a zkonvertovat ho * na stejny pixel format, jako ma okno (framebuffer) */ SDL_Surface *LoadImage(const char *filename, bool alpha) { SDL_Surface *tmp;// Pomocny SDL_Surface *ret;// Bude vracen if((tmp = IMG_Load(filename)) == NULL)// Prilinkovat SDL_image { fprintf(stderr, "%s\n", SDL_GetError()); return NULL; } if((ret = (alpha) ? SDL_DisplayFormatAlpha(tmp) : SDL_DisplayFormat(tmp)) == NULL) { fprintf(stderr, "%s\n", SDL_GetError()); SDL_FreeSurface(tmp); return NULL; } SDL_FreeSurface(tmp);// Uz neni potreba return ret; } /* * Zmena modu okno/fullscreen (melo by fungovat vsude, nejen pod X11) */ bool ToggleFullscreen() { // Negace priznakoveho bitu ve flagach if(g_win_flags & SDL_FULLSCREEN)// Z fullscreenu do okna g_win_flags &= ~SDL_FULLSCREEN; else// Z okna do fullscreenu g_win_flags |= SDL_FULLSCREEN; // Pokus o prepnuti if(SDL_WM_ToggleFullScreen(g_screen) == 0) { fprintf(stderr, "Unable to toggle fullscreen," "trying to recreate window\n"); SDL_FreeSurface(g_screen); g_screen = SDL_SetVideoMode(WIN_WIDTH, WIN_HEIGHT, WIN_BPP, g_win_flags); if(g_screen == NULL) { fprintf(stderr, "Unable to recreate window: %s\n", SDL_GetError()); return false;// Ukonci program } Draw();// Prekresli scenu } return true;// OK }