I am currently learning SDL2 and just managed to create a ping pong game. Some friends told me that I should start using classes for managing as an example player1 and player2. I know how to create a class but I do not understand how I would be able to pass SDL_Renderer between classes in order to render an object from within the class to the main.cpp file.
#include "SDL2/SDL.h"
#include "SDL2/SDL_render.h"
#include <iostream>
#include <windows.h>
#include <thread>
#include "player.h"
Player Player; //defining the class
const int WINDOW_WIDTH = 1280;
const int WINDOW_HEIGHT = 720;
int main(int argc, char *args[]) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window;
SDL_Renderer *renderer;
window = SDL_CreateWindow ("Test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WINDOW_WIDTH,
WINDOW_HEIGHT,
0
);
if (window == NULL) {
std::cout << "Window could not load" << SDL_GetError() << std::endl;
return 0;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
while (running) //running is a bool (true) {
Player.draw();
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
What do I have to do in my player.cpp draw function in order to draw an object on the screen?
Using C++ windows, compiling the code with g++ main.cpp player.cpp -o main.exe -IC:\MinGW\i686-w64-mingw32\include -LC:\MinGW\i686-w64-mingw32\lib -lmingw32 -lSDL2main -lSDL2
In main.cpp
Player.draw(renderer)
(presuming you are using the same code as above, just pass "renderer" to the Player.draw() function.)
In player.h
class Player {
public:
void draw(SDL_Renderer *renderer)
};
In player.cpp
void Player::draw(SDL_Renderer *renderer) {
SDL_Rect object;
object.x = 0;
object.y = 0;
object.h = 10;
object.w = 10;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &object);
SDL_RenderFillRect(renderer, &object);
}
// will draw a white box with at position (0,0)
I believe this is a simple way to do it
Related
I have a C++ project where I'm initially trying to display a PNG image to the screen.
This is my code.
RenderWindow.hpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
class RenderWindow
{
public:
RenderWindow(const char *p_title, int p_width, int p_height);
void render();
void cleanUp();
private:
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Surface *image = IMG_Load("~/SDL2_Game/images/Green_Tile.png");
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, image);
};
RenderWindow.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "RenderWindow.hpp"
RenderWindow::RenderWindow(const char* p_title, int p_w, int p_h):window(NULL), renderer(NULL)
{
window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if (window == NULL) std::cout << "Window failed to init: " << SDL_GetError() << std::endl;
renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
}
void RenderWindow::render(){
SDL_RenderClear(renderer);
//SDL_Rect dstrect = { 5, 5, 320, 240 };
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
void RenderWindow::cleanUp(){
SDL_DestroyTexture(texture);
SDL_FreeSurface(image);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "RenderWindow.hpp"
int main(int argc, char** argv){
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cout << "Problem with initialization. " << SDL_GetError() << std::endl;
}
else {
std::cout << "Initialization success!" <<std::endl;
}
if (!IMG_Init(IMG_INIT_PNG)){
std::cout << "Problem with Image initialization " <<SDL_GetError() << std::endl;
}
RenderWindow win("RPG_Game_v_1.0", 800, 600);
win.render();
bool gameRunning = true;
SDL_Event event;
while(gameRunning){
while(SDL_PollEvent(&event)){
if (event.type == SDL_QUIT) gameRunning = false;
}
}
win.cleanUp();
IMG_Quit();
SDL_Quit();
return 0;
}
I'm on a Linux machine.
I compile this with
g++ -g -o game ./*.cpp -lSDL2main -lSDL2 -lSDL2_image
Only a window is displaying. There is no image. I've tried refactoring my code with SDL_BlitSurface() and it does indeed display the PNG image. But why is this code not working? is it due to the fact that I'm using SDL_Texture* and my current system does not have a discrete graphics card?
I think that the call to SDL_CreateTextureFromSurface fails because it is called before SDL_CreateWindow and SDL_CreateRenderer, thereby initializing texture to NULL.
Please move the initizalization of texture (and image) to after window and renderer are initialized.
To further help with such issues, please check if the result of SDL functions != NULL and print SDL_GetError() to get more information about what went wrong.
I have been trying to make a pong clone as a first c++ "big" project, and I am encountering several problems.
First of all, this is my code so far:
game.hpp:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <iostream>
class Game
{
public:
Game();
~Game();
// GAME VARIABLES
const int WIDTH=720, HEIGHT=720, FONT_SIZE=32;
int running, lastTime;
int frameCount, timerFPS, lastFrame, fps;
// GAME TOOLS
SDL_Window *window;
SDL_Renderer *renderer;
TTF_Font *font;
SDL_Color color;
// GAME OBJECTS:
SDL_Rect rPaddle, lPaddle, Ball, scoreBoard;
// GAME FUNCTIONS:
void initRects(); // AFTER YOU HAVE A WORKING VERSION, TRY TO MOVE TO CONSTRUCTOR
void render();
void run();
};
game.cpp:
#include "game.hpp"
Game::Game()
{
running = 1;
if(SDL_Init(SDL_INIT_EVERYTHING)<0)
std::cerr << "SDL FAILED: SDL_INIT_EVERYTHING: " << SDL_GetError() << std::endl;
if(SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, 0, &window, &renderer)<0)
std::cerr << "SDL FAILED: SDL_CreateWindowAndRenderer: " << SDL_GetError() << std::endl;
TTF_Init();
font = TTF_OpenFont("PreschoolBits.ttf", FONT_SIZE);
color.r=color.g=color.b=255;
}
Game::~Game()
{
TTF_CloseFont(font);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
}
void Game::initRects()
{
lPaddle.x=32; lPaddle.h=HEIGHT/5;
lPaddle.y=(HEIGHT/2)-(lPaddle.h/2);
lPaddle.w=12;
rPaddle=lPaddle;
rPaddle.x=WIDTH-rPaddle.w-32;
Ball.w=Ball.h=16;
}
void Game::render()
{
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
frameCount++;
timerFPS=SDL_GetTicks()-lastFrame;
if(timerFPS<(1000/60))
SDL_Delay(timerFPS<((1000/60)-timerFPS));
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 0);
SDL_RenderFillRect(renderer, &lPaddle);
SDL_RenderFillRect(renderer, &rPaddle);
SDL_RenderFillRect(renderer, &Ball);
SDL_RenderPresent(renderer);
}
void Game::run()
{
initRects();
while(running)
{
lastFrame=SDL_GetTicks();
if(lastFrame>=(lastTime+1000))
{
lastTime=lastFrame;
fps=frameCount;
frameCount=0;
}
render();
SDL_Delay(2000);
running=0;
}
}
pong.cpp:
#include "game.hpp"
int main()
{
Game game;
game.run();
return 0;
}
Now, when I try to render the render the rectangles, they don't show up. So I tried to remove them and just render colors on screen.
Both before and after the SDL_RenderClear I wrote:
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
But the window still showed up black, no matter what I tried.
What could I be doing wrong?
To make a filled Rect you must create a rect object:SDL_Rect MyRectName, Set its values to whatever you want:MyRectName.(w,h,x,y) = MyValue, and then to render, run SDL_RenderFillRect(MyRenderer, MyRectName);.
I'm learning the basics of creating a window using SDL2 by following a tutorial. The code works just fine, and even compiles correctly, however on runtime it gives the error message 'Assertion failure at SDL_RenderClear_REAL'.
I've tried reinstalling SDL2, as well as moving it to the user library folder on my mac, but neither of these fixed the issue
main.cpp
#include "game.hpp"
Game *game = nullptr;
int main() {
game = new Game();
game->init("GUI", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, false);
while (game->running()) {
game->handleEvents();
game->update();
game->render();
}
game->clean();
return 0;
}
game.cpp
#include "game.hpp"
Game::Game(){}
Game::~Game(){}
void Game::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen) {
int flags = 0;
if (fullscreen == true) {
flags = SDL_WINDOW_FULLSCREEN;
}
if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
std::cout << "Sub-systems initialized\n";
window = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
if (window) {
std::cout << "Window created.\n";
}
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer) {
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
std::cout << "Renderer created\n";
}
isRunning = true;
} else {
isRunning = false;
}
}
void Game::handleEvents() {
SDL_Event event;
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
isRunning = false;
break;
default:
break;
}
}
void Game::update() {
cnt++;
std::cout << cnt << "\n";
}
void Game::render() {
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
void Game::clean() {
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
std::cout << "Game cleaned\n";
}
game.hpp
#ifndef game_hpp
#define game_hpp
#include "SDL2/SDL.h"
#include <iostream>
class Game {
public:
Game();
~Game();
void init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
void handleEvents();
void update();
void render();
void clean();
bool running() { return isRunning; }
private:
int cnt = 0;
bool isRunning;
SDL_Window *window;
SDL_Renderer *renderer;
};
#endif
After narrowing down the code, it seems that the issue is limited to SL_RenderClear. Here's the exact message it produces in the console:
2019-08-20 15:26:15.508900-0500 GUI[26436:7287503] WARN:
Assertion failure at SDL_RenderClear_REAL (/Users/valve/release/SDL/SDL2-2.0.10-source/src/render/SDL_render.c:2235), triggered 1 time:
'renderer && renderer->magic == &renderer_magic'
Program ended with exit code: 42
How can I fix this issue?
EDIT: Added full code to help identify the problem.
A basic "hello world" of creating a window and clearing the color on the screen for SDL requires a few boilerplate initialization steps
Initialize SDL
Create a SDL_Window
Create a SDL_Renderer
After which you can do
SDL_RenderClear and use SDL_RenderDrawColor to set a custom color to make it more obvious that it is properly clearing the Renderer.
Without error checking this would look something like:
SDL_Init(flags);
SDL_Window* window = SDL_CreateWindow("window title", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, more_flags);
SDL_SetRenderDrawColor(renderer, red, green, blue, alpha);
SDL_RenderClear(renderer);
Also remember to call SDL_Delay(ms) if you want the program to not immediately close before you get a chance to see the window.
I'm trying to render a SDL_Rect in a class, I send the renderer to the "draw" function of my class, and then render it from there.
void Tray::draw(SDL_Renderer *renderer){
SDL_RenderFillRect(renderer, &bckRect);
}
When I put the same code on my main loop. All goes fine, but when I do this from my tray class, It compiles, but doesn't run.
Simplified code:
main.cpp
#include <iostream>
#include <SDL2/SDL.h>
// local includes
#include "editor.h"
using namespace std;
int main(int argc, const char * argv[]) {
Editor *editor = new Editor();
while (editor->running){
editor->render();
}
editor->clean();
return 0;
}
editor.h
#ifndef EDITOR_H
#define EDITOR_H
#include <iostream>
#include <SDL2/SDL.h>
#include "Gui-classes/tray.h"
#include "properties.h"
class Editor{
private:
// Window variables
SDL_Window *window;
SDL_Renderer *renderer;
Tray *tray;
public:
Editor();
~Editor();
void render();
};
#endif
editor.cpp
#include "editor.h"
Editor::Editor(){
props = new Properties();
if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {
window = SDL_CreateWindow("Great Editor", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1000, 600, SDL_WINDOW_RESIZABLE);
running = true;
if (window) {
std::cout << "Window created!" << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, 0);
}
}
void Editor::render(){
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 12, 12, 55, 255);
tray->draw(renderer);
SDL_RenderPresent(renderer);
}
void Editor::clean(){
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
std::cout << "Window ended" << std::endl;
}
tray.h
#ifndef TRAY_H
#define TRAY_H
#include <iostream>
#include <SDL2/SDL.h>
class Tray{
private:
// Position variables
int x;
int y;
int w;
int h;
//Display variables
SDL_Color color;
SDL_Rect bckRect;
public:
Tray();
~Tray();
void draw(SDL_Renderer *renderer);
};
#endif
Tray.cpp
#include "tray.h"
Tray::Tray(){
bckRect.x = x;
bckRect.x = y;
bckRect.w = w;
bckRect.h = h;
}
Tray::~Tray(){
}
void Tray::draw(SDL_Renderer *renderer){
SDL_RenderFillRect(renderer, &bckRect);
//std::cout << "teeest" << std::endl;
}
Thanks for the help.
so I was following this tutorial, and everything was going all smooth and dandy, until I encountered a problem, namely that I couldn't load a .bmp.
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include <iostream>
#include <SDL2/SDL_main.h>
using namespace std;
int main(int argc, char* argv[]) {
bool quit = false;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
window = SDL_CreateWindow("window", 100, 100, 1280, 720, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if(window == NULL){
cout << "Disn't work, here is why: " << SDL_GetError()<< endl;
return 0;
}
SDL_Renderer* renderer = NULL;
renderer= SDL_CreateRenderer(window, -1 ,SDL_RENDERER_ACCELERATED);
SDL_Event* mainEvent = new SDL_Event();
SDL_Texture* grass_image = NULL;
grass_image = IMG_LoadTexture(renderer, "grass.bmp");
SDL_Rect grass_rect;
grass_rect.x = 10;
grass_rect.y = 50;
grass_rect.w = 250;
grass_rect.h = 250;
while(!quit && mainEvent->type != SDL_QUIT){
SDL_PollEvent(mainEvent);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass_image, NULL, &grass_rect);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
delete mainEvent;
return 0;
}
When I try to compile the code (in Code::Blocks) it gives me the error of
Undefined reference to "IMG_LoadTexture"
Well, I tried to change IMG_LoadTexture(renderer, "grass.bmp"); to IMG_LoadTexture(renderer, "/the/full/path/of/grass.bmp");but this didn't work either. Same error. Have I written something wrong, or missed some part? Also, grass.bmp is in the same folder as main.cpp (the code above).
The error here says that you have declared a function but have not defined it - undefined reference.
Most probably it happened because you forgot to link against library SDL_image to which function IMG_LoadTexture belongs.