Can't see My Player on the Screen

My player’s not visible on the screen. I guess there’s something wrong with my code but I can’t figure out what, here’s my function definitions’ code:

#include <SDL.h>
#include <iostream>
#include <SDL_image.h>
#include "Game.hpp"
using namespace std;

// defining member func of Game class
Game::Game(const char *title, int x, int y, int w, int h, int flags) {
	// initialize SDL
	if (SDL_Init(SDL_INIT_EVERYTHING) >= 0) {
		mRunning = true;
		// create window
		mWindow = SDL_CreateWindow(title, x, y, w, h, flags);
		if (mWindow != 0) {
			// create renderer
			mRenderer = SDL_CreateRenderer(mWindow, -1, 0);
		}
		else {
			mRunning = false;
			cout << "SDL Error: " << SDL_GetError;
		}
	}
	else {
		mRunning = false;
		cout << "SDL Error: " << SDL_GetError;
	}

	// create texture from surface
	SDL_Surface* tempSurface = IMG_Load("dino_00.png");
	mTexture = SDL_CreateTextureFromSurface(mRenderer, tempSurface);
	SDL_FreeSurface(tempSurface);

	SDL_QueryTexture(mTexture, NULL, NULL, &mExtractRect.w, &mExtractRect.h);

	// mExtractRect: corresponding to coordinates given, extracts a collection of pixels from image

	// coordinates
	mExtractRect.x = 0;
	mExtractRect.y = 0;

	// mPasteRect: corresponding to coordinates given, displays the pixels on the screen

	//coordinates
	mPasteRect.x = 0;
	mPasteRect.y = 0;
	// size
	mPasteRect.w = mExtractRect.w;
	mPasteRect.h = mExtractRect.h;

	mRunning = true;
}

void Game::handleEvents() {
	SDL_Event event;
	if (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_QUIT:
			mRunning = false;
			break;

		default:
			break;
		}
	}
}

void Game::render() {
	// set renderer color
	SDL_SetRenderDrawColor(mRenderer, 158, 217, 39, 1);

	// clear screen to black as, per frame previous screen is discarded
	SDL_RenderClear(mRenderer);

	// displays pixels to screen currently being rendered
	SDL_RenderCopy(mRenderer, mTexture, &mExtractRect, &mPasteRect);

	// update screen per frame
	SDL_RenderPresent(mRenderer);
}

Game::~Game() {
	// destroy window
	SDL_DestroyWindow(mWindow);

	// destroy renderer
	SDL_DestroyRenderer(mRenderer);

	// quit SDL subsystems
	SDL_Quit();
}

Your handleEvents method is invalid — instead of if, use while and process all pending events. By the way, you can load the file into texture directly (without touching surfaces), using for example IMG_LoadTexture function. All you need are the renderer and filename.

2 Likes

It seems to work for me (after adding the png and code that is missing).

You might want to check if IMG_Load/IMG_LoadTexture returns a null pointer to make sure that dino_00.png is found and loaded correctly.

Note that SDL_GetError is a function so you need parentheses to call it.

cout << "SDL Error: " << SDL_GetError();
                                     ^^
1 Like

I made the changes you mentioned, it did return a null and the problem was that sdl wasn’t able to open the .png file; So, I gave it the absolute image path and it works now. Thanks a ton!

Thanks for the suggestion! I’m actually a novice and am learning from a book, I’ll definitely implement IMG_LoadTexture when I level-up my grasp on SDL.

You don’t have to wait with learning new things. Instead of this:

// create texture from surface
SDL_Surface* tempSurface = IMG_Load("dino_00.png");
mTexture = SDL_CreateTextureFromSurface(mRenderer, tempSurface);
SDL_FreeSurface(tempSurface);

do this:

mTexture = IMG_LoadTexture(mRenderer, "dino_00.png");

and the result will be the same (file loaded into texture) but less code to write. :wink:

1 Like

That’s solid advice, It works! Thank you!!
Could you also suggest a book/source for learning SDL…I’m currently reading “SDL Game Development” but there’s some sections that I can’t figure out. Thanks again.

I’m not familiar with SDL books, especially since I use it in conjunction with Free Pascal, which is not very popular.

The first thing to do is to read the documentation of this library — just go to the documentation site, check what functions this library provides, what these functions do, what parameters they require, how to use them. So first look around and find out what SDL can do, and then try to imagine what you can use these functions for (what you can build from them). SDL is low-level, but very easy to use, which is its great advantage.

Links to documentation and well-known tutorials are provided above, but if you want to know how to do something, always use Google — there is a lot of sensible material to help you. If you need anything, you can ask here on the forum, as well as on SDL’s Discord.

1 Like

Thank you for the input!

My player stops being displayed after a minute or 2.
Here’s Setup.h file :-

#pragma once
#include<SDL.h>
#include<SDL_image.h>
#include<iostream>
using namespace std;

SDL_Window* gWindow = 0;
SDL_Renderer* gRenderer = 0;

class Setup {
private:
	bool mRunning = false;
public:
	void init(const char*, int, int, int, int, int);
	void handleEvent();
	void render_clear();
	void render();
	void clean();

	bool running() { return mRunning; }
};

void Setup::init(const char* title, int x, int y, int w, int h, int flags) {
	if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
		// create window
		gWindow = SDL_CreateWindow(title, x, y, w, h, flags);
		if(gWindow != NULL) {
			// create renderer
			gRenderer = SDL_CreateRenderer(gWindow, -1, 0);
		}
		mRunning = true;
	}
	else {
		cout << "SDL Error: " << SDL_GetError();
		mRunning = false;
	}
}

void Setup::handleEvent() {
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_QUIT:
			mRunning = false;
			break;

		default:
			break;
		}
	}
}

void Setup::render_clear() {
	SDL_RenderClear(gRenderer);
}

void Setup::render() {
	SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 1);
	SDL_RenderPresent(gRenderer);
}

void Setup::clean() {
	SDL_DestroyWindow(gWindow);
	SDL_DestroyRenderer(gRenderer);
	SDL_Quit();
}

Here’s the TextureManager.h file :-

#pragma once
#include<SDL.h>
#include<iostream>
#include<map>
#include"Setup.h"
using namespace std;

class TextureManager {
private:
	map<string, SDL_Texture*> m_textureMap;
public:
	void load_texture(const char*, string);
	void draw_tile(int, int, int, int);
	void draw_texture(int, int, string);
};

void TextureManager::load_texture(const char* path, string id) {
	SDL_Texture* m_texture = 0;
	m_texture = IMG_LoadTexture(gRenderer, path);
	m_textureMap[id] = m_texture;
}

void TextureManager::draw_tile(int x, int y, int w, int h) {
	SDL_Rect rect;
	rect.x = x;
	rect.y = y;
	rect.w = w;
	rect.h = h;

	SDL_SetRenderDrawColor(gRenderer, 28, 108, 139, 1);
	SDL_RenderDrawRect(gRenderer, &rect);
	SDL_RenderFillRect(gRenderer, &rect);
}

void TextureManager::draw_texture(int x_pos, int y_pos, string id) {
	SDL_Rect src;
	SDL_Rect dest;

	//src.x = (24 * 4) * int((SDL_GetTicks() / 100) % 4);
	src.x = 0;
	src.y = 0;
	src.w = (24 * 4);
	src.h = (24 * 4);

	dest.x = x_pos;
	dest.y = y_pos;
	dest.w = src.w;
	dest.h = src.h;

	SDL_RenderCopy(gRenderer, m_textureMap[id], &src, &dest);
}

Change the Setup::handleEvent to this:

void Setup::handleEvent() {
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_QUIT:
			mRunning = false;
			break;
		}
	}
}

Currently if the event is different that the SDL_QUIT, the loop is terminated, so it does not process any events.

1 Like

This is not right. The break in the default label breaks out of the switch, not the loop.

default: break; is a common way to silence “enumeration value not handled in switch” warnings.

3 Likes

It’s very difficult to debug without all the code that is necessary to compile and run the program and to reproduce the problem.

Preferably would be if you posted a “minimal reproducible example”.

1 Like

I called the loadTexture func in the while loop so, it created a texture every second resulting in memory leak. I placed it outside the game loop and the problem’s solved. Thank you for your replies!

If I declare renderer pointer as global it throws me the following error:

However when I declare it as static pointer variable, like so:

static SDL_Renderer* renderer;

I can use them in any file without any errors. Can someone explain why’s that so…?

Remember, you’re allowed to declare a variable as many times as you like but your are (usually) not allowed to define a variable more than once.


If you declare a variable outside of any function or class without using static then you’re defining a variable with external linkage.

int foo; // defines a variables named foo with external linkage

If you do this inside a .cpp file then it’s usually not a problem because the content of that file will only be compiled once.

But if you do this inside a header file then it will get defined in all the .cpp files that includes it which will lead to multiple definitions.


What you could do is declare it in a header file using extern

extern int foo; // declares a variables named foo with external linkage (without defining it)

and define it in a .cpp file as normal. Then the .cpp files could just include the header file if they want to use the variable.


Since C++17 there is also another alternative. You could define it as an inline variable. Then multiple definitions will be allowed.

inline int foo; // defines a variables named foo with external linkage (multiple definitions allowed)

If you do this you must make sure that you always define the variable the same way. You should for example not define it as an int in one .cpp file and as float in another .cpp file. That could lead to trouble and the compiler might not complain. This is not a problem if you only define it once in one of your header files. This is no different from how it works with inline functions.


If you do what you did, using static, then it will define a variable with internal linkage.

static int foo; // defines a variables named foo with internal linkage

This means that if you put this into a header file then each .cpp file that includes it will get it’s own copy of the variable. This is probably not what you want.

1 Like

I just want to declare my renderer once like:
SDL_Renderer* renderer = nullptr; renderer = SDL_CreateRenderer(window);
And, use this same renderer in different .cpp files. What should I do?
If I understand you correctly, you want me to use extern right?

Put extern SDL_Renderer* renderer; in the header file.
Put SDL_Renderer* renderer = nullptr; in the .cpp file.

1 Like

Did just that, it works. Thanks a lot!