im using SDL2 and just grasped some of the basic-concepts of SDL TTF, but for some reason after a certain amount of time running the app, my text elements disappear with seemingly no reason why, can someone please tell me what i need to do to top my text renders from disappearing? what went wrong here?
#include <iostream>
#include <iomanip>
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>
#include "AdviLib.h"
#define SDLKCM SDLK_COMMA
#define SDLKPR SDLK_PERIOD
#define SDLKSP SDLK_SPACE
#define SDLKES SDLK_ESCAPE
void Screenshot(SDL_Renderer* r, const char* name, int w, int h)
{
const uint32_t format{ SDL_PIXELFORMAT_ARGB8888 };
SDL_Surface* sur{ SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, format) };
SDL_RenderReadPixels(r, NULL, format, sur->pixels, sur->pitch);
SDL_SaveBMP(sur, name);
SDL_FreeSurface(sur);
std::cout << name << " captured!\n";
}
int main(int args, char* argc[])
{
// before SDL init
std::cout << "enter the name of the session: "; string sesh{ sInput() };
std::cout << "enter the name of the local, non .bmp, image: "; string image{ sInput() };
// SDL init
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
TTF_Init();
const int W{ 800 }; const int H{ 750 };
SDL_Window* win{ SDL_CreateWindow(sesh.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, W, H, SDL_WINDOW_SHOWN) };
SDL_Renderer* ren{ SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC) };
SDL_Surface* img{ IMG_Load(image.c_str()) };
TTF_Font* font{ TTF_OpenFont("CRYSRG__.ttf", 40) };
SDL_Color color{ 205, 99, 35 };
SDL_Texture* tex{ SDL_CreateTextureFromSurface(ren, img) };
SDL_Event e;
// buffer variables
string Txt; string Tx2; string Tx3; string Tx4; string Tx5; string Tx6; string Tx7;
SDL_Surface* ts1 = nullptr; SDL_Surface* ts2 = nullptr; SDL_Surface* ts3 = nullptr; SDL_Surface* ts4 = nullptr; SDL_Surface* ts5 = nullptr; SDL_Surface* ts6 = nullptr; SDL_Surface* ts7 = nullptr;
SDL_Texture* tb1 = nullptr; SDL_Texture* tb2 = nullptr; SDL_Texture* tb3 = nullptr; SDL_Texture* tb4 = nullptr; SDL_Texture* tb5 = nullptr; SDL_Texture* tb6 = nullptr; SDL_Texture* tb7 = nullptr;
int w{ img->w }; int h{ img->h }; int x{ randomWithinRange(W - w) }; int y{ randomWithinRange(H - h) };
int tbW{ 0 }; int tbH{ 0 }; int X{ 2 }; int tbY{ 1 }; int tb2Y{ 32 }; int tb3Y{ 63 }; int tb4Y{ 94 }; int tb5Y{ 125 }; int tb6Y{ 156 }; int tb7Y{ 187 };
int ms{ 1 };
bool q{ false };
double ANG{ 0 }; int ANGI{ 0 };
// before main loop
// main loop
while (!q)
{
// before buffer setup
SDL_Rect IR{ x, y, w, h };
// buffer setup
ANGI = ANG;
int _TXT_RED = color.r; int _TXT_GRN = color.g; int _TXT_BLU = color.b;
//current x pos, current y pos, current angle, current speed, text color red, text color grn, text color blue,
char buf1[255]; char buf2[255]; char buf3[255]; char buf4[255]; char buf5[255]; char buf6[255]; char buf7[255];
sprintf_s(buf1, "x: %i", x); sprintf_s(buf2, "y: %i", y); sprintf_s(buf3, "a: %i", ANGI); sprintf_s(buf4, "MS: %i", ms); sprintf_s(buf5, "TR: %i", _TXT_RED); sprintf_s(buf6, "TG: %i", _TXT_GRN);
sprintf_s(buf7, "TB: %i", _TXT_BLU);
Txt = buf1; Tx2 = buf2; Tx3 = buf3; Tx4 = buf4; Tx5 = buf5; Tx6 = buf6; Tx7 = buf7;
ts1 = TTF_RenderText_Blended(font, Txt.c_str(), color); ts2 = TTF_RenderText_Blended(font, Tx2.c_str(), color); ts3 = TTF_RenderText_Blended(font, Tx3.c_str(), color);
ts4 = TTF_RenderText_Blended(font, Tx4.c_str(), color); ts5 = TTF_RenderText_Blended(font, Tx5.c_str(), color); ts6 = TTF_RenderText_Blended(font, Tx6.c_str(), color);
ts7 = TTF_RenderText_Blended(font, Tx7.c_str(), color);
tb1 = SDL_CreateTextureFromSurface(ren, ts1); tb2 = SDL_CreateTextureFromSurface(ren, ts2); tb3 = SDL_CreateTextureFromSurface(ren, ts3); tb4 = SDL_CreateTextureFromSurface(ren, ts4);
tb5 = SDL_CreateTextureFromSurface(ren, ts5); tb6 = SDL_CreateTextureFromSurface(ren, ts6); tb7 = SDL_CreateTextureFromSurface(ren, ts7);
SDL_QueryTexture(tb1, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb2, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb3, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb4, NULL, NULL, &tbW, &tbH);
SDL_QueryTexture(tb5, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb6, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb7, NULL, NULL, &tbW, &tbH);
SDL_Rect Rct{ X, tbY, tbW, tbH }; SDL_Rect Rc2{ X, tb2Y, tbW, tbH }; SDL_Rect Rc3{ X, tb3Y, tbW, tbH }; SDL_Rect Rc4{ X, tb4Y, tbW, tbH }; SDL_Rect Rc5{ X, tb5Y, tbW, tbH }; SDL_Rect Rc6{ X, tb6Y, tbW, tbH };
SDL_Rect Rc7{ X, tb7Y, tbW, tbH };
// set display renders
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
SDL_RenderClear(ren);
SDL_RenderCopyEx(ren, tex, NULL, &IR, ANG, 0, SDL_FLIP_NONE);
SDL_RenderCopy(ren, tb1, NULL, &Rct); SDL_RenderCopy(ren, tb2, NULL, &Rc2); SDL_RenderCopy(ren, tb3, NULL, &Rc3); SDL_RenderCopy(ren, tb4, NULL, &Rc4); SDL_RenderCopy(ren, tb5, NULL, &Rc5);
SDL_RenderCopy(ren, tb6, NULL, &Rc6); SDL_RenderCopy(ren, tb7, NULL, &Rc7);
SDL_RenderPresent(ren);
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT) q = true;
else if (e.type == SDL_KEYDOWN)
{
switch (e.key.keysym.sym)
{
case SDLK_w: y -= ms; break; case SDLK_s: y += ms; break;
case SDLK_a: x -= ms; break; case SDLK_d: x += ms; break;
case SDLK_r: if (color.r < 255) color.r += 1; else if (color.r == 255) color.r = 0; break;
case SDLK_g: if (color.g < 255) color.g += 1; else if (color.g == 255) color.g = 0; break;
case SDLK_b: if (color.b < 255) color.b += 1; else if (color.b == 255) color.b = 0; break;
case SDLKCM: ANG -= 1; break;
case SDLKPR: ANG += 1; break;
case SDLKSP: Screenshot(ren, "capture.bmp", W, H); break;
case SDLK_q: if (ms > 1) { ms -= 1; /*std::cout << "ms decreased to " << ms << "\n";*/ } /*else if (ms == 1) std::cout << "ms cannot decrease further\n";*/ break;
case SDLK_e: if (ms < 10) { ms += 1; /*std::cout << "ms increased to " << ms << "\n";*/ } /*else if (ms == 10) ms = 10; std::cout << "ms cannot increase further\n";*/ break;
case SDLKES: q = true; break;
}
}
}
}
// after main loop - usually nothing
// exit code
SDL_DestroyTexture(tb1); SDL_DestroyTexture(tb2); SDL_DestroyTexture(tb3); SDL_DestroyTexture(tb4); SDL_DestroyTexture(tb5); SDL_DestroyTexture(tb6); SDL_DestroyTexture(tb7); SDL_DestroyTexture(tex);
SDL_FreeSurface(ts1); SDL_FreeSurface(ts2); SDL_FreeSurface(ts3); SDL_FreeSurface(ts4); SDL_FreeSurface(ts5); SDL_FreeSurface(ts6); SDL_FreeSurface(ts7); SDL_FreeSurface(img);
TTF_CloseFont(font);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}
Its because you keep loading more textures and surfaces without freeing them. You only need to load them once. Put your buffer setup before the loop, also check the memory usage when its running im almost certain its gonna be rising alot
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 months ago.
Improve this question
I'm trying to make a game in C++ with SDL2, and I can't even get a texture displaying. SDL_GetError() returns nothing.
I'm on a windows 10 pro using Visual Studio.
Here are my 3 files:
main.cpp
#include "Classes.h"
int MouseX = 0;
int MouseY = 0;
int PlayerX = 0;
int PlayerY = 0;
SDL_Renderer* renderer;
Tile tile = Tile({10, 10, TileTypes::Tile_Grass}, renderer);
EventReturns HandleEvent(SDL_Event* event) {
switch (event->type) {
case SDL_QUIT:
return EventReturns::Event_QUIT;
case SDL_KEYDOWN:
switch (event->key.keysym.sym) {
case SDLK_ESCAPE:
return EventReturns::Event_TryQuit;
default:
return EventReturns::Event_None;
}
default:
return EventReturns::Event_None;
}
}
int mainLoop(EventReturns eventReturn) {
SDL_GetMouseState(&MouseX, &MouseY);
if (eventReturn == EventReturns::Event_QUIT || eventReturn == EventReturns::Event_TryQuit) {
return 1;
}
return 0;
}
void render() {
SDL_SetRenderDrawColor(renderer, 100, 200, 200, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
tile.SetPos(0, 0);
if (tile.Draw(renderer) != 0) {
SDL_ShowSimpleMessageBox(0, "ERROR", "ERROR: Rect in tile has 0x0 size, Please close this with the task manager", NULL);
}
SDL_RenderPresent(renderer);
}
int main(int argc, char* argv[]) {
SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 2880, 1600, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
bool running = true;
EventReturns eventReturn = EventReturns::Event_None;
SDL_Event event;
int quit = 0;
while (running) {
while (SDL_PollEvent(&event)) {
eventReturn = HandleEvent(&event);
}
quit = mainLoop(eventReturn);
render();
if (quit == 1) {
running = false;
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Classes.h
#pragma once
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#define SpriteSizeMult 1
enum class EventReturns {
Event_QUIT,
Event_None,
Event_TryQuit
};
enum class TileTypes {
Tile_Grass
};
struct TileStruct {
int x;
int y;
TileTypes type;
};
class Tile {
public:
Tile(int x, int y, char* TexturePath, SDL_Renderer* renderer);
Tile(TileStruct structure, SDL_Renderer* renderer);
Tile();
int Draw(SDL_Renderer* renderer);
void SetPos(int x, int y);
private:
int x = 0;
int y = 0;
int TextureWidth = 0;
int TextureHeight = 0;
SDL_Texture* texture;
SDL_Rect rect;
};
SDL_Point getsize(SDL_Texture* texture);
Classes.cpp
#include "Classes.h"
SDL_Point getsize(SDL_Texture* texture) {
SDL_Point size;
SDL_QueryTexture(texture, NULL, NULL, &size.x, &size.y);
return size;
}
Tile::Tile(int x, int y, char* TexturePath, SDL_Renderer* renderer)
{
this->x = x;
this->y = y;
this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load(TexturePath));
if (this->texture == nullptr) {
this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/MissingTexture.png"));
std::cout << IMG_GetError();
}
SDL_Point point = getsize(this->texture);
this->TextureHeight = point.y;
this->TextureWidth = point.x;
this->rect = {this->x - ((this->TextureWidth * SpriteSizeMult) / 2), this->y - ((this->TextureHeight * SpriteSizeMult) / 2), this->TextureWidth * SpriteSizeMult, this->TextureHeight * SpriteSizeMult};
}
Tile::Tile(TileStruct structure, SDL_Renderer* renderer)
{
this->x = structure.x;
this->y = structure.y;
switch (structure.type) {
case TileTypes::Tile_Grass:
this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/Tiles/Grass.png"));
default:
this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/MissingTexture.png"));
}
if (this->texture == NULL) {
this->texture = SDL_CreateTextureFromSurface(renderer, IMG_Load("Assets/MissingTexture.png"));
if (this->texture == NULL) {
SDL_ShowSimpleMessageBox(0, "ERROR", "Failed to load texture", NULL);
SDL_ShowSimpleMessageBox(0, "ERROR", IMG_GetError(), NULL);
}
}
SDL_Point point = getsize(this->texture);
this->TextureHeight = point.y;
this->TextureWidth = point.x;
this->rect = { this->x - ((this->TextureWidth * SpriteSizeMult) / 2), this->y - ((this->TextureHeight * SpriteSizeMult) / 2), this->TextureWidth * SpriteSizeMult, this->TextureHeight * SpriteSizeMult };
}
Tile::Tile()
{
}
int Tile::Draw(SDL_Renderer* renderer)
{
if (rect.w == 0 || rect.h == 0) {
return -1;
}
this->rect.x = 0;
this->rect.y = 0;
SDL_RenderCopy(renderer, this->texture, NULL, &rect);
return 0;
}
void Tile::SetPos(int x, int y)
{
this->x = x;
this->y = y;
}
I'm sorry for the sheer amount of code that is, but I'd really appreciate the help. If there's any more info I need to put here, just let me know.
I'm fully aware that I should make a Minimal Reproducible Example, but as far as I'm aware, all the code listed here is necessary.
Finally, in case I've been unclear, when running the code the Missing Texture image that should appear isn't showing up.
I can't see SDL_INIT function in your code.
You should add this in the beginning of your main function.
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
return 1;
You are initialising tile before creating a renderer so the constructor is trying to create a texture without a renderer.
SDL_Renderer* renderer;
Tile tile = Tile({10, 10, TileTypes::Tile_Grass}, renderer);
You should do something like this
#include "Classes.h"
int MouseX = 0;
int MouseY = 0;
int PlayerX = 0;
int PlayerY = 0;
SDL_Renderer* renderer;
EventReturns HandleEvent(SDL_Event* event) {
switch (event->type) {
case SDL_QUIT:
return EventReturns::Event_QUIT;
case SDL_KEYDOWN:
switch (event->key.keysym.sym) {
case SDLK_ESCAPE:
return EventReturns::Event_TryQuit;
default:
return EventReturns::Event_None;
}
default:
return EventReturns::Event_None;
}
}
int mainLoop(EventReturns eventReturn) {
SDL_GetMouseState(&MouseX, &MouseY);
if (eventReturn == EventReturns::Event_QUIT || eventReturn == EventReturns::Event_TryQuit) {
return 1;
}
return 0;
}
void render(Tile tile) {
SDL_SetRenderDrawColor(renderer, 100, 200, 200, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
tile.SetPos(0, 0);
if (tile.Draw(renderer) != 0) {
SDL_ShowSimpleMessageBox(0, "ERROR", "ERROR: Rect in tile has 0x0 size, Please close this with the task manager", NULL);
}
SDL_RenderPresent(renderer);
}
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
return 1;
SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 2880, 1600, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
Tile tile = Tile({ 10, 10, TileTypes::Tile_Grass }, renderer);
bool running = true;
EventReturns eventReturn = EventReturns::Event_None;
SDL_Event event;
int quit = 0;
while (running) {
while (SDL_PollEvent(&event)) {
eventReturn = HandleEvent(&event);
}
quit = mainLoop(eventReturn);
render(tile);
if (quit == 1) {
running = false;
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Im following this (https://www.udemy.com/course/free-learn-c-tutorial-beginners/learn/lecture/1838486#announcements ) tutorial and im stuck.
It seem that windows throws that exception and it cant be handled.
I think I try write something to some wrong place but cant see it.
Heres the line that causes the problem.
m_buffer[(y * SCREEN_WIDTH) + x] = color;
And here is everything else
//====================================main.cpp=======================================
#include<iostream>
#include "Screen.h"
#include<SDL.h>
using namespace std;
int main(int argc, char* argv[]) {
Screen screen;
if (!screen.init()) {
cout << "Error initialising SDL." << endl;
}
while (true) {
// update particles
// draw particles
for (int y = 0; y < Screen::SCREEN_HEIGHT; y++) {
for (int x = 0; x < Screen::SCREEN_WIDTH; x++ ){
screen.setPixel(x, y, 128, 0, 255);
}
}
//Draw the screen
screen.update();
// see for messages/events
if (!screen.processEvents()) {
break;
}
}
screen.close();
return 0;
}
//==========================================================================================
screen.h
#ifndef SCREEN_H_
#define SCREEN_H_
#include<SDL.h>
#include<iostream>
class Screen
{
public:
const static int SCREEN_WIDTH = 800;
const static int SCREEN_HEIGHT = 600;
private:
SDL_Window* m_window;
SDL_Renderer* m_renderer;
SDL_Texture* m_texture;
Uint32* m_buffer;
public:
Screen();
bool init();
void update();
void setPixel(int x, int y, Uint8 red, Uint8 green, Uint8 blue);
bool processEvents();
void close();
};
#endif // !SCREEN_H_
//=======================screen.cpp======================================================
#include "Screen.h"
Screen::Screen() : m_window(NULL), m_renderer(NULL), m_texture(NULL), m_buffer(NULL)
{
}
bool Screen::init() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
return false;
}
m_window = SDL_CreateWindow("Particle Fire Explosion",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN); //-----------------SDL_WINDOW_HIDDEN SDL_WINDOW_SHOWN
if (m_window == 0) {
SDL_Quit();
return false;
}
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_PRESENTVSYNC);
m_texture = SDL_CreateTexture(m_renderer,
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, SCREEN_WIDTH, SCREEN_HEIGHT);
if (m_renderer == NULL) {
SDL_DestroyWindow(m_window);
SDL_Quit();
return false;
}
if (m_texture == NULL) {
SDL_DestroyWindow(m_window);
SDL_DestroyRenderer(m_renderer);
SDL_Quit();
return false;
}
Uint32* buffer = new Uint32[SCREEN_WIDTH * SCREEN_HEIGHT];
memset(buffer, 0xFF, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(Uint32));
return true;
}
bool Screen::processEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT)
{
return false;
}
}
return true;
}
void Screen::setPixel(int x, int y, Uint8 red, Uint8 green, Uint8 blue) {
Uint32 color = 0;
color += red;
color <<= 8;
color += green;
color <<= 8;
color += blue;
color <<= 8;
color += 0xFF;
m_buffer[(y * SCREEN_WIDTH) + x] = color;
}
void Screen::update() {
SDL_UpdateTexture(m_texture, NULL, m_buffer, SCREEN_WIDTH * sizeof(Uint32));
SDL_RenderClear(m_renderer);
SDL_RenderCopy(m_renderer, m_texture, NULL, NULL);
SDL_RenderPresent(m_renderer);
}
void Screen::close() {
delete[] m_buffer;
SDL_DestroyRenderer(m_renderer);
SDL_DestroyTexture(m_texture);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
//==========================================================================================
Maybe someone can see what is the broblem?
Your Screen::init() method never sets m_buffer, so when setPixel() tries to dereference it, it is dereferencing a NULL pointer, which invokes undefined behavior.
this line is wrong
Uint32* buffer = new Uint32[SCREEN_WIDTH * SCREEN_HEIGHT];
you mean
m_buffer = new Uint32[SCREEN_WIDTH * SCREEN_HEIGHT];
What I'm trying to do is make an SDL program that can write special symbols to a window I created. The keyboard can change between 4 layers each registering 32 keys. I just can't figure out how to actually make something appear on the screen and have no idea what I'm doing wrong.
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, const char * argv[])
{
//Setup
bool quit = false;
SDL_Event event;
int z = 0; //Layer
int x = 0;
int y = 0;
//Init
SDL_Init(SDL_INIT_VIDEO);
SDL_Window * window = SDL_CreateWindow("TPKB", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 640, SDL_WINDOW_SHOWN);
SDL_Rect rect = {x, y, 32, 32};
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface * A_srf = SDL_LoadBMP("A.bmp"); SDL_Texture * A = SDL_CreateTextureFromSurface(renderer, A_srf); SDL_FreeSurface(A_srf);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
//Events
while (!quit)
{
SDL_WaitEvent(&event);
switch (event.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_KEYUP:
{
if(z == 0)
{
switch(event.key.keysym.sym)
{
//case SDLK_1: SDL_BlitSurface(A_srf, NULL, surface, srfrect); break;
case SDLK_2: SDL_RenderCopy(renderer, A, NULL, &rect); if(x == 928){x = 0; y += 32;} else{x += 32;} rect.x = x; rect.y = y; SDL_RenderClear(renderer); SDL_RenderPresent(renderer); break;
case SDLK_LEFT: z = 1; std::cout << "1"; break;
}
}
if(z == 1)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: z = 0; std::cout << "0"; break;
}
}
}
}
}
//Cleanup
SDL_DestroyRenderer(renderer);
SDL_DestroyTexture(A);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I've tried moving the render clear render present stuff around but it hasn't seemed to be activating at all.
Question:
First off, I'm very new to C++ so I'm just starting out. One of the exercises I'm currently on is having me create a "Particle Explosion" as you can see in the window title then have it flash different colors as you can see in the main.cpp.
My problem:
Whenever I run it in VS2015 I get my console to open, the window opens, but it doesn't flash any colors, it just stays white. Everything seems to be working just fine and it doesn't freeze or have any errors. Just. No. Colors.
Does anyone see an error I'm making? Once I created it I compared it to the exercise, but everything seems to be 100% exactly the same.
I'm on W7, VS2015 and using SDL2 lib.
main.cpp
#include <iostream>
#include <SDL.h>
#include "Screen.h"
#include <math.h>
#undef main
using namespace std;
using namespace caveofprogramming;
int main() {
Screen screen;
if (screen.init() == false) {
cout << "Error initialzing SDL." << endl;
}
while (true) {
// Update particles
// Draw Particles
int elapsed = SDL_GetTicks();
unsigned char green = (1 + sin(elapsed * 0.001)) * 128;
unsigned char red = (1 + sin(elapsed * 0.002)) * 128;
unsigned char blue = (1 + sin(elapsed * 0.003)) * 128;
for (int y = 0; y < Screen::SCREEN_HEIGHT; y++) {
for (int x = 0; x < Screen::SCREEN_WIDTH; x++) {
screen.setPixel(x, y, red, green, blue);
}
}
//Draw the screen
// Check for messages/events
if (screen.processEvents() == false) {
break;
}
}
screen.close();
return 0; // usually when your program runs ok it returns 0
}
Screen.cpp
#include "Screen.h"
#include <iostream>
namespace caveofprogramming {
Screen::Screen() :
m_window(NULL), m_renderer(NULL), m_texture(NULL), m_buffer(NULL) {
}
bool Screen::init() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
return false;
}
m_window = SDL_CreateWindow("Particle Fire Explosion",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (m_window == NULL) {
SDL_Quit();
return false;
}
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_PRESENTVSYNC);
m_texture = SDL_CreateTexture(m_renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_STATIC, SCREEN_WIDTH, SCREEN_HEIGHT);
if (m_renderer == NULL) {
SDL_DestroyWindow(m_window);
SDL_Quit();
return false;
}
if (m_texture == NULL) {
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
SDL_Quit();
return false;
}
m_buffer = new Uint32[SCREEN_WIDTH * SCREEN_HEIGHT];
memset(m_buffer, 0, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(Uint32));
return true;
}
void Screen::clear() {
memset(m_buffer, 0, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(Uint32));
}
void Screen::setPixel(int x, int y, Uint8 red, Uint8 green, Uint8 blue) {
if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) {
return;
}
Uint32 color = 0;
color += red;
color <<= 8;
color += green;
color <<= 8;
color += blue;
color <<= 8;
color += 0xFF;
m_buffer[(y * SCREEN_WIDTH) + x] = color;
}
void Screen::update() {
SDL_UpdateTexture(m_texture, NULL, m_buffer, SCREEN_WIDTH * sizeof(Uint32));
SDL_RenderClear(m_renderer);
SDL_RenderCopy(m_renderer, m_texture, NULL, NULL);
SDL_RenderPresent(m_renderer);
}
bool Screen::processEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
return false;
}
}
return true;
}
void Screen::close() {
delete[] m_buffer;
SDL_DestroyRenderer(m_renderer);
SDL_DestroyTexture(m_texture);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
}
Screen.h
#pragma once
#include <SDL.h>
namespace caveofprogramming {
class Screen {
public:
const static int SCREEN_WIDTH = 800;
const static int SCREEN_HEIGHT = 600;
private:
SDL_Window *m_window;
SDL_Renderer *m_renderer;
SDL_Texture *m_texture;
Uint32 *m_buffer;
public:
Screen();
bool init();
bool processEvents();
void update();
void clear();
void setPixel(int x, int y, Uint8 red, Uint8 green, Uint8 blue);
void close();
};
}
As Elderbug said, I just had to add the function to my object to render.
//Draw the screen
screen.update();
thanks!
I'am new there. I've been learning classes and tried to make a very simple platform game. But I have problem now. I've wanted to set Class "Player" to collide with 2 objects of Class "Block" But Collision do not work for one of them.
Here is my code:
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#undef main
class Block
{
private:
SDL_Texture *BlockTexture;
public:
Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height);
~Block();
void Draw(SDL_Renderer *renderTarget);
SDL_Rect BlockPos;
};
Block::Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
BlockTexture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
BlockPos.x = xPos;
BlockPos.y = yPos;
BlockPos.w = Width;
BlockPos.h = Height;
}
Block::~Block()
{
SDL_DestroyTexture(BlockTexture);
}
void Block::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, BlockTexture, NULL, &BlockPos);
}
class Player
{
private:
SDL_Texture *Texture;
float moveSpeed;
float jumpSpeed;
int falling = 0;
SDL_Scancode keys [3];
public:
SDL_Rect PlayerPos;
Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height);
~Player();
void Update(float delta, const Uint8 *Keystate);
void Draw(SDL_Renderer *renderTarget);
bool Collision(Block &p);
};
Player::Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
Texture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
PlayerPos.x = PosX;
PlayerPos.y = PosY;
PlayerPos.w = Width;
PlayerPos.h = Height;
keys[0] = SDL_SCANCODE_UP;
keys[1] = SDL_SCANCODE_LEFT;
keys[2] = SDL_SCANCODE_RIGHT;
moveSpeed = 200.f;
jumpSpeed = 100.f;
}
Player::~Player()
{
SDL_DestroyTexture(Texture);
}
void Player::Update(float delta, const Uint8 *KeyState)
{
if(KeyState[keys[0]])
{
PlayerPos.y -= moveSpeed * delta;
}
if(KeyState[keys[1]])
{
PlayerPos.x -= (moveSpeed / 2) * delta;
}
if(KeyState[keys[2]])
{
PlayerPos.x += moveSpeed * delta;
}
if(falling == 0)
{
PlayerPos.y += jumpSpeed * delta;
}
}
void Player::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, Texture, NULL, &PlayerPos);
}
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *Renderer)
{
SDL_Texture *texture = NULL;
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
texture = SDL_CreateTextureFromSurface(Renderer, surface);
}
SDL_FreeSurface(surface);
return texture;
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("Platform", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
SDL_Renderer *renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
int imgFlags = IMG_INIT_PNG;
int currentTime = 0;
int previousTime = 0;
float delta = 0;
const Uint8 *Keystate;
Player Player(renderTarget, "BlockP.png", 100, 100, 50, 50);
Block Block1(renderTarget, "Block.png", 0, 500, 800, 100);
Block Block2(renderTarget, "Block.png", 100, 300, 300, 50);
bool isRunning = true;
SDL_Event ev;
while(isRunning)
{
Keystate = SDL_GetKeyboardState(NULL);
Player.Collision(Block1);
Player.Collision(Block2);
previousTime = currentTime;
currentTime = SDL_GetTicks();
delta = (currentTime - previousTime) / 1000.0f;
Player.Update(delta, Keystate);
while(SDL_PollEvent(&ev) != 0)
{
if(ev.type == SDL_QUIT)
isRunning = false;
}
SDL_RenderClear(renderTarget);
Player.Draw(renderTarget);
Block1.Draw(renderTarget);
Block2.Draw(renderTarget);
SDL_RenderPresent(renderTarget);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderTarget);
window = NULL;
renderTarget = NULL;
SDL_Quit();
return 0;
}
The problem with your code is that each call to Player.Collision overwrites the "falling" variable.
Player.Collision(Block1); //this call calculates a falling value
Player.Collision(Block2); //...then this call overwrites falling with a new value
So effectively your code is only testing if the player is colliding with Block2, so collisions with Block1 are ignored.
Currently your Collision function is:
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
Firstly, your "return false;" is not actually part of the else, as you don't have {}. In this particular case it makes no difference as the else is exited and then the return happens but your indentation would suggest you expect the "return false;" line to be executed as part of the else block so you should put:
else
{
falling = 1;
return false;
}
Next you want to say if you have already detected a collision (eg, with Block1) then don't set falling to 1, to do this add an if statement.
else
{
if(falling != 0) //if we haven't already detected a collision this frame
{
falling = 1;
}
return false;
}
You will however need to set falling back to 1 at the start of each frame, otherwise if a collision is detected on one frame then the player will never fall on subsequent frames, even if they are not colliding with a block.
As a side note, your Player.Update code modifies the player's y position if falling == 0, this seems counter intuitive as usually 0 is false and 1 is true, hence you seem to be saying if not falling then update y, where as it should be if falling update y. Personally I would use a bool rather than an int to hold the value of falling, and then say if(falling) update y, this would make your code clearer.