How can I perfectly manage my memory of my C project? - c

I am working on an object of SDL Tetris. When I ran my code, it first worked fine. But it automatically stopped displaying my text a few minutes later. I guessed there must be some problem on the memory management and I proved that I was right via Task Manager.
I look over my source code but found nothing wrong. (at least I didn't find it) Every heap object I delcared was freed and textures were destroyed. So, what can be the problem?
Here's my source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Surface * text;
TTF_Font* font;
bool running = true;
#define ScreenWidth 60
#define ScreenHeight 30
#define CharWidth 14
#define CharHeight 24
char screen[ScreenHeight][ScreenWidth + 1];
SDL_Color color = {192, 192, 192};
SDL_Rect rect;
int score = 0;
char shapes[7][17];
typedef struct Block {
int type;
char shape[17];
int x, y;
int width, height;
} Block;
Block * newBlock(int type) {
Block * block = malloc(sizeof(Block));
return block;
}
void CheckEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
} else if (event.type == SDL_KEYDOWN) {
switch (event.key.keysym.sym) {
case SDLK_w:
;
break;
case SDLK_a:
;
break;
case SDLK_d:
;
break;
case SDLK_s:
;
break;
case SDLK_SPACE:
;
break;
default:
break;
}
}
}
free(&event);
}
void UpdateBoard() {
for (int i = 0; i < ScreenHeight; ++i) {
for (int j = 0; j < ScreenWidth; ++j) {
screen[i][j] = ' ';
}
}
for (int i = 0; i != 20; ++i) {
screen[i + 2][1] = '#';
screen[i + 2][1 + 10 + 1] = '#';
}
for (int i = 0; i != 10 + 2; ++i) {
screen[22][i + 1] = '#';
}
sprintf(&(screen[0][1]), "Score: %d", score);
for (int i = 0; i != ScreenHeight; i++) {
for (int j = 0; j != ScreenWidth; j++) {
if (screen[i][j] == '\0') {
screen[i][j] = ' ';
}
}
}
}
void UpdateScreen() {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
for (int i = 0; i < ScreenHeight; ++i) {
text = TTF_RenderText_Solid(font, screen[i], color);
SDL_Texture * texture;
texture = SDL_CreateTextureFromSurface(renderer, text);
rect.x = 0;
rect.y = i * CharHeight;
rect.w = strlen(screen[i]) * CharWidth;
rect.h = CharHeight;
SDL_RenderCopy(renderer, texture, NULL, &rect);
free(texture);
SDL_DestroyTexture(texture);
}
SDL_RenderPresent(renderer);
}
void Init() {
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
window = SDL_CreateWindow("Tetris", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
ScreenWidth * CharWidth, ScreenHeight * CharHeight, 0);
renderer = SDL_CreateRenderer(window, -1, 0);
font = TTF_OpenFont("s8514oem.fon", 0);
sprintf(shapes[0], "OOOO............");
sprintf(shapes[1], "OO...OO.........");
sprintf(shapes[2], ".OO.OO..........");
sprintf(shapes[3], "O...OOO.........");
sprintf(shapes[4], "..O.OOO.........");
sprintf(shapes[5], "OO..OO..........");
sprintf(shapes[6], "OOO..O..........");
}
int main(int argc, char ** argv) {
Init();
while (running) {
CheckEvents();
UpdateBoard();
UpdateScreen();
SDL_Delay(1000/16);
}
TTF_Quit();
SDL_Quit();
return 0;
}
My Makefile:
tetris:
gcc -std=c99 -Wall -Isrc/include -Lsrc/lib -o Tetris main.c -lSDL2main -lSDL2 -lSDL2_ttf

Several things:
Don't try to free() stack-allocated variables like event:
//free(&event);
text needs to be freed with SDL_FreeSurface() before replacing its pointer value with a new one from TTF_RenderText_Solid():
if(text) {
SDL_FreeSurface(text);
}
text = TTF_RenderText_Solid(font, screen[i], color);
Don't use free() on the textures returned by SDL_CreateTextureFromSurface(), only use SDL_DestroyTexture():
texture = SDL_CreateTextureFromSurface(renderer, text);
...
//free(texture);
SDL_DestroyTexture(texture);

Related

How can I increase the length of the snake and make it follow the head?

Can someone help me to increase the length of the snake and make it follow the head ?
I tried to develop a simple snake game without videos or help and did almost great but cannot figure out how to increase the size of the snake and move it properly.
I'd be very thankful
#include <SDL2/SDL.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#define LOG(x) printf("%s\n", x)
#define LOG_ERROR(x) fprintf(stderr, "Error: %s\n", x)
#define LOG_SDL_ERROR(x) fprintf(stderr, "%s: %s\n", x, SDL_GetError())
#define global_variable static
#define internal_function static
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define HEAD_SIZE 30
#define APPLE_SIZE 25
#define MAX_LENGHT 10
typedef const char* string;
typedef float realNum;
typedef struct Snake
{
SDL_Rect body[MAX_LENGHT];
int xSpeed;
int ySpeed;
int site;
realNum xPos;
realNum yPos;
} Snake;
typedef struct Apple
{
int xPos;
int yPos;
int size;
} Apple;
void checkColissions(Apple *apple, Snake *snake );
bool initGame(void);
void update(realNum);
void handleEvent(SDL_Event);
void renderGame(void);
void gameOver(void);
void shutdownGame(void);
Snake makeSnake(void);
void renderSnake(Snake *snake);
void updateSnake(Snake *, realNum);
Apple makeApple();
void renderApple(Apple *);
global_variable bool Running;
global_variable SDL_Window *g_pWindow;
global_variable SDL_Renderer *g_pRenderer;
Snake *g_pSnake = NULL;
Apple *g_pApple = NULL;
int
main(int argc, char const *argv[])
{
srand((unsigned int)time(NULL));
atexit(shutdownGame);
if (!initGame())
{
LOG_ERROR("Failed Initialization");
exit(1);
}
else
{
Running = true;
int fps = 330;
int desiredDelta = 1000/fps;
SDL_Event event;
while (Running)
{
renderGame();
update(desiredDelta);
handleEvent(event);
SDL_Delay(rand() % 30);
}
}
return (EXIT_SUCCESS);
}
bool
initGame()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
LOG_SDL_ERROR("Failed initialization: ");
return (false);
}
else
{
g_pWindow =
SDL_CreateWindow("Snake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
g_pRenderer =
SDL_CreateRenderer(g_pWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
g_pSnake = (Snake*)malloc(sizeof(Snake));
g_pApple = (Apple*)malloc(sizeof(Apple));
*g_pSnake = makeSnake();
*g_pApple = makeApple();
if ((g_pApple || g_pSnake || g_pRenderer || g_pWindow) == NULL)
{
return (false);
}
g_pWindow == NULL ? LOG_ERROR("Window failed") : LOG("Succes Window");
g_pRenderer == NULL ? LOG_ERROR("Renderer failed") : LOG("Succes Renderer");
g_pApple == NULL ? LOG_ERROR("Apple failed") : LOG("Succes Apple");
g_pSnake == NULL ? LOG_ERROR("Snake failed") : LOG("Succes Snake");
LOG("Game initialized");
}
return true;
}
void
renderGame()
{
SDL_SetRenderDrawColor(g_pRenderer, 0, 80, 0, 255);
SDL_RenderClear(g_pRenderer);
renderSnake(g_pSnake);
renderApple(g_pApple);
SDL_RenderPresent(g_pRenderer);
}
void update(realNum elapsed)
{
updateSnake(g_pSnake, elapsed);
checkColissions(g_pApple, g_pSnake);
}
void
handleEvent(SDL_Event event)
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
{
Running = false;
} break;
default:
break;
}
}
void
shutdownGame()
{
if (g_pWindow)
{
SDL_DestroyWindow(g_pWindow);
}
if (g_pRenderer)
{
SDL_DestroyRenderer(g_pRenderer);
}
if (g_pApple)
{
free(g_pApple);
}
if (g_pSnake)
{
free(g_pSnake);
}
SDL_Quit();
LOG("Game shutdowned");
}
Snake makeSnake(void)
{
const int speed = 0;
Snake snake = {
.xSpeed = speed,
.ySpeed = speed,
.xPos = SCREEN_WIDTH / 2,
.yPos = SCREEN_HEIGHT / 2,
.site = HEAD_SIZE
};
SDL_Rect SnakeRect = {
.h = snake.site,
.w = snake.site,
.x = snake.xPos,
.y = snake.yPos
};
snake.body[0] = SnakeRect;
return (snake);
}
void renderSnake(Snake *snake)
{
for (int i = 0; i < MAX_LENGHT; i++)
{
SDL_SetRenderDrawColor(g_pRenderer, 0, 0, 100, 255);
SDL_RenderFillRect(g_pRenderer, &snake->body[i]);
}
}
void updateSnake(Snake *snake, realNum elapsed)
{
const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
for (int i = 0; i < MAX_LENGHT; i++)
{
/* code */
snake->body[i].y += snake->ySpeed * elapsed;
snake->body[i].x += snake->xSpeed * elapsed;
}
/* code */
/* code */
/* code */
if (keyboardState[SDL_SCANCODE_W])
{
snake->ySpeed = -1;
snake->xSpeed = 0;
}
if (keyboardState[SDL_SCANCODE_D])
{
snake->ySpeed = 0;
snake->xSpeed = 1;
}
if (keyboardState[SDL_SCANCODE_A])
{
snake->ySpeed = 0;
snake->xSpeed = -1;
}
if (keyboardState[SDL_SCANCODE_S])
{
snake->ySpeed = 1;
snake->xSpeed = 0;
}
if (snake->body->x < 0 - HEAD_SIZE)
{
snake->body->x = SCREEN_WIDTH + HEAD_SIZE;
}
if (snake->body->x > SCREEN_WIDTH + HEAD_SIZE)
{
snake->body->x = 0 - HEAD_SIZE;
}
if (snake->body->y < 0 - HEAD_SIZE)
{
snake->body->y = SCREEN_HEIGHT + HEAD_SIZE;
}
if (snake->body->y > SCREEN_HEIGHT + HEAD_SIZE)
{
snake->body->y = 0 - HEAD_SIZE;
}
}
void
checkColissions(Apple *apple, Snake *snake )
{
SDL_Rect appleRect = {
.h = APPLE_SIZE,
.w = APPLE_SIZE,
.x = apple->xPos,
.y = apple->yPos
};
if (SDL_HasIntersection(&appleRect, snake->body))
{
*g_pApple = makeApple();
};
}
Can someone help me to increase the length of the snake and make it follow the head ?
Snake is defined by an array of coordinates, not just one (x,y). You need some kind of circular buffer, that can change capacity. Or you can just use an array, and then change every element of the array with every snake's move. And then you would realize that circular buffer is a really neat idea.
Once you have your buffer, be it an array or circular buffer, the question becomes how to move and enlarge the snake in it. It is simple. To move the snake you add one coordinate to the head, and remove one from the tail of the buffer. When the snake should become bigger you just don't remove the last element in the buffer. Add to the head, but don't remove the tail. This is how circular buffer would be handled. In case of a plain array moving means overwriting everything, and enlarging means adding to the beginning, and moving everything else by one place.

How to change direction smoothly using SDL2 and how to keep moving when I press shift after holding a key?

It's my Code, it's a very simple tank games, I have 2 problems:
use WSAD to move with speed 4, when I pressing and holding shift, the speed change to 8, when I release shift, speed back to 4. But, with my code, when I press shift after holding WSAD, the tank stop, I must repress the key to move it.
When I press WSAD, the tank just change the direction, but not move,so when I holding d, the tank first change it's direction to right for about 0.5 second, then start to move. How to get it move smoothly?
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
const int WINDOW_WIDTH = 960; //窗体宽度
const int WINDOW_HEIGHT = 640; //窗体高度
//使用旋转角度定义方向
const int UP = 0;
const int DOWN = 180;
const int LEFT = 270;
const int RIGHT = 90;
//-------------------
typedef struct {
int x;
int y;
int width;
int height;
int direction;
SDL_Texture *texture;
} Player;
void RenderPlayer(Player player, SDL_Renderer *renderer) {
SDL_Rect srcRect = {.x = 0, .y = 0, .w = player.width, .h = player.height};
SDL_Rect destRect = {.x = player.x, .y = player.y, .w = player.width / 2, .h = player.height / 2};
SDL_RenderCopyEx(renderer, player.texture, &srcRect, &destRect, player.direction, NULL, SDL_FLIP_NONE);
}
int main(int argc, char *argv[]) {
SDL_Window *window;
SDL_Renderer *renderer;
if (SDL_Init(SDL_INIT_EVERYTHING)) {
printf("SDL对象初始化失败!\n");
return -1;
}
if (!(window = SDL_CreateWindow("坦克大战", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL))) {
printf("窗体创建失败!\n");
return -1;
}
if (!(renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE))) {
printf("渲染器创建失败!\n");
return -1;
}
SDL_SetRenderDrawColor(renderer, 76, 110, 150, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Surface *surface = IMG_Load("Tank01.png");
if (!surface) {
printf("像素集创建失败:%s\n", IMG_GetError());
return -1;
}
printf("宽度:%d\n高度:%d\n", surface->w, surface->h);
Player player1 = {(WINDOW_WIDTH - surface->w) / 2, WINDOW_HEIGHT - surface->h, surface->w, surface->h, UP, SDL_CreateTextureFromSurface(renderer, surface)};
int speed;
const Uint8 *state = SDL_GetKeyboardState(NULL);
SDL_Event sdlEvent;
while (1) {
int flag1 = 0;
while (SDL_PollEvent(&sdlEvent)) {
speed = 4;
switch (sdlEvent.type) {
case SDL_KEYDOWN:
if (state[SDL_SCANCODE_LSHIFT] && (state[SDL_SCANCODE_W] || state[SDL_SCANCODE_S] || state[SDL_SCANCODE_A] || state[SDL_SCANCODE_D])) {
speed = 8;
}
switch (sdlEvent.key.keysym.sym) {
case SDLK_w:
if (player1.y > 0) {
player1.y -= speed;
}
player1.direction = UP;
break;
case SDLK_s:
if (player1.y < WINDOW_HEIGHT - player1.height / 2) {
player1.y += speed;
}
player1.direction = DOWN;
break;
case SDLK_a:
if (player1.x > 0) {
player1.x -= speed;
}
player1.direction = LEFT;
break;
case SDLK_d:
if (player1.x < WINDOW_WIDTH - player1.width / 2) {
player1.x += speed;
}
player1.direction = RIGHT;
break;
case SDLK_ESCAPE:
SDL_Quit();
flag1 = 1;
break;
}
break;
case SDL_QUIT:
SDL_Quit();
flag1 = 1;
break;
}
}
SDL_RenderClear(renderer);
RenderPlayer(player1, renderer);
SDL_RenderPresent(renderer); //使用渲染器更新窗体
if (flag1) {
break;
}
}
return 0;
}
I couldn't reproduce your first problem with the code you provided, if I hold any of wasd and press shift the tank keeps moving.
The problem here is a bit hard to understand, but you're basically moving the tank only on SDL_Pressed events, meaning that the only reason your tank is moving at all is because SDL repeats the same events over and over, and because it doesn't do this very fast (polling events is kinda slow), your movement is choppy/laggy/steppy whatever you want to call it.
A fix for this is to remove the actual movement step outside your SDL_Event loop, also you should filter out repeat events since you've already checked them.
Meaning your code should look should be something like this
while (1) {
while (SDL_Event(e)) {
if (event is repeated)
skip event
if (UP Key is pressed)
up_state = 1;
if (UP key is released)
up_state = 0;
// etc..
}
// Outside the event loop
if (up_state == 1) // if its 0 we don't add anything
player.x -= speed;
// and so on..
}
For this to work properly you'll also need to read about how to implement a delta time in your loop, because this will run as fast as your processor can meaning that your speed wont be regular, it might add more or less speed depending on how fast is running, which is bad.
Here is your code with these problems fixed, except the delta time, since I actually don't which platform you're on and I was too lazy to do it in C, I capped the framerate at 60fps with a sleep at the end, which is a very bad idea.
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
// I don't know if you're on windows or linux
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
const int WINDOW_WIDTH = 960; //窗体宽度
const int WINDOW_HEIGHT = 640; //窗体高度
//使用旋转角度定义方向
const int UP = 0;
const int DOWN = 180;
const int LEFT = 270;
const int RIGHT = 90;
//-------------------
typedef struct {
int x;
int y;
int width;
int height;
int direction;
SDL_Texture *texture;
} Player;
int m_up = 0;
int m_down = 0;
int m_left = 0;
int m_right = 0;
void RenderPlayer(Player player, SDL_Renderer *renderer) {
SDL_Rect srcRect = {.x = 0, .y = 0, .w = player.width, .h = player.height};
SDL_Rect destRect = {.x = player.x,
.y = player.y,
.w = player.width / 2,
.h = player.height / 2};
SDL_RenderCopyEx(renderer, player.texture, &srcRect, &destRect,
player.direction, NULL, SDL_FLIP_NONE);
}
int main(int argc, char *argv[]) {
SDL_Window *window;
SDL_Renderer *renderer;
if (SDL_Init(SDL_INIT_EVERYTHING)) {
return -1;
}
if (!(window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH,
WINDOW_HEIGHT, SDL_WINDOW_OPENGL))) {
return -1;
}
if (!(renderer = SDL_CreateRenderer(window, -1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_TARGETTEXTURE))) {
return -1;
}
SDL_SetRenderDrawColor(renderer, 76, 110, 150, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Surface *surface = IMG_Load("tank.png");
if (!surface) {
return -1;
}
Player player1 = {(WINDOW_WIDTH - surface->w) / 2,
WINDOW_HEIGHT - surface->h,
surface->w,
surface->h,
UP,
SDL_CreateTextureFromSurface(renderer, surface)};
int speed = 4;
SDL_Event sdlEvent;
int run = 1;
while (run) {
while (SDL_PollEvent(&sdlEvent)) {
// Now we skip over repeat events
if ((sdlEvent.type == SDL_KEYDOWN || sdlEvent.type == SDL_KEYUP) &&
sdlEvent.key.repeat == 0) {
SDL_Keycode key = sdlEvent.key.keysym.sym;
int is_pressed = sdlEvent.key.state == SDL_PRESSED;
if (key == SDLK_LSHIFT && is_pressed) {
speed = 8;
} else if (key == SDLK_LSHIFT && !is_pressed) {
speed = 4;
}
if (key == SDLK_w && is_pressed) {
m_up = 1;
} else if (key == SDLK_w) {
m_up = 0;
}
if (key == SDLK_s && is_pressed) {
m_down = 1;
} else if (key == SDLK_s) {
m_down = 0;
}
if (key == SDLK_a && is_pressed) {
m_left = 1;
} else if (key == SDLK_a) {
m_left = 0;
}
if (key == SDLK_d && is_pressed) {
m_right = 1;
} else if (key == SDLK_d) {
m_right = 0;
}
if (key == SDLK_ESCAPE) {
run = 0;
}
if (sdlEvent.type == SDL_QUIT) {
run = 0;
}
}
}
// Handle the movement outside the event loop
if (m_up && player1.y > 0)
player1.y -= speed;
if (m_down && player1.y < WINDOW_HEIGHT - player1.height / 2)
player1.y += speed;
if (m_left && player1.x > 0)
player1.x -= speed;
if (m_right && player1.x < WINDOW_WIDTH - player1.width / 2)
player1.x += speed;
SDL_RenderClear(renderer);
RenderPlayer(player1, renderer);
SDL_RenderPresent(renderer);
#ifdef _WIN32
sleep(0.016); // asume 60 fps, horrible idea
#else
usleep(16000);
#endif
}
SDL_Quit();
return 0;
}
the test image I was using as 'tank.png' https://i.imgur.com/qlUagLp.png

C SDL VS Code image is not displaying

I have recently started learning game programming in C. I am using a virtual studio code on linux Ubuntu, and image star.png is not displaying on the screen, there are no errors or problems reported by vs code. I have tried reinstalling sdl2-dev and sdl2-image-dev libraries. Maybe it is a problem with SDL, or maybe with my code (it was written in 2013).
The code should draw a white ractangl, which i can move around, on a blue screen and place a star in upper left corner of a window. It does everything except placing a star.
The code: (doesn't show "Cannot dinf star.png!" so I guess it is not that)
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
typedef struct
{
int x, y;
short life;
char *name;
}Man;
typedef struct
{
//players
Man man;
//image
SDL_Texture *star;
} GameState;
/////////////////////////////////////////////////////////////////////processEvents
int processEvents(SDL_Window *window , GameState *game)
{
SDL_Event event;
int done = 0;
//Check for events
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_WINDOWEVENT_CLOSE:
{
if (window)
{
SDL_DestroyWindow(window);
window = NULL;
done = 1;
}
}
break;
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
done = 1;
break;
}
}
break;
case SDL_QUIT:
done = 1;
break;
}
}
const Uint8 *state = SDL_GetKeyboardState(NULL);
if(state[SDL_SCANCODE_LEFT])
{
game->man.x -= 1;
}
if(state[SDL_SCANCODE_RIGHT])
{
game->man.x += 1;
}
if(state[SDL_SCANCODE_UP])
{
game->man.y -= 1;
}
if(state[SDL_SCANCODE_DOWN])
{
game->man.y += 1;
}
SDL_Delay(10);
return done;
}
/////////////////////////////////////////////////////////////////////////////////////doRender
void doRedner(SDL_Renderer *renderer, GameState *game)
{
SDL_SetRenderDrawColor(renderer , 0, 0, 255, 255); //blue
//screen clean up into blue
SDL_RenderClear(renderer);
//set color
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_Rect rect = {game->man.x, game->man.y, 80, 80};
SDL_RenderFillRect(renderer, &rect);
//draw a star
SDL_Rect starRect = { 50, 50, 64, 64 };
SDL_RenderCopy(renderer, game->star, NULL, &starRect);
SDL_RenderPresent(renderer);
}
/////////////////////////////////////////////////////////////////////////////////////main funkction
int main(int argc, char *argv[])
{
GameState gameState;
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Surface *starSurface = NULL;
SDL_Init(SDL_INIT_VIDEO);
gameState.man.x = 340-40;
gameState.man.y = 240-40;
window = SDL_CreateWindow("Game Widnow",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
0
);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
//load image
starSurface = IMG_Load("star.png");
if(starSurface = NULL)
{
printf("Cannot find star.png!\n\n");
SDL_Quit();
return 1;
}
gameState.star = SDL_CreateTextureFromSurface(renderer, starSurface);
SDL_FreeSurface(starSurface);
int done = 0;
while(!done)
{
//check events
done = processEvents(window, &gameState);
//render
doRedner(renderer, &gameState);
}
SDL_Delay(1000);
//exit game and free memory
SDL_DestroyTexture(gameState.star);
//destroy and close window
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
TL;DR: Your intention is to perform a comparison, but you are using the assignment operator (i.e., =) instead of the comparison operator ==.
The conditional expression in your if statement:
if(starSurface = NULL)
{
...
}
does not check whether starSurface is NULL. The expression starSurface = NULL assigns NULL to starSurface and evaluates to NULL. Therefore, the condition evaluates to false and no error message is displayed.
Instead, you should write (note the double = below):
if (starSurface == NULL)
or just:
if (!starSurface)

Why does this SDL2 program slow down?

I have a problem with this program that reads audio data from an input device and displays a line representing the volume level. It starts ok then a few seconds later it starts lagging. It worked without slow downs until I tried to add some code to add image display functionality, which didn't work so I removed it, but now it the program doesn't work properly. I've removed most of the program functionality which I'll add back if I fix it. The CPU and GPU usage remains low so no problems there. If I switch to Software Mode it seems to work. I'm on Windows using MinGW-w64.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <math.h>
int SCREEN_WIDTH = 1024; //default
int SCREEN_HEIGHT = 768; //default
int FULLSCREEN = 0;
SDL_Renderer *rend;
//#define SOFTWARE_RENDER
//#define VSYNC_ON
#define PROGRAM_NAME "My Game"
#ifdef SOFTWARE_RENDER
#define RENDERER SDL_RENDERER_SOFTWARE
#else
#define RENDERER SDL_RENDERER_ACCELERATED
#endif
#if !defined(SOFTWARE_RENDER) && defined(VSYNC_ON)
#define VSYNC SDL_RENDERER_PRESENTVSYNC
#else
#define VSYNC 0
#endif
////https://wiki.libsdl.org/SDL_AudioSpec#callback
void audioInCallback(void *userdata, Uint8 *stream,int len)
{
float *floatStream = (float*)stream;
if (stream == NULL)
{
puts("Stream is NULL.");
return;
}
SDL_SetRenderDrawColor(rend, 0, 0, 0, 255);
SDL_RenderClear(rend);
SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);
float avg = 0;
for (int i=0;i<len;i++)
avg += fabs(floatStream[i]);
avg /= len;
SDL_RenderDrawLine(rend, 0,
SCREEN_HEIGHT/2 + round(SCREEN_HEIGHT/2.0 * avg),
SCREEN_WIDTH,
SCREEN_HEIGHT/2 + round(SCREEN_HEIGHT/2.0 * avg)
);
return;
}
int main(int argv, char *argc[])
{
int bufferSize = 8;
SDL_Window* window = NULL;
rend = NULL;
SDL_Event event;
bool loopIsActive = true;
SDL_AudioSpec want, have;
SDL_AudioDeviceID dev;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0)
{
printf("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
if( (window = SDL_CreateWindow( PROGRAM_NAME, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_SHOWN )) == NULL )
{
printf("Window could not be created! %s\n", SDL_GetError());
SDL_Quit();
return 0;
}
if ( (rend = SDL_CreateRenderer(window, -1, RENDERER | VSYNC)) == NULL )
{
printf("Error creating renderer. %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
int count = SDL_GetNumAudioDevices(1);
for (int i=0;i<count;i++)
{
printf("%d. %s\n", i, SDL_GetAudioDeviceName(i, 1));
}
SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */
want.freq = 44100;
want.format = AUDIO_S16;
want.channels = 1;
want.samples = pow(2,bufferSize);
want.callback = audioInCallback;
dev = SDL_OpenAudioDevice(NULL, 1, &want, &have, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
if (dev == 0)
printf("Failed to open audio: %s", SDL_GetError());
else
{
printf("have.samples = %u\n", have.samples);
printf("Opened device %s\nAudio format: ", SDL_GetAudioDeviceName(0, 1));
if (SDL_AUDIO_ISFLOAT(have.format))
printf("%d-bit %s\n", SDL_AUDIO_BITSIZE(have.format), SDL_AUDIO_ISFLOAT(have.format) ? "float" :
SDL_AUDIO_ISSIGNED(have.format) ? "signed" : "unsigned");
SDL_PauseAudioDevice(dev, 0); /* start audio playing. */
}
while (loopIsActive == true)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
loopIsActive = false;
break;
case SDL_KEYDOWN:
if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
{
loopIsActive = false;
}
break;
}
}
SDL_RenderPresent(rend);
SDL_Delay(16);
}
if (dev != 0) SDL_CloseAudioDevice(dev);
SDL_DestroyRenderer(rend);
SDL_DestroyWindow(window);
SDL_Quit();
puts("Hello world!");
return 0;
}
Don't try to do SDL_Renderer operations in a different thread like the one the audio callback is typically called from. As #keltar pointed out this is prohibited by SDL:
These functions must be called from the main thread.
Instead, bundle up the audio samples via your favorite method for rendering on the main thread (sorry for the C++, not much of a C guy re: threading primitives):
#include <SDL.h>
#include <vector>
#include <atomic>
#include <iostream>
// triple-buffering logic stol^H^H^H^Hborrowed from:
// https://stackoverflow.com/questions/49352853
std::vector< float >* g_ProducerBuffer;
std::vector< float >* g_ConsumerBuffer;
std::atomic< std::vector< float >* > g_CurrentBuffer;
void audioInCallback( void* userdata, Uint8* stream, int len )
{
const float* floatStream = reinterpret_cast< float* >( stream );
for( auto& sample : *g_ProducerBuffer )
{
sample = *floatStream;
floatStream++;
}
// post new buffer
g_ProducerBuffer = g_CurrentBuffer.exchange( g_ProducerBuffer );
}
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetHint( SDL_HINT_RENDER_VSYNC, "1" );
//SDL_SetHint( SDL_HINT_RENDER_DRIVER, "software" );
Uint32 flags = SDL_WINDOW_SHOWN;
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_CreateWindowAndRenderer( 1024, 768, flags, &window, &renderer );
// dump device names
int count = SDL_GetNumAudioDevices( 1 );
for( int i = 0; i < count; i++ )
{
std::cout << i << ": " << SDL_GetAudioDeviceName( i, 1 ) << '\n';
}
SDL_AudioSpec spec = { 0 };
spec.freq = 44100;
spec.format = AUDIO_F32LSB;
spec.channels = 1;
spec.samples = 1024;
spec.callback = audioInCallback;
const unsigned int deviceIndex = 0;
const std::string deviceName = SDL_GetAudioDeviceName( deviceIndex, 1 );
SDL_AudioDeviceID dev = SDL_OpenAudioDevice( deviceName.c_str(), 1, &spec, nullptr, 0 );
// set up audio buffers
std::vector< float > buffers[ 3 ];
buffers[ 0 ].resize( spec.samples );
buffers[ 1 ].resize( spec.samples );
buffers[ 2 ].resize( spec.samples );
g_ProducerBuffer = &buffers[ 0 ];
g_ConsumerBuffer = &buffers[ 1 ];
g_CurrentBuffer = &buffers[ 2 ];
// start audio capture
SDL_PauseAudioDevice( dev, 0 );
bool running = true;
while( running )
{
SDL_Event ev;
while( running && SDL_PollEvent( &ev ) )
{
if( SDL_QUIT == ev.type ||
SDL_KEYDOWN == ev.type && SDL_SCANCODE_ESCAPE == ev.key.keysym.scancode )
{
running = false;
}
}
SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255 );
SDL_RenderClear( renderer );
// grab latest audio buffer
// (this *seems* to work on my system but I'm not 100% sure it's correct)
while( !g_CurrentBuffer.compare_exchange_weak( g_ConsumerBuffer, g_ConsumerBuffer ) );
// draw audio sample waveform
std::vector< SDL_Point > points( g_ConsumerBuffer->size() );
for( size_t i = 0; i < g_ConsumerBuffer->size(); ++i )
{
const int x = static_cast< int >( i );
const int y = static_cast< int >( (*g_ConsumerBuffer)[ i ] * 200 + 768 / 2 );
points[ i ] = SDL_Point{ x, y };
}
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
SDL_RenderDrawLines( renderer, points.data(), points.size() );
SDL_RenderPresent( renderer );
}
SDL_CloseAudioDevice( dev );
SDL_DestroyRenderer( renderer );
SDL_DestroyWindow( window );
SDL_Quit();
return 0;
}

My code won't display sprite SDL2

The screen is always black. Tell me how to display the sprites correctly.
This is my code:
#define SHAPE_SIZE 32
void aff_map(SDL_Renderer *renderer)
{
SDL_Surface *img;
SDL_Texture *Tfloor
int x = 0;
int y = 0;
int map[4][8] = {{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}};
SDL_Rect SrcR;
SDL_Rect DestR;
DestR.x = 0;
DestR.y = 0;
DestR.w = SHAPE_SIZE;
DestR.h = SHAPE_SIZE;
img = IMG_Load("floor.bmp");
Tfloor = SDL_CreateTextureFromSurface(renderer, img);
while (y < 4)
{
x = 0;
while (x < 8)
{
if (map[y][x] == 0)
SDL_RenderCopy(renderer, Tfloor, NULL, &DestR);
x++;
DestR.x = DestR.x + 32;
}
DestR.x = 0;
DestR.y = DestR.y + 32;
y++;
}
SDL_RenderPresent(renderer);
}
int main()
{
SDL_Window *screen;
SDL_Event evenements;
SDL_Renderer *renderer;
screen = SDL_CreateWindow("Zappy", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 8 * SHAPE_SIZE -32, 4 * SHAPE_SIZE, 0);
renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED);
SDL_RenderClear(renderer);
while (42)
{
SDL_WaitEvent(&evenements);
if (evenements.window.event == SDL_WINDOWEVENT_CLOSE ||
evenements.key.keysym.sym == SDLK_ESCAPE)
{
SDL_DestroyWindow(screen);
SDL_Quit();
break;
}
aff_map(renderer);
}
return 0;
}
The error message is explicit.
It says that the "floor.bmp" has not been converted to a surface.
It means that 'img' parameter is NULL.
Try the following :
Specify the full path to your picture in IMG_Load(), for example "/home/quentin/floor.bmp"
Check the return value of IMG_Load().

Resources