SDL2 cannot render entities from vector - c++

Rendering individual textures was no problem at all, though after i wrapped these textures in an entity class, and put these in a vector, things just didn't work anymore (renders black screen). Anyone got a clue why?
main.cpp
#include "RenderWindow.hpp"
#include "vec.h"
#include "entity.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) > 0) {
std::cout << "Could not Init VIDEO, Error: " << SDL_GetError() << std::endl;
return 0;
}
if (!IMG_Init(IMG_INIT_PNG)) {
std::cout << "Could not Init IMG, Error: " << SDL_GetError() << std::endl;
return 0;
}
RenderWindow r("Bread.", 600, 600);
// entity vector
std::vector<Entity> entities = {Entity(Vec2i{5, 5}, r.CreateTexture("res/gfx/bob.png"))};
// single entity
Entity bob(Vec2i{5, 5}, r.CreateTexture("res/gfx/bob.png"));
bool running = true;
SDL_Event event;
while (running) {
Uint64 start = SDL_GetPerformanceCounter();
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
}
r.Clear();
// doesn't render (black screen)
for (const Entity& e : entities) {
r.RenderEntity(e);
}
// renders fine
r.RenderEntity(bob);
r.Display();
Uint64 end = SDL_GetPerformanceCounter();
float elapsedMS = (end - start) / (float)SDL_GetPerformanceFrequency() * 1000.0f;
SDL_Delay(floor(16.666f - elapsedMS));
}
return 0;
}
RenderWindow.cpp
#include "RenderWindow.hpp"
#include <iostream>
RenderWindow::RenderWindow(const char* p_title, int32_t p_w, int32_t p_h)
: window(NULL), renderer(NULL) {
this->window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if (this->window == NULL) {
std::cout << "Failed to initialize window, Error: " << SDL_GetError() << std::endl;
}
this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED);
if (this->renderer == NULL) {
std::cout << "Failed to initialize renderer, Error: " << SDL_GetError() << std::endl;
}
}
RenderWindow::~RenderWindow() {
SDL_DestroyWindow(this->window);
SDL_DestroyRenderer(this->renderer);
SDL_Quit();
}
SDL_Texture* RenderWindow::CreateTexture(const char* p_path) {
return IMG_LoadTexture(this->renderer, p_path);
}
void RenderWindow::Clear() {
SDL_RenderClear(this->renderer);
}
void RenderWindow::RenderTexture(SDL_Texture* p_texture) {
SDL_RenderCopy(this->renderer, p_texture, NULL, NULL);
}
// **mentioned method**
// takes const Entity& and renders it's texture
void RenderWindow::RenderEntity(const Entity& p_entity) {
SDL_RenderCopy(this->renderer, p_entity.GetTexture(), NULL, NULL);
}
void RenderWindow::Display() {
SDL_RenderPresent(this->renderer);
}
and finally entity.cpp
#include "entity.h"
Entity::Entity(Vec2i p_pos, SDL_Texture* p_texture)
: pos(p_pos), texture(p_texture) {}
Entity::Entity()
: pos(Vec2i{0, 0}), texture(NULL) {}
Entity::~Entity() {
SDL_DestroyTexture(this->texture);
}
void Entity::SetPos(Vec2i p_pos) { this->pos = p_pos; }
const Vec2i& Entity::GetPos() const { return this->pos; }
void Entity::SetTexture(SDL_Texture* p_texture) { this->texture = p_texture; }
// used to get texture of entity to pass to renderer
SDL_Texture* Entity::GetTexture() const { return this->texture; }
void Entity::Move(Vec2i p_pos) {
this->pos = p_pos;
}
void Entity::Move(size_t p_x, size_t p_y) {
this->pos.x += p_x;
this->pos.y += p_y;
}

The creation of entities requires a temporary Entity, which is destroyed afterwards. Since you did not implement a copy constructor, this leaves the new Entity with a dangling pointer to a freed object.
The quickest fix is to change the type of Entity::texture to std::shared_ptr<SDL_Texture>.
Alternatively, you can create a move constructor and prevent copy constructors:
Entity::Entity(const Entity&) = delete;
Entity::Entity(Entity&& other)
: pos(other.pos), texture(nullptr) {
std::swap(texture, other.texture);
}

Related

SDL2 Texture wont move when main loop event calls w, a, s, or d in c++

so i've been working on a game system/engine, for my 2D Platformer, and when i press the w, a, s, or d keys it won't move when called in the main loop event.
Here is all of my project files and everything that i've written:
main.cpp:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
#include "RenderWindow.hpp"
#include "Entity.hpp"
#include "Utils.hpp"
int main(int argc, char const *argv[])
{
if (SDL_Init(SDL_INIT_VIDEO) > 0)
std::cout << "ERROR: SDL_Init() HAS FAILED: SDL_ERROR => " << SDL_GetError() << std::endl;
if (!(IMG_Init(IMG_INIT_PNG)))
std::cout << "ERROR: IMG_Init() HAS FAILED: SDL_ERROR => " << SDL_GetError() << std::endl;
RenderWindow window("GAME v1.0", 1280, 720);
SDL_Texture* grassTexture = window.loadTexture("res/gfx/ground_grass.png");
SDL_Texture* playerTexture = window.loadTexture("res/gfx/ghost.png");
std::vector<Entity> platforms = {Entity(Vector2f(0, 30), grassTexture),
Entity(Vector2f(30, 30), grassTexture),
Entity(Vector2f(30, 30), grassTexture),
Entity(Vector2f(60, 30), grassTexture)};
Entity player(Vector2f(30, 8), playerTexture);
bool gameRunning = true;
SDL_Event event;
const float timeStep = 0.01f;
float accumulator = 0.0f;
float currentTime = utils::hireTimeInSeconds();
while(gameRunning)
{
int startTicks = SDL_GetTicks();
float newTime = utils::hireTimeInSeconds();
float frameTime = newTime - currentTime;
currentTime = newTime;
accumulator += frameTime;
while(accumulator >= timeStep)
{
// Get out controls and events
while(SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
gameRunning = false;
break;
// window.freeTexture(grassTexture);
// window.freeTexture(playerTexture);
}
// Add code to move the player texture
const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL);
Vector2f& playerPos = player.getPos();
if(currentKeyStates[SDL_SCANCODE_W]) {
playerPos.y -= 1;
break;
}
if(currentKeyStates[SDL_SCANCODE_S]) {
playerPos.y += 1;
break;
}
if(currentKeyStates[SDL_SCANCODE_A]) {
playerPos.x -= 1;
break;
}
if(currentKeyStates[SDL_SCANCODE_D]) {
playerPos.x += 1;
break;
}
}
window.clear();
for (Entity& e : platforms)
{
window.render(e);
window.render(player);
}
window.display();
// // Add code to move the player texture
// const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL);
// Vector2f& playerPos = player.getPos();
// if(currentKeyStates[SDL_SCANCODE_W]) {
// playerPos.y -= 1;
// }
// if(currentKeyStates[SDL_SCANCODE_S]) {
// playerPos.y += 1;
// }
// if(currentKeyStates[SDL_SCANCODE_A]) {
// playerPos.x -= 1;
// }
// if(currentKeyStates[SDL_SCANCODE_D]) {
// playerPos.x += 1;
// }
//playerPos.print();
accumulator -= timeStep;
// std::cout << accumulator << std::endl;
}
// const float alpha = accumulator / timeStep; // 50%?
// window.freeTexture(grassTexture);
// window.freeTexture(playerTexture);
int frameTicks = SDL_GetTicks() - startTicks;
if (frameTicks < 1000 / window.getRefreshRate())
SDL_Delay(100 / window.getRefreshRate() - frameTicks);
}
window.cleanUp();
SDL_Quit();
return 0;
}
renderwindow.hpp:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "Entity.hpp"
class RenderWindow
{
public:
RenderWindow(const char* p_title, int p_w, int p_h);
SDL_Texture* loadTexture(const char* p_filePath);
int getRefreshRate();
void cleanUp();
void clear();
void render(Entity& p_entity);
//void freeTexture(SDL_Texture* p_tex);
void display();
private:
SDL_Window* window;
SDL_Renderer* renderer;
};
renderwindow.cpp:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "RenderWindow.hpp"
#include "Entity.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 << "ERROR: Window has failed to init! SDL_Error: " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
}
SDL_Texture* RenderWindow::loadTexture(const char* p_filePath)
{
SDL_Texture* texture = NULL;
texture = IMG_LoadTexture(renderer, p_filePath);
if (texture == NULL)
std::cout << "ERROR: Failed to load texture! SDL_Error: " << SDL_GetError() << std::endl;
return texture;
}
int RenderWindow::getRefreshRate()
{
int displayIndex = SDL_GetWindowDisplayIndex(window);
SDL_DisplayMode mode;
SDL_GetDisplayMode(displayIndex, 0, &mode);
return mode.refresh_rate;
}
void RenderWindow::cleanUp()
{
SDL_DestroyWindow(window);
}
void RenderWindow::clear()
{
SDL_RenderClear(renderer);
}
void RenderWindow::render(Entity& p_entity)
{
SDL_Rect src;
src.x = p_entity.getCurrentFrame().x;
src.y = p_entity.getCurrentFrame().y;
src.w = p_entity.getCurrentFrame().w;
src.h = p_entity.getCurrentFrame().h;
SDL_Rect dst;
dst.x = p_entity.getPos().x * 4;
dst.y = p_entity.getPos().y * 4;
dst.w = p_entity.getCurrentFrame().w * 4;
dst.h = p_entity.getCurrentFrame().h * 4;
SDL_RenderCopy(renderer, p_entity.getTex(), &src, &dst);
}
// void RenderWindow::freeTexture(SDL_Texture* p_tex) {
// SDL_DestroyTexture(p_tex);
// }
void RenderWindow::display()
{
SDL_RenderPresent(renderer);
}
Entity.hpp:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "Math.hpp"
class Entity
{
public:
Entity(Vector2f p_pos, SDL_Texture* p_tex);
Vector2f& getPos()
{
return pos;
}
void setPos(Vector2f p_pos)
{
pos = p_pos;
}
SDL_Texture* getTex();
SDL_Rect getCurrentFrame();
private:
Vector2f pos;
SDL_Rect currentFrame;
SDL_Texture* tex;
};
entity.cpp:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "Entity.hpp"
#include "Math.hpp"
Entity::Entity(Vector2f p_pos, SDL_Texture* p_tex)
:pos(p_pos), tex(p_tex)
{
currentFrame.x = 0;
currentFrame.y = 0;
currentFrame.w = 32;
currentFrame.h = 32;
}
SDL_Texture* Entity::getTex()
{
return tex;
}
SDL_Rect Entity::getCurrentFrame()
{
return currentFrame;
}
math.hpp:
#pragma once
#include <iostream>
struct Vector2f
{
Vector2f()
:x(0.0f), y(0.0f)
{}
Vector2f(float p_x, float p_y)
:x(p_x), y(p_y)
{}
void print()
{
std::cout << x << ", " << y << std::endl;
}
float x, y;
};
Utils.hpp:
#pragma once
#include <SDL2/SDL.h>
namespace utils
{
inline float hireTimeInSeconds()
{
float t = SDL_GetTicks();
t *= 0.001f;
return t;
}
}
Thanks!
This is an updated version of my code, i've figured it out.
It turns out the problem was:
if (frameTicks < 1000 / window.getRefreshRate())
SDL_Delay(100 / window.getRefreshRate() - frameTicks);
was actually delaying it by 100 instead of 1000.

SDL2 can't render PNG file as texture

I am trying to make a simple racing game with C++ using SDL2. When i tried rendering my car asset(PNG Image) it simply did not render saying in the console that it couldn't access the file. Note that the source files are located in an exclusive directory (src/), the headers are in /include and the images are located in /assets. Here is my code:
main.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <Headers/RenderWindow.hpp>
int main(int argc, char *args[])
{
if (SDL_Init(SDL_INIT_VIDEO) > 0)
{
std::cout << "SDL_Init has failed..." << std::endl;
}
if (!(IMG_Init(IMG_INIT_PNG)))
{
std::cout << "IMG_Init has failed" << std::endl;
}
RenderWindow window("Untitled Racing Game", 1280, 720);
SDL_Texture *blueCar = window.LoadTexture("../assets/blue_car.png");
bool run = true;
SDL_Event event;
while (run)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
run = false;
}
}
window.Clear();
window.Render(blueCar);
window.Display();
}
window.CleanUp();
SDL_Quit();
return 0;
}
RenderWindow.hpp
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
class RenderWindow
{
public:
RenderWindow(const char *title, int width, int height);
SDL_Texture *LoadTexture(const char *filePath);
void CleanUp();
void Clear();
void Render(SDL_Texture *texture);
void Display();
private:
SDL_Window *window;
SDL_Renderer *renderer;
};
RenderWindow.cpp
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "Headers/RenderWindow.hpp"
RenderWindow::RenderWindow(const char *title, int width, int height)
: window(NULL), renderer(NULL)
{
window = (SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN));
if (window == NULL)
{
std::cout << "Window Failed to Load. Error " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
}
SDL_Texture *RenderWindow::LoadTexture(const char *filePath)
{
SDL_Texture *texture = NULL;
texture = IMG_LoadTexture(renderer, filePath);
if (texture == NULL)
{
std::cout << "Failed to load texture, " << SDL_GetError() << std::endl;
}
return texture;
}
void RenderWindow::CleanUp()
{
SDL_DestroyWindow(window);
}
void RenderWindow::Clear()
{
SDL_RenderClear(renderer);
}
void RenderWindow::Render(SDL_Texture *texture)
{
SDL_RenderCopy(renderer, texture, NULL, NULL);
}
void RenderWindow::Display()
{
SDL_RenderPresent(renderer);
}

Objects in std::vector not saving attributes correctly

The problem I'm having is that when I change an attribute of an Object the change isn't 'saving'. Easier to show you what's happening.
I'm learning c++ and decided to build a small chess app. Each Piece is a seperate Object.
They're stored in a std::vector as such
std::vector<Piece> pieces;
They're initialised like so
for (int i = 0; i < 2; i++)
{
Piece p;
p.Init(i*2+1, 1, renderer, SQUARE_SIZE, "king");
pieces.push_back(p);
}
When I click the mouse I want to select all pieces (temporarily)
for (int i = 0; i < pieces.size(); i++)
{
Piece p = pieces[i];
p.Select();
}
The issue is that while the Select() function is being called, by the time I get to rendering their selected attribute is false. Strangely this does not happen to the piece not contained within in the vector, referred to as k.
Before you ask there is nowhere in my code that I set selected to false :) (Except the constructor :P )
Also if you feel like downvoting, send me a comment first and I'll try fix whatever it is!
Here are the entire files. (not sure if this is the proper way to insert them)
Piece.h
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDl_image.h>
#include <array>
#include <vector>
class Piece
{
public:
Piece();
void Init(int _x, int _y, SDL_Renderer* renderer, int SQUARE_SIZE, std::string type);
void SetPos(int _x, int _y, int _w);
void LoadTexture(SDL_Renderer* renderer, std::string type);
void LoadMovementVector(std::string type);
void Render(SDL_Renderer* renderer);
void Select(){ selected = true; std::cout << "called\n";}
bool isSelected(){ return selected; }
int GetX(){ return x; } // SDL_Point
int GetY(){ return y; }
private:
int x, y;
std::vector<int> move_vector;
bool selected;
SDL_Rect rect;
SDL_Texture* texture;
};
Piece.cpp
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDl_image.h>
#include <vector>
#include "Piece.h"
Piece::Piece()
: x(0)
, y(0)
, selected(false)
{
}
void Piece::Init(int _x, int _y, SDL_Renderer* renderer, int SQUARE_SIZE, std::string type)
{
SetPos(_x, _y, SQUARE_SIZE);
LoadTexture(renderer, type);
LoadMovementVector(type);
}
void Piece::Render(SDL_Renderer* renderer)
{
//selected = true;
//std::cout << selected << std::endl;
if (selected)
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
if (texture != nullptr)
{
SDL_RenderCopy(renderer, texture, nullptr, &rect);
}
else
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
}
void Piece::LoadMovementVector(std::string type)
{
if (type == "king"){ // There literally has to be a better way to init std::vector
int arr[4] = {1,1,1,0};
for (int i = 0; i < 4; i++){ move_vector.push_back(arr[i]); }
}
for (int i = 0; i < move_vector.size(); i++)
{
std::cout << move_vector[i];
}
std::cout << std::endl;
}
void Piece::LoadTexture(SDL_Renderer* renderer, std::string type)
{
std::string source;
if (type == "king"){
source = "wk.png";
}
texture = IMG_LoadTexture(renderer, "res/wk.png");
}
void Piece::SetPos(int _x, int _y, int _w)
{
x = _x;
y = _y;
rect.x = _w*(_x-1);
rect.y = _w*(8-_y);
rect.w = _w;
rect.h = _w;
std::cout << x << y << std::endl;
}
Main.cpp
#include <iostream>
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDl_image.h>
#include "Piece.h"
using namespace std::chrono;
// Would be 'const int' but I want to make the board resizeable
int SCREEN_WIDTH = 800;
int SCREEN_HEIGHT = 800;
int BOARD_WIDTH, BOARD_HEIGHT, SQUARE_SIZE;
SDL_Window* window;
SDL_Renderer* renderer;
std::vector<Piece> pieces;
Piece k;
bool InitEverything();
bool InitSDL();
bool CreateWindow();
bool CreateRenderer();
void SetupRenderer();
void Quit();
void RunGame();
void Render();
void HandleInput();
void UpdateDimensions();
double GetDelta();
void RenderGameBoard();
bool loop = true;
auto timePrev = high_resolution_clock::now();
int main(int argc, char* args[])
{
if (!InitEverything())
return -1;
std::cout << "Running Game..." << std::endl;
for (int i = 0; i < 2; i++)
{
Piece p;
p.Init(i*2+1, 1, renderer, SQUARE_SIZE, "king");
pieces.push_back(p);
}
k.Init(5, 1, renderer, SQUARE_SIZE, "king");
RunGame();
Quit();
return 0;
}
void RunGame()
{
while (loop)
{
HandleInput();
Render();
double delta = GetDelta();
}
}
void Render()
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
RenderGameBoard();
for (int i = 0; i < pieces.size(); i++)
{
pieces[i].Render(renderer);
}
k.Render(renderer);
SDL_RenderPresent(renderer);
}
void RenderGameBoard()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if ((j%2==0&&i%2==0)||(j%2!=0&&i%2!=0))
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
else
SDL_SetRenderDrawColor(renderer, 180, 180, 180, 255);
SDL_Rect r = {i*SQUARE_SIZE, j*SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE};
SDL_RenderFillRect(renderer, &r);
}
}
}
void HandleInput()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
loop = false;
else if (event.type == SDL_KEYDOWN)
{
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
k.Select();
for (int i = 0; i < pieces.size(); i++)
{
Piece p = pieces[i];
p.Select();
}
int x = floor(event.button.x/SQUARE_SIZE)+1;
int y = 8-floor(event.button.y/SQUARE_SIZE);
for (int i = 0; i < pieces.size(); i++)
{
Piece p = pieces[i];
if (p.GetX() == x && p.GetY() == y)
{
p.Select();
}
}
}
}
}
}
void UpdateDimensions()
{
BOARD_WIDTH = SCREEN_WIDTH;
BOARD_HEIGHT = SCREEN_HEIGHT;
SQUARE_SIZE = BOARD_WIDTH/8;
}
double GetDelta()
{
auto timeCurrent = high_resolution_clock::now();
auto timeDiff = duration_cast< nanoseconds >( timeCurrent - timePrev );
double delta = timeDiff.count();
delta /= 1000000000;
timePrev = timeCurrent;
return delta;
}
bool InitEverything()
{
if (!InitSDL())
return false;
if (!CreateWindow())
return false;
if (!CreateRenderer())
return false;
SetupRenderer();
UpdateDimensions();
return true;
}
bool InitSDL()
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL failed to initialize : " << SDL_GetError() << std::endl;
return false;
}
return true;
}
bool CreateWindow()
{
window = SDL_CreateWindow("Chess", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (!window)
{
std::cout << "Failed to create window : " << SDL_GetError() << std::endl;
return false;
}
return true;
}
bool CreateRenderer()
{
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer)
{
std::cout << "Failed to create renderer : " << SDL_GetError() << std::endl;
return false;
}
return true;
}
void SetupRenderer()
{
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
}
void Quit()
{
SDL_DestroyWindow(window);
SDL_Quit();
}
This:
Piece p = pieces[i];
is creating a copy of the piece at index i in the vector.
Any methods you call after that are operating on the copy, not on the piece in the array.
Instead, take a reference to it:
Piece& p = pieces[i];
After that, p is a reference to element i in the vector and any operations you perform on it are performed on the vector element.

SDL not responding after running for a few seconds on linux

I was following the SDL Game development book and I cant even get the first file to work right. Upon the application starting it renders the window and then after a few seconds Linux says the game is not responding and ask me to force quit. This repeats every few seconds if I click wait. One thing I have noticed is that SDL_PollEvent never returns true.I am not sure why things are not working. Here is my code.
Main.cpp
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include "Game.h"
// our Game object
Game* g_game = 0;
int main(int argc, char* argv[]) {
g_game = new Game();
g_game->init("Chapter 1", 100, 100, 640, 480, 0);
while(g_game->running()) {
g_game->handleEvents();
//g_game->update();
g_game->render();
}
g_game->clean();
return 0;
}
Game.h
#ifndef __Game__
#define __Game__
#if !WINDOWS
#include <SDL2/SDL.h>
#else
#include <SDL.h>
#endif
class Game {
public:
Game() {}
~Game() {}
// simply set the running variable to true
bool init(const char* title, int xpos, int ypos, int width, int
height, bool fullscreen);
void render();
void update();
void handleEvents();
void clean();
// a function to access the private running variable
bool running() {
return m_bRunning;
}
private:
SDL_Window* m_pWindow;
SDL_Renderer* m_pRenderer;
bool m_bRunning;
};
#endif /* defined(__Game__) */
Game.cpp
#include "Game.h"
#include <iostream>
bool Game::init(const char* title, int xpos, int ypos, int width,
int height, bool fullscreen) {
// attempt to initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) == 0) {
std::cout << "SDL init success\n";
// init the window
int flags = 0;
if(fullscreen) {
flags = SDL_WINDOW_FULLSCREEN;
}
m_pWindow = SDL_CreateWindow(title, xpos, ypos,
width, height, flags);
if(m_pWindow != 0) { // window init success
std::cout << "window creation success\n";
m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);
if(m_pRenderer != 0) { // renderer init success
std::cout << "renderer creation success\n";
SDL_SetRenderDrawColor(m_pRenderer,
255,0,255,255);
} else {
std::cout << "renderer init fail\n";
return false; // renderer init fail
}
} else {
std::cout << "window init fail\n";
return false; // window init fail
}
} else {
std::cout << "SDL init fail\n";
return false; // SDL init fail
}
std::cout << "init success\n";
m_bRunning = true; // everything inited successfully, start the main loop
return true;
}
void Game::render() {
SDL_RenderClear(m_pRenderer); // clear the renderer to the draw color
SDL_RenderPresent(m_pRenderer); // draw to the screen
}
void Game::clean() {
std::cout << "cleaning game\n";
SDL_DestroyWindow(m_pWindow);
SDL_DestroyRenderer(m_pRenderer);
SDL_Quit();
}
void Game::handleEvents() {
SDL_Event event;
while(SDL_PollEvent(&event)) {
std::cout << "Checking Events";
switch(event.type) {
case SDL_QUIT:
std::cout << "Quiting";
m_bRunning = false;
break;
default:
break;
}
}
}
Edit:
so I made a minamal version of the code and now i get a new error. The error says "Segmentation Fault (core dumped)". Based on running it to a specific line in debug the error seems to appear at the line that says "SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);" I am not sure what the error is though
Here is the minial code:
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, char** argv) {
if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if(win == NULL) {
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(ren == NULL) {
SDL_DestroyWindow(win);
std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
std::string imagePath = "cb.bmp";
SDL_Surface *bmp = SDL_LoadBMP(imagePath.c_str());
if(bmp == NULL) {
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
std::cout << "SDL_LoadBMP Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);
if(tex == NULL) {
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_FreeSurface(bmp);
SDL_Event e;
bool quit = false;
while(!quit) {
while(SDL_PollEvent(&e)) {
//If user closes the window
if(e.type == SDL_QUIT) {
quit = true;
}
//If user presses any key
if(e.type == SDL_KEYDOWN) {
quit = true;
}
//If user clicks the mouse
if(e.type == SDL_MOUSEBUTTONDOWN) {
quit = true;
}
}
SDL_RenderClear(ren);
SDL_RenderPresent(ren);
}
SDL_DestroyTexture(tex);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
I have compiled and run your minimal code successfully under Linux with SDL 2.0.4. I used a simple image as "cb.bmp".
Try the following :
compile like this : g++ -Wall -ggdb $(sdl2-config --cflags) -o program main.cpp -lSDL2
gdb ./program, then type 'run'
when it crashes, type 'bt' (for backtrace)
copy the output here
My guess is : either the "bmp" file format is not supported or the rendering driver is not supported. try to use :
SDL_CreateRenderer(win, -1, 0);

Trouble changing class variable

I'm trying to write a small game where boxes drop down from the top of the window. But for some reason, I can't change a internal variable in the class, the y-coordinate. I don' knowif I'm missing something basic, but I can't find the bug.
Box.h
#pragma once
#include "SDL.h"
class Box
{
public:
Box();
~Box();
void setX (int a);
void setY (int a);
void setSpeed (int a);
void setSurface ();
void render(SDL_Surface *source, SDL_Window *win);
void update();
private:
int x;
int y;
int speed;
SDL_Surface *sur;
SDL_Rect rect;
};
Box.cpp
#include "Box.h"
#include "SDL_image.h"
#include <iostream>
void Box::setX(int a)
{
x = a;
}
void Box::setY (int a)
{
y = a;
}
void Box::setSpeed (int a)
{
speed = a;
}
void Box::setSurface()
{
sur = IMG_Load("C:/hello.bmp");
if (sur == NULL)
{
std::cout << IMG_GetError();
}
}
Box::Box()
{
speed = 5;
y = 0;
x = 3;
rect.x = 0;
rect.y = 0;
}
Box::~Box()
{
}
void Box::render(SDL_Surface *source, SDL_Window *win)
{
SDL_BlitSurface(sur, NULL, source, &rect);
SDL_UpdateWindowSurface(win);
}
void Box::update()
{
setY(y + speed); //I've also tried y = y + speed
rect.y = y;
}
main.cpp
#include "SDL.h"
#include "Box.h"
#include "SDL_image.h"
#include <iostream>
bool init();
void update(Box test);
void render(Box test);
SDL_Window *win;
SDL_Surface *source;
int main(int argc, char *argv[])
{
init();
bool quit = false;
SDL_Event e;
Box test;
test.setSurface();
test.render(source, win);
while (quit ==false)
{
while( SDL_PollEvent( &e ) != 0 )
{
if( e.type == SDL_QUIT )
{
quit = true;
}
}
update(test);
render(test);
}
return 0;
}
void update(Box test)
{
test.update();
}
void render(Box test)
{
test.render(source, win);
}
bool init()
{
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return 1;
}
win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if (win == NULL)
{
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
return 1;
}
source = SDL_GetWindowSurface(win);
return true;
}
update takes its Box argument by value, so a copy of the original Box is always made when update(test) is called. This copy is then modified, and the original is left unchanged. To fix this, make update take its argument by reference.
void update(Box& test);
void update(Box& test)
{
test.update();
}