Elementary inquiry about C++ (SDL2 library) - c++

I'm fairly new to programming, so this question will probably be basic. I'm writing a very basic program in C++ with the SDL2 library (in Visual Studio 2013). When I was writing it, I came across a problem. I wrote the following:
int controles(){
//declare actions that will happen when a key is pressed
const Uint8 * estado = SDL_GetKeyboardState(NULL);
if (estado[SDL_SCANCODE_UP]){ y--; SDL_UpdateWindowSurface(ventana); }
if (estado[SDL_SCANCODE_DOWN]){ y++; SDL_UpdateWindowSurface(ventana); }
return 0;
}
The problem is that I need to update the window surface after the value of y is modified, but I get an error because ventana, the name of the window, is defined in another function. I tried to define ventana globally, but the program won't work then. I then thought the following; write a goto statement in graficos, the function where ventana is defined, in order to skip every other statement in that function, except for the one that updates the window surface. However, when I did that, the program doesn't even compile:
int graficos(int caso){
if (caso == 1) {goto reload;} //skip to reload if (1)
SDL_Init(SDL_INIT_VIDEO); //load SDL
//load graphics in memory
SDL_Window * ventana = SDL_CreateWindow("ventana", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Surface * superficie = SDL_GetWindowSurface(ventana);
SDL_Surface * pantallainicio = SDL_LoadBMP("pantallainicio.bmp");
SDL_Surface * paleta = SDL_LoadBMP("paleta.bmp");
SDL_Rect rpantallainicio = { 0, 0, 640, 480 };
SDL_Rect rpaleta = { x, y, 16, 16 };
//render graphics
SDL_BlitSurface(pantallainicio, NULL, superficie, &rpantallainicio);
SDL_BlitSurface(paleta, NULL, superficie, &rpaleta);
SDL_UpdateWindowSurface(ventana);
reload:SDL_UpdateWindowSurface(ventana);
return 0;
}
I get the following errors:
error C4533: initialization of 'rpaleta' is skipped by 'goto reload'
error C4533: initialization of 'rpantallainicio' is skipped by 'goto reload'
I hope I explained my issue well enough. What can I do? Is there a way to fix this? Or can I reference ventana in some other way? This issue might be very basic, sorry for that, and thanks in advance!

You can fix this issue by simply not using goto at all - use a sub-function instead. Also, extract the variable ventana, as you need it to be stored and usable by graficos whenever.
void init()
{
SDL_Init(SDL_INIT_VIDEO); //load SDL
//load graphics in memory
ventana = SDL_CreateWindow("ventana", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Surface * superficie = SDL_GetWindowSurface(ventana);
SDL_Surface * pantallainicio = SDL_LoadBMP("pantallainicio.bmp");
SDL_Surface * paleta = SDL_LoadBMP("paleta.bmp");
SDL_Rect rpantallainicio = { 0, 0, 640, 480 };
SDL_Rect rpaleta = { x, y, 16, 16 };
//render graphics
SDL_BlitSurface(pantallainicio, NULL, superficie, &rpantallainicio);
SDL_BlitSurface(paleta, NULL, superficie, &rpaleta);
}
int graficos(int caso)
{
if (caso != 1) { init(); } //skip to reload if (1)
SDL_UpdateWindowSurface(ventana);
return 0;
}
SDL_Window * ventana;
Use of goto should generally be avoided. Use subroutines or other alternatives where possible. Here, the code does exactly the same thing as originally intended, but the "extra" flow that occurs when caso is not 1 is wrapped in its own subroutine named 'init'.

Related

SDL_RenderCopy not doing anything

I'm calling SDL_RenderCopy and it gets called and returns normally but doesn't draw anything to the window. Edited to make the question and code clearer. I'm thinking I might be trying to use something beyond its scope and hence it can't be called but this doesn't produce any error so I'm not sure. Here's the simple picture I refer to https://commons.wikimedia.org/wiki/Category:PNG_chess_pieces/Standard_transparent#/media/File:Chess_kdt60.png
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
// Recreation of the problem. Doesnt draw anything onto the white screen.
class King{
public:
King(SDL_Renderer *renderer){
SDL_Surface *Piece;
Piece = IMG_Load("Pieces/BK.png"); // I'll attach the picture
king = SDL_CreateTextureFromSurface(renderer, Piece);
SDL_FreeSurface(Piece);
kingRect.h = 100;
kingRect.w = 100;
}
~King(){}
void render(SDL_Renderer *renderer){
SDL_RenderCopy(renderer, king, NULL, &kingRect); // 99% sure the problem is this
}
private:
SDL_Texture *king;
SDL_Rect kingRect;
};
class Game {
public:
Game(const char *title, int sidelength){
isRunning = true;
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) isRunning = false;
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, sidelength, sidelength, SDL_WINDOW_OPENGL);
if(window == NULL) isRunning = false;
renderer = SDL_CreateRenderer(window, -1, 0);
if(!renderer) isRunning = false;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
}
~Game(){}
void handleEvents(){
//Handles Events. I know this works.
}
}
void update(){};
void render(){
SDL_RenderClear(renderer);
BK.render(renderer);
SDL_RenderPresent(renderer);
}
void clean(){
//Cleans up after. I know this works.
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
}
bool running(){return(isRunning);}
King BK{renderer};
private:
bool isRunning{true};
SDL_Window *window;
SDL_Renderer *renderer;
};
Game *game = nullptr;
int main(int argc, const char *argv[]){
game = new Game("Testing Window", 800);
while(game->running()){
game->handleEvents();
game->update();
game->render();
}
game->clean();
return(0);
}
King BK{renderer}; field gets initialised before your Game::Game finishes and gets a chance to assign a renderer, so it gets NULL instead. NULL is not a valid renderer and can't create textures. If you would have checked for error you would have got Invalid renderer message. Also decent compiler with enabled warnings will tell something like warning: 'Game::renderer' is used uninitialized in this function [-Wuninitialized]; consider enabling better warning levels in your compiler.
Second thing is that you never called IMG_Init with required image formats you intend to load.
Third thing is that code is misformatted and wouldn't compile without modifications. I suggest testing code that you post as MCCVE for still being compilable and reproducing your problem (as MCCVE implies).

C++ - passing a pointer to a function and using it as an argument to another function

i am currently reentering programming in C++ to write a small game. I am using Visual Studio 2017 and SDL2. I am following a series of tutorials to get into SDL. My problem seems to be related to me not entirely understanding the workings of pointers in c++. I am passing a pointer to a function as an argument and want to use it within this function as an argument to another function which returns a pointer to a SDL_Surface. Following my code:
init SDL:
SDL_Surface* init(SDL_Window *window)
{
SDL_Surface *screenSurface = nullptr;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("%s", "Error in init");
}
else
{
screenSurface = SDL_GetWindowSurface(window);
}
return screenSurface;
}
load bmp:
SDL_Surface* loadMedia(const char file[])
{
SDL_Surface *image = SDL_LoadBMP(file);
if (image == nullptr)
{
printf("%s", "Error in loadMedia");
}
return image;
}
main:
int main(int argc, char *argv[])
{
SDL_Window *window = SDL_CreateWindow("xyz", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Surface *screenSurface = init(window);
if (screenSurface == nullptr)
{
printf("%s", "surface is null");
}
SDL_Surface *image = loadMedia("resources/images/village.bmp");
SDL_BlitSurface(image, NULL, screenSurface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(1000);
SDL_FreeSurface(image);
image = nullptr;
SDL_DestroyWindow(window);
window = nullptr;
SDL_Quit();
return 0;
}
if i create
SDL_Window *window = SDL_CreateWindow("xyz",...)
as a global variable and initialize it within init(), everything works fine and screenSurface is initialized with a valid value. As soon as i do as it is in the code, pass the pointer window to init() to create the surface there and then return screenSurface, screenSurface = SDL_GetWindowSurface(window) returns null.
I have been programming mostly SAS and Java the last years and didnt touch c++ for several years, so im sure its just a minor misunderstanding on my side but i cannot figure out what it is.
Thx in advance :)

SDL Pong Movement Bug

The problem with my code is that I am making a pong game in SDL 2.0 in c++. I did everything until creating the movement. When the player paddle moves, it leaves behind a trail in the same color as the paddle. I watched some videos on YouTube, but when they do the movement it's nice and clear and for me to fix this but I need to recolor the background every time the player moves, which makes it being all flashy and if I hold the button I don't see the paddle at all.
#include<iostream>
#include<SDL2/SDL.h>
#include<SDL2/SDL_image.h>
#include<windows.h>
#define width 800
#define height 600
using namespace std;
bool run = true;
class Player{
private:
SDL_Window* window = SDL_CreateWindow("Pong!", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE);
SDL_Surface* Screen = SDL_GetWindowSurface(window);
Uint32 screen_color = SDL_MapRGB(Screen->format, 0, 0, 0);
Uint32 In_game_RGB = SDL_MapRGB(Screen->format, 255, 255, 255);
SDL_Rect Pl;
SDL_Rect AI;
SDL_Rect Ball;
SDL_Rect ClearP;
SDL_Rect ClearAI;
public:
Player(){
//Player parameters
Pl.x = 60;Pl.y = 225;Pl.w = 25;Pl.h = 200;
//AI parameters
AI.x = 720;AI.y = 225;AI.w = 25;AI.h = 200;
//Ball parameters
Ball.x = width/2;Ball.y = height/2+10;Ball.w = 25;Ball.h = 25;
//Recoloring parameters
ClearP.x = 0;ClearP.y = 0; ClearP.w = 375;ClearP.h = height;
ClearAI.x = 425;ClearAI.y = 0;ClearAI.w = 375;ClearAI.h = height;
//Make the screen color black
SDL_FillRect(Screen, NULL, screen_color);
}
void scrUpdate(){
SDL_UpdateWindowSurface(window);
}
void drawPlayer(){
SDL_FillRect(Screen, &Pl, In_game_RGB);
}
void drawComputer(){
SDL_FillRect(Screen, &AI, In_game_RGB);
}
void ball(){
SDL_FillRect(Screen, &Ball, In_game_RGB);
}
void Movement(){
if(GetAsyncKeyState(VK_DOWN)){
Pl.y += 2;
SDL_FillRect(Screen,&ClearP,screen_color);
}
if(GetAsyncKeyState(VK_UP)){
SDL_FillRect(Screen,&ClearP,screen_color);
Pl.y -= 2;
}
}
};
void EventCheck(){
SDL_Event event;
if(SDL_PollEvent(&event)){
if(event.type == SDL_QUIT){
run = false;
}
}
}
int main( int argc, char *argv[] )
{
SDL_Init(SDL_INIT_EVERYTHING);
Player Play;
//Player Computer();
while(run){
Play.scrUpdate();
Play.drawPlayer();
Play.drawComputer();
Play.ball();
Play.Movement();
EventCheck();
}
SDL_Quit();
return EXIT_SUCCESS;
}
It would help to show some code or an example of what you have been doing, or a link to one of the videos you have been watching:
Youtube tutorial
but I suggest taking a look at:
screen = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE); and SDL_Flip(screen) as those have to do with screen buffering and drawing.
Another possibilty is that you are running an outdated version of SDL, or an incompatible one with your current system.
To be able to give a more complete and proper answer, I'd highly suggest adding more information about your code, screenshots of results and your version of SDL and operating system.
Also, you said it was flashy when you hold the paddle. I think it must be that you are performing your logic to move the paddle and you redraw the paddle once it's still. If you are redrawing the entire screen constantly, consider double buffering.

SDL will only draw a black screen when trying to print a picture C++

class Game {
public:
Game(int width, int height) {
gwidth = width;
gheight = height;
}
~Game() {
}
bool initGame() {
bool sucsess = true;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
sucsess = false;
}
//gTetrisSurface = SDL_LoadBMP("TetrisBg.bmp");
gWindow = SDL_CreateWindow("Petris V1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gwidth, gheight, SDL_WINDOW_SHOWN);
gScreenSurface = SDL_GetWindowSurface(gWindow);
gMainBG = SDL_LoadBMP("test.bmp");
/**if (gMainBG == NULL) {
return false;
}**/
bool running = true;
//SDL_SetWindowFullscreen(gWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
while (running == true) {
SDL_BlitSurface(gMainBG, NULL, gScreenSurface, NULL);
SDL_UpdateWindowSurface( gWindow );
}
return sucsess;
}
protected:
int gwidth, gheight;
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
SDL_Surface* gTetrisSurface = NULL;
SDL_Surface* gPongSurface = NULL;
SDL_Surface* gMainBG = NULL;
};
The thought behind this, is that this should be one huge surface, containing 2 other surfaces for 2 other games. Problem is, it wont seem to draw the BMP that i try to draw on it. Because of this my development got kinda stuck. Anyone see a possible sulotion for this problem? Thanks!
EDIT: I made it so it flushes the events, BUT, i did a bit of debugging, the problem seems to be that the img file returns NULL, why? It should be loaded with a bmp... (No error messages at all..)
From the documentation of SDL2:
https://wiki.libsdl.org/SDL_GetWindowSurface
This surface will be invalidated if the window is resized. After resizing a window this function must be called again to return a valid surface.
You may not combine this with 3D or the rendering API on this window.
My advice is to avoid using the window surface directly.
Instead, you should use a renderer and copy your own main surface to your background texture.
The SDL2 migration guide explains clearly the right way to copy surfaces and textures on the screen, especially the paragraph "If your game wants to do both".
The whole problem was that the BMP file was in the wrong folder.
If anyone have the same problem, the picture should either be in the same directory as the src (when debugging) or the solution (if building).
Hope this might help someone in the future, either way, thanks to those who tried coming up with other possibilites.
(Using visual studio)

cannot display texture in SDL 2

I'm trying to display a texture onto the screen but all I'm getting is a black window.
No SDL Errors are being reported. There's a good chance that I'm missing something stupid, but I can't see it. Hopefully another set of eyes will help. Feel free to ask for more code/info.
main.cpp
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * grass;
SDL_Rect g_dst;
SDL_Event event;
Game app;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("tmp", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
g_dst.x = g_dst.y = 0;
g_dst.w = 640;
g_dst.h = 480;
grass = IMG_LoadTexture(renderer, "grass.bmp");
while (app.isRunning()) {
app.pollEvents(&event);
app.render_init();
app.render(grass, NULL, &g_dst);
app.render_end();
}
//SDL_Quit() is handled by the Game class' destructor
Game.cpp
//Only functions used for rendering are shown
void render_init(Uint8 red=0, Uint8 green=0, Uint8 blue=0, Uint8 alpha=255)
{
SDL_SetRenderDrawColor(renderer, red, green, blue, alpha);
SDL_RenderClear(renderer);
}
void render(SDL_Texture * texture, SDL_Rect * src, SDL_Rect * dest) {
SDL_RenderCopy(renderer, texture, src, dest);
}
void render_end() { SDL_RenderPresent(renderer); }
First of all, you're initializing everything? please don't do that frequently, mind you that you're also initializing MANY unnecessary stuffs like for game controllers, etc. if the app gets bigger then the efficiency and the possibility of this app running at a smoot speed is at stake.
I also noticed that you are declaring variables in the .cpp file, do that in the header file and just recall the header to the cpp file that will be using it.
You want to render the grass right? and render it as much as the screens size.
(I'll just assume that you used this in the game.cpp part, which is the very first file, thus, not regarding any classes made)
int winWidth = 680; //The reason for this is just in case you make the window resizable
int winHeight = 480; //then the texture would also resize along with the window
SDL_Window *window = window = SDL_CreateWindow("The Space Project", 100, 100, winWidth, winHeight, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = NULL; //I've set this to NULL so that we can know if
the reason as to why your image is not rendering is because the renderer is not properly working.
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
if(renderer == NULL)
{
cout >> "Renderer is not working" >> endl;
//This shows a line at the command prompt that your renderer doesn't have any output, thus, only having a NULL as an equivalent
}
SDL_Texture* grass= NULL;
grass= IMG_LoadTexture(renderer, "grass.bmp"); //As you can see, I've set the grass to Null again
if(grass == NULL)
{
cout >> "Grass have failed to initialize" >> endl;
/*I don't normally do this but it's very important if you really need trouble shooting guides
but this time, were here to check IF the grass.bmp entered the SDL_Texture grass, so if the system can't find the .bmp file then it would show this error
since the grass (SDL_Texture) still doesn't have anything inside it (NULL)*/
}
SDL_Rect grass_rect;
grass_rect.x = 0;
grass_rect.y = 0;
grass_rect.w = winWidth;
grass_rect.h = winHeight;
//Loop part, I'll skip some of it
while (!quit && mainEvent->type != SDL_QUIT) //!quit is just an imaginary Boolean I've typed)
{
SDL_PollEvent(mainEvent); //Let's say you created the event already
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass, NULL, &grass_rect);
//The NULL part is also similar to a rect but it's a limiting type, we didn't assign anything to it
since I assumed that you wanted the whole image to be rendered
SDL_RenderPresent(renderer);
}
I revised the code and made it more efficient since your code called for useless extras which might result in lower performance.
I also notice that you tried calling for color changes?
use this
SDL_SetTextureColorMod(texture, red-value, green-value, blue-value);
and put it in the loops part under the render present of the same texture.
SDL_SetTextureColorMod(grass, 250, 250, 250);
Doing this would set all color values to 250, thus, having a white color, this change your texture color to white.
You're also wasting space on making the app.is running(), you could easily replace it with a boolean, which consumes much less space or you could omit it if you don't have an exit button inside the application and just make your loop read the SDL_QUIT, this saves space for the file, mind the efficiency.
If this still doesn't work then try replacing the image your using, make a simple one on paint name it something like "grass.png" or anything then try it again.
Don't forget to put the file in the proper folder, in the DEBUG folder if you haven't specified a folder, and also put it in the app folder so it would also read it when it executes as an .exe file and not as part of the debug command.