/*************************************************************************** * Copyright (C) 2005 by Michal Turek - Woq * * WOQ (zavinac) seznam.cz * * * * Program vykresluje objekt, se kterym je mozno sipkami pohybovat. * * Stiskem se nemeni poloha primo, ale pres rychlost je aplikovano * * zrychleni. V kazdem pruchodu se, nezavisle na stisku sipek, aplikuje * * gravitace. V pripade, ze objekt narazi do steny (okraj okna), * * odrazi se a jeho rychlost je zmensena. Jako bonus:-) kdyz se * * na klavesnici natuka urcita posloupnost klaves ("cheat"), bude * * aplikovan cheat... * * * * 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 <SDL.h> #include <SDL_image.h> /* * Symbolicke konstanty */ #define SDL_SUBSYSTEMS SDL_INIT_VIDEO #define WIN_WIDTH 320 #define WIN_HEIGHT 240 #define WIN_BPP 0 #define WIN_TITLE "Odrazy" /* * Funkcni prototypy */ bool Init(); // Inicializace void Destroy(); // Deinicializace void Draw(); // Vykresleni void Update(); // Aktualizace sceny bool ProcessEvent(); // Osetruje udalosti int main(int argc, char *argv[]); // Vstup do programu void CalculateFPS(); // Vypocet FPS bool ToggleFullscreen(); // Zmena okno/fullscreen SDL_Surface *LoadImage(const char *filename, bool alpha = false); /* * Globalni promenne */ // Grafika Uint8 g_win_flags = SDL_HWSURFACE|SDL_DOUBLEBUF; SDL_Surface *g_screen; // Surface okna SDL_Surface *g_bg; // Surface pozadi SDL_Surface *g_obj; // Surface objektu // Pohyby float g_xpos = 0, g_ypos = 0; // Pozice float g_xvel = 20, g_yvel = 0; // Rychlost const float g_xacc = 60, g_yacc = 60; // Zrychleni // Cheaty bool g_cheat_flag = false; // Flag cheatu char g_cheat_str[] = "cheat"; // Retezec cheatu unsigned int g_cheat_pos = 0; // Pozice v retezci // Pomocne prov vypocet FPS float g_fps = 1.0f; // Aktualni FPS Uint32 g_last_time = 0; // Cas minuleho prekresleni /* * Inicializacni funkce */ bool Init() { // 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); // Loading obrazku if(((g_bg = LoadImage("bg.jpg", false)) == NULL) || ((g_obj = LoadImage("obj.png", true)) == NULL)) { return false; } g_last_time = SDL_GetTicks(); return true; } /* * Deinicializacni funkce */ void Destroy() { if(g_bg != NULL) SDL_FreeSurface(g_bg); if(g_obj != NULL) SDL_FreeSurface(g_obj); SDL_Quit(); } /* * Vykresleni sceny */ void Draw() { SDL_Rect rect = { (short int)g_xpos, (short int)g_ypos, g_obj->w, g_obj->h }; if(!g_cheat_flag) SDL_BlitSurface(g_bg, NULL, g_screen, NULL); SDL_BlitSurface(g_obj, NULL, g_screen, &rect); SDL_Flip(g_screen); } void Update() { SDL_PumpEvents(); Uint8* keys; keys = SDL_GetKeyState(NULL); // Sipkami se ovlada rychlost objektu // (aplikace zrychleni na rychlost) if(keys[SDLK_RIGHT] == SDL_PRESSED) g_xvel += g_xacc / g_fps; if(keys[SDLK_LEFT] == SDL_PRESSED) g_xvel -= g_xacc / g_fps; if(keys[SDLK_UP] == SDL_PRESSED) g_yvel -= g_yacc / g_fps; if(keys[SDLK_DOWN] == SDL_PRESSED) g_yvel += g_yacc / g_fps; // Gravitace g_yvel += 40.0f / g_fps; // Zmena pozice o rychlost g_xpos += g_xvel / g_fps; g_ypos += g_yvel / g_fps; // Naraz do steny, odraz a zmenseni rychlosti if(g_xpos < 0) { g_xpos = 0; g_xvel /= -1.5f; // Bez deleni fps - jednorazova akce... } if(g_xpos > g_screen->w - g_obj->w) { g_xpos = g_screen->w - g_obj->w; g_xvel /= -1.5f; } if(g_ypos < 0) { g_ypos = 0; g_yvel /= -1.5f; } if(g_ypos > g_screen->h - g_obj->h) { g_ypos = g_screen->h - g_obj->h; g_yvel /= -1.5f; } } /* * Osetreni udalosti */ bool ProcessEvent() { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { // Stisk klavesy case SDL_KEYDOWN: // CHEATY // Spravna klavesa v posloupnosti if(g_cheat_str[g_cheat_pos] == event.key.keysym.sym) { // Cela posloupnost spravne if(++g_cheat_pos == strlen(g_cheat_str)) { // Aplikace cheatu g_cheat_flag = !g_cheat_flag; g_cheat_pos = 0;// Pristi pruchod } } else// Spatny cheat { g_cheat_pos = 0; } // Klasicke vetveni podle klavesy switch(event.key.keysym.sym) { case SDLK_ESCAPE: return false; break; case SDLK_F1: if(!ToggleFullscreen()) return false; 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; } } 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(); CalculateFPS(); // Vypocet FPS Update(); // Aktualizace sceny Draw(); // Vykresleni } // Deinicializace a konec Destroy(); return 0; } //////////////////////////////////////////////////////////////// // "Standardni funkce" // //////////////////////////////////////////////////////////////// /* * Vypocet poctu snimku za sekundu, pohyby budou nezavisle na rychlosti pocitace * Pri ~100 fps, prenechava cas jinym procesum */ void CalculateFPS() { // SDL_GetTicks() vraci cas v sekundach od inicializace SDL Uint32 miliseconds = SDL_GetTicks() - g_last_time; if(miliseconds < 10)// Max ~100 fps { SDL_Delay(10-miliseconds);// Cas pro dalsi procesy miliseconds = SDL_GetTicks() - g_last_time; } g_fps = 1.0f / (miliseconds / 1000.0f); g_last_time = SDL_GetTicks(); } /* * 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 }