В этом уроке научимся показывать таймер, фпс, и ускорять/замедлять frame per second.
Код:
SDL_Texture* titleInscription(SDL_Renderer* gRenderer,TTF_Font* timerFont,SDL_Color timerColor,int*x,int* k,SDL_Rect yourNameRect,char*writeYourName)
{
SDL_Surface* image = TTF_RenderText_Solid(timerFont,writeYourName,timerColor);
*x = image->w,*k=image->h;
yourNameRect.w = *x; yourNameRect.h = *k;
SDL_Texture* groundTexture = SDL_CreateTextureFromSurface(gRenderer,image);
SDL_RenderCopy(gRenderer,groundTexture,NULL,&yourNameRect);
SDL_RenderPresent(gRenderer);
return groundTexture;
}
Эта функция выводит надписи на экран(gRenderer) , и корректирует размер отображения(x,y)
исходя из длины символов.
void pasteNumberToChar(char **bufferString,int minNumber) {
char* bufferString2 = (char*)malloc(25);
int BufferCounter = 0;
while(minNumber >= 1) {
*bufferString2 = (minNumber%10) + '0';
bufferString2++;
minNumber = minNumber/10;
}
bufferString2--;
while(*bufferString2){
**bufferString = *bufferString2;
bufferString2--; (*bufferString)++;
BufferCounter++;
}
**bufferString =' ';
(*bufferString)++;
(**bufferString) = '\0';
(*bufferString) -=BufferCounter +1;
return;
}
Функция, которая меняет число на ее отображение строку.
void changeFPS (int *quit, SDL_Event e,int *delayTime,int *timerZero, int *framesInt){
while(SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT) {
*quit =1 ;
}else if (e.type == SDL_KEYDOWN || e.type == SDL_MOUSEBUTTONDOWN) {
if ( e.key.keysym.sym ==SDLK_UP ) {
if ( *delayTime >5 ){
(*delayTime) += 5;
*framesInt = 1;
*timerZero = time(NULL);
}
}else if ( e.key.keysym.sym ==SDLK_DOWN) {
if( *delayTime <300 ){
*framesInt = 1;
(*delayTime) -= 5;
*timerZero = time(NULL);
}
}else {
*quit =1;
}
}
}
}
Функция, которая изменяет фпс в зависимости от нажатия вверх или вниз, и выходит из программы при нажатии любой другой кнопки.
int main ( void )
{
int mWidth = 800, mHeight = 600;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_Window* window = SDL_CreateWindow("Read_Write", SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,mWidth,mHeight,SDL_WINDOW_SHOWN);
SDL_Renderer* gRenderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
SDL_Color timerColor = {0,255,0};
TTF_Font* timerFont = TTF_OpenFont("v_DigitalStrip_v1.5.ttf",25);
SDL_Rect timerPosition = {700,50,100,20};
SDL_Rect titleRect = { 580,50, 200,50};
SDL_Surface* timerSurface = NULL;
SDL_Texture* timerTexture = NULL;
SDL_Rect frameRect = { 580,100, 200,50};
SDL_Rect framePosition = { 700,100, 200,50};
SDL_Surface* frameSurface = NULL;
SDL_Texture* frameTexture = NULL;
SDL_Event e;
int quit = 0, checkerTime= 0;
int timerZero,timerNow;
timerZero = time(NULL);
SDL_Delay(1000);
char* timerText = "TIME:";
char* frameText = "FRAME:";
char* timerChar =(char*)malloc(12);
char* frameChar =(char*)malloc(12);
SDL_Texture* titleTime = titleInscription( gRenderer, timerFont, timerColor, &titleRect.w, &titleRect.h,titleRect,timerText);
SDL_Texture* titleFrame = titleInscription( gRenderer, timerFont, timerColor, &frameRect.w, &frameRect.h,frameRect,frameText);

C++

int main ( void )
{
int mWidth = 800, mHeight = 600;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_Window* window = SDL_CreateWindow("Read_Write", SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,mWidth,mHeight,SDL_WINDOW_SHOWN);
SDL_Renderer* gRenderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
SDL_Color timerColor = {0,255,0};
TTF_Font* timerFont = TTF_OpenFont("v_DigitalStrip_v1.5.ttf",25);
SDL_Rect timerPosition = {700,50,100,20};
SDL_Rect titleRect = { 580,50, 200,50};
SDL_Surface* timerSurface = NULL;
SDL_Texture* timerTexture = NULL;
SDL_Rect frameRect = { 580,100, 200,50};
SDL_Rect framePosition = { 700,100, 200,50};
SDL_Surface* frameSurface = NULL;
SDL_Texture* frameTexture = NULL;
SDL_Event e;
int quit = 0, checkerTime= 0;
int timerZero,timerNow;
char* timerText = "TIME:";
char* frameText = "FRAME:";
char* timerChar =(char*)malloc(12);
char* frameChar =(char*)malloc(12);
SDL_Texture* titleTime = titleInscription( gRenderer, timerFont, timerColor, &titleRect.w, &titleRect.h,titleRect,timerText);
SDL_Texture* titleint framesInt = 0, delayTime = 15;Frame = titleInscription( gRenderer, timerFont, timerColor, &frameRect.w, &frameRect.h,frameRect,frameText);
int framesInt = 0, delayTime = 15;
timerZero = time(NULL);
Стандартно задаем все переменные, так же задаем начальное время(timerZero).
while (!quit)
{
changeFPS(&quit, e, &delayTime,&timerZero,&framesInt);
SDL_SetRenderDrawColor(gRenderer,0,0,0,0);
SDL_RenderClear(gRenderer);
framesInt++;
timerNow = time(NULL)+1;
pasteNumberToChar( &timerChar, (timerNow - timerZero));
pasteNumberToChar( &frameChar, (framesInt)/(timerNow - timerZero));
Создаем бесконечный цикл, пока не нажата кнопка, проверяем функцией, проверяем нажата ли кнопка и если нажата меняем фпс(changeFPS),
устанавливаем черный цвет(SDL_SetRenderDrawColor),очищаем экран(SDL_RenderClear),
считываем фрейм(framesInt)
Считываем время сейчас(timerNow) и изменяем числа на текст для отображения.
timerSurface = TTF_RenderText_Solid(timerFont,timerChar,timerColor);
timerTexture = SDL_CreateTextureFromSurface(gRenderer,timerSurface);
frameSurface = TTF_RenderText_Solid(timerFont,frameChar,timerColor);
frameTexture = SDL_CreateTextureFromSurface(gRenderer,frameSurface);
timerPosition.w = timerSurface->w;
timerPosition.h = timerSurface->h;
framePosition.w = frameSurface->w;
framePosition.h = frameSurface->h;
SDL_RenderCopy(gRenderer,timerTexture,NULL,&timerPosition);
SDL_RenderCopy(gRenderer,frameTexture,NULL,&framePosition);
SDL_RenderCopy(gRenderer,titleTime,NULL,&titleRect);
SDL_RenderCopy(gRenderer,titleFrame,NULL,&frameRect);
SDL_RenderPresent(gRenderer);
SDL_FreeSurface(timerSurface);
SDL_FreeSurface(frameSurface);
SDL_DestroyTexture(timerTexture);
SDL_DestroyTexture(frameTexture);
SDL_Delay( delayTime );
Создаем текстуры времени и фпс, и выводим их на экран
после этого очищаем текстуры, для экономии памяти
и ставим задержку на delayTime, который регулируется в функции changeFPS
SDL_DestroyWindow( window );
TTF_Quit();
SDL_Quit();
}
CJay
В первом методе
не нужно ли удалять SDL_Surface* image после конвертации его в текстуру?
scorpka Автор
(gdb) printf "%i\n",titleTime
1437434912
(gdb) printf "%i\n",groundTexture
No symbol "groundTexture" in current context.
(gdb) printf "%i\n",image
No symbol "image" in current context.
_________________________________
как видно из отладчика, локальные переменные внешней функции после использования автоматически уничтожаются
CJay
Вот только SDL_Surface* image -- это не локальная переменная, а указатель на область памяти, выделенный внутри функции TTF_RenderText_Solid.
И чтобы не было утечки памяти, необходимо не забывать вызывать метод SDL_FreeSurface(image).
scorpka Автор
Спасибо за ваше недоверие, image это локальная переменная, содержащая в себе указатель на структуру, а не на динамическую память. Ну и так как никакой динамической памяти не выделяется, то можно и не освобождать surface
CJay
Так, попробую с другого бока.
Посмотрите, вот у вас имеется строка:
SDL_Surface* image = TTF_RenderText_Solid(timerFont,writeYourName,timerColor);
В ней вы создали локальную переменную, содержащую в себе указатель на структуру
SDL_Surface
. Структура эта создана в куче (то есть, в области динамической памяти), а не на стеке. Если бы она была создана на стеке, то строка имела бы вид:SDL_Surface image = TTF_RenderText_Solid(timerFont,writeYourName,timerColor);
Когда функция
titleInscription(...)
завершит своё выполнение, то локальная переменная, содержащая в себе указатель на струкрутуSDL_Surface
уничтожится, а вот память с этой структурой, выделенная в динамической области памяти, никуда не денется.А функция
titleInscription(...)
вызывается на каждом кадре, выделяя память под стркутуруSDL_Surface
размером 200x50 пикселей, что должно занимать память не менее чем 200*50*3=30000 байт за кадр. А если кадров 60 в секунду, то в секунду утечка памяти на 30 килобайт. За час работы программы утекает не менее 105 мегабайт памяти только на выводе FPS на экран.Чтобы этого безобразия не было, нужно в функции
titleInscription(...)
после строкиSDL_Texture* groundTexture = SDL_CreateTextureFromSurface(gRenderer,image);
вызвать метод
SDL_FreeSurface(image);
scorpka Автор
titleInscription(...)
вызывается только два раза за программу, и больше не вызывается.