C++ error, Calling a class member from a function - c++

I am working on building a game, and I get a compiling error apply_surface was not declared in this scope. the error is in line 95, in the function User::show().
EDIT: Now that it is fized, the image "baz", is not showing up on the screen. sorry for the edit.
/*This source code copyrighted by Lazy Foo' Productions (2004-2013)
and may not be redistributed without written permission.*/
//The headers
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <string>
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *baz = NULL;
SDL_Event event;
void cleanup()
{
SDL_FreeSurface(background);
SDL_FreeSurface(screen);
SDL_FreeSurface(baz);
SDL_Quit;
}
bool quit = false;
class User
{
private:
SDL_Surface *baz = NULL;
SDL_Surface *screen = NULL;
int x;
int y;
int xVel;
int yVel;
public:
void keys();
void move();
void show();
void user();
};
void User::keys()
{
while(quit == false)
if(SDL_PollEvent(&event))
{
if( event.type == SDL_QUIT )
quit = true;
}
Uint8 *keystates = SDL_GetKeyState(NULL);
if(keystates[SDLK_d] )
{
User::xVel+=50;
}
if(keystates[SDLK_a])
{
User::xVel-=50;
}
if(keystates[SDLK_s])
{
User::yVel+=50;
}
if(keystates[SDLK_w])
{
User::yVel-=50;
}
if(keystates[SDLK_ESCAPE])
{
cleanup();
}
}
void User::user()
{
x = 0;
y = 0;
xVel = 0;
yVel = 0;
}
void User::move()
{
x+=xVel;
y+=yVel;
x-=xVel;
}
void User::show()
{
apply_surface(x,y,baz,screen);
SDL_Flip( screen );
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{ //Temporary rectangle to hold the offsets
SDL_Rect offset;
//Get the offsets
offset.x = x;
offset.y = y; //Blit the surface
SDL_BlitSurface( source, NULL, destination, &offset );
}
int main( int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(640,400,32,SDL_SWSURFACE);
background = IMG_Load("background.png");
baz = IMG_Load("baz.png");
apply_surface(0,0,background,screen);
SDL_Flip(screen);
while( quit == false )
{
User Baz;
Baz.user();
Baz.keys();
Baz.move();
Baz.show();
if(quit == true)
{
cleanup();
}
}
return 0;
}

your apply_surface() function is not declared within the scope
So move your code :
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{ //Temporary rectangle to hold the offsets
SDL_Rect offset;
//Get the offsets
offset.x = x;
offset.y = y; //Blit the surface
SDL_BlitSurface( source, NULL, destination, &offset );
}
to the top ( before you use it )
Or else
Add a function prototype at the top like this :
void apply_surface( int, int, SDL_Surface*, SDL_Surface*);

Related

Exception thrown: write access violation. this->**m_buffer** was 0x111011101110112

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];

I debugged a SDL2 Program in Visual Studio and I had to force-quit, and now my screen is brighter out of the program. Why, and how do I fix this?

I was making a little program to practice pointer usage and rendering.
I was trying to debug an Illegal memory access, and my program crashed.
The problem, is that it crashed and I had to force-quit the debugging session by pressing shift-f5
because my program was taking mouse focus, and I could not click anything.
Now my screen is constantly brighter than before, probably due to an draw operation that was supposed to draw a fullscreen white rectangle.
This will probably be fixed when I restart my PC.... but it is still a problem if this stacks, since I will have to restart every 3 debugging sessions to not burn my eyes.
Any advice on how to ENSURE my program releases resources?
Edit for reproducible example:
#include "SDL.h"
#include "SDL_render.h"
#include <stdio.h>
#include <iostream>
#include <list>
#include <string>
#include <ft2build.h>
#include <SDL_ttf.h>
#include <functional>
#include <memory>
#include FT_FREETYPE_H
struct element {
SDL_Rect* area;
SDL_Texture* texture;
SDL_Surface* surface;
std::string name = "";
std::function<void()> functionPointer;
element(SDL_Rect* rect, SDL_Texture* tex, SDL_Surface* surf, std::string elementName, std::function<void()> fp) {
area = rect;
texture = tex;
surface = surf;
name = elementName;
functionPointer = fp;
}
~element() {
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
area = nullptr;
surface = nullptr;
texture = nullptr;
name = "";
functionPointer = nullptr;
}
};
struct screenVariables {
std::list<SDL_Texture*> textureList;
std::list<element*>& elementList;
SDL_Renderer* renderer;
std::list<SDL_Surface*> surfaceList;
screenVariables(std::list<SDL_Texture*> tex, std::list<element*> rec, SDL_Renderer* render,std::list<SDL_Surface*> surf) :
textureList(tex),elementList(rec), renderer(render),surfaceList(surf) {};
};
class gameHandler{
private:
SDL_Window* screen;
SDL_Renderer* renderer;
SDL_Texture* mainBlock;
bool saveAvailable = false;
bool quit = false;
std::list<SDL_Texture*> textureList;
std::list<element*> elementList;
std::list<SDL_Surface*> surfaceList;
screenVariables screenInfo{ textureList, elementList, renderer, surfaceList };
void nothing() {};
void continuePressed() {};
void newGame() {};
public:
gameHandler() {
SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS);
TTF_Init();
screen = SDL_CreateWindow("Game Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
1920, 1080,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
renderer = SDL_CreateRenderer(screen, -1, 0);
mainBlock = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
SDL_TEXTUREACCESS_TARGET, 1920, 1080);
}
//All methods that do operations on elements will operate on the LAST ADDED ELEMENT. Always create a new element and use push_back() to add it to the end.
//Everything commented out is not nessesary for reproduction, but
//will be left for reference.
/*bool showFirstElement(screenVariables& arg, const char* imgPath, SDL_Rect* area) {
SDL_Renderer* renderRef = arg.renderer;
//The following line means: end() returns an iterator, take the iterator and make it go back once, then deference it to get the value.
//This gets the value of the last added surface.
SDL_Surface* newSurface = *(--(arg.surfaceList.end()));
newSurface = SDL_LoadBMP(imgPath);
SDL_Texture* newTexture = *(--(arg.textureList.end()));
newTexture = SDL_CreateTextureFromSurface(renderRef, newSurface);
std::function<void()> nothingWrapper = [&]() { nothing(); };
element* toBeModified = *(--(arg.elementList.end()));
toBeModified->element::area = area;
toBeModified->texture = newTexture;
toBeModified->surface = newSurface;
toBeModified->name = imgPath;
toBeModified->functionPointer = nothingWrapper;
arg.elementList.push_back(toBeModified);
SDL_RenderCopy(renderRef, newTexture, NULL, area);
return true;
}
bool textOnElement(screenVariables& arg, const char* text,int points, element* el) {
SDL_Renderer* renderRef = arg.renderer;
TTF_Font* font = NULL;
SDL_Color textColor = { 0,0,0 };
font = TTF_OpenFont("TravelingTypewriter.ttf", points);
SDL_Surface* newSurface = *(--(arg.surfaceList.end()));
newSurface = TTF_RenderText_Solid(font,text,textColor);
SDL_Texture* newTexture = *(--(arg.textureList.end()));
newTexture = SDL_CreateTextureFromSurface(renderRef, newSurface);
el->surface = newSurface;
el->texture = newTexture;
SDL_RenderCopy(renderRef, newTexture, NULL, el->area);
return true;
}
element* checkClickedElement(screenVariables& arg, SDL_Point pos) {
for (element* i : arg.elementList) {
if (SDL_PointInRect(&pos, i->area)) {
return i;
}
return nullptr;
}
}
bool fillWithColor(screenVariables& arg, Uint32 red, Uint32 green, Uint32 blue, Uint32 alpha) {
SDL_Renderer* renderRef = arg.renderer;
SDL_Surface* surface = SDL_CreateRGBSurface(0, 1920, 1080, 8, red, green, blue, alpha);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderRef, surface);
SDL_Rect fullScreen = { 1920,1080 };
std::string name = "R" + std::to_string(red) + "G" + std::to_string(green) + "B" + std::to_string(blue);
std::function<void()> nothingWrapper = [&]() { nothing(); };
element newElement = element(&fullScreen, texture, surface, name, nothingWrapper);
SDL_RenderCopy(renderRef, texture, NULL, NULL);
return true;
}
bool fillElementPointer(screenVariables& arg, SDL_Point leftTop, SDL_Point rightBottom, std::function<void()> fp,std::string name,element* newElement) {
SDL_Rect newRect;
newRect.x = (leftTop.x + rightBottom.x) / 2;
newRect.y = (leftTop.y + rightBottom.y) / 2;
newRect.w = (rightBottom.x - leftTop.x);
newRect.h = (leftTop.y - rightBottom.y);
newElement = &element(&newRect, nullptr, nullptr, name, fp);
arg.elementList.push_back(newElement);
return true;
}
//This allows me to create pointers that will not go out of scope when methods return. Always use this method if the element you will create needs to presist through functions.
element* createElementPointer(){
element* newPointer = nullptr;
return newPointer;
}
int showMenu(screenVariables& arg) {
fillWithColor(arg, 255, 255, 255, 255);
SDL_Point leftTop = { 200,700 };
SDL_Point rightBottom = { 600,200 };
std::function<void()> nothingWrapper = [&]() { nothing(); };
element* titleText = createElementPointer();
if (!fillElementPointer(screenInfo, leftTop, rightBottom, nothingWrapper, "titleText", titleText)) {
std::cout << "createElement failed in showMenu()";
}
leftTop.y = 100;
rightBottom.x = 0;
element* continueOrStart = createElementPointer();
if (saveAvailable) {
std::function<void()> continueWrapper = [&]() { continuePressed(); };
if (!fillElementPointer(screenInfo, leftTop, rightBottom, continueWrapper, "continueButton", continueOrStart)) {
std::cout << "createElement failed in showMenu() saveAvailable.";
}
textOnElement(arg, "Continue", 16, continueOrStart);
}
else {
std::function<void()> newGameWrapper = [&]() { newGame(); };
if (!fillElementPointer(screenInfo, leftTop, rightBottom, newGameWrapper, "newGameButton", continueOrStart)) {
std::cout << "createElement failed in showMenu() !saveAvailable.";
}
textOnElement(arg, "New Game", 16, continueOrStart);
}
return 0;
}
void mainLoop() {
SDL_Event event;
showMenu(screenInfo);
while (!quit) {
SDL_RenderClear(renderer);
while (SDL_PollEvent(&event) != 0) {
switch (event.type)
{
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT) {
SDL_Point position = { event.button.x,event.button.y };
element* result = checkClickedElement(screenInfo, position);
if (result == nullptr) {
break;
}
else {
result->functionPointer();
}
}
break;
case SDL_QUIT:
quit = true;
break;
}
}
SDL_RenderPresent(renderer);
}
}
void clearResources() {
int index{ 0 };
for (element* i : screenInfo.elementList) {
delete i;
}
SDL_DestroyRenderer(renderer);
SDL_Quit();
} */
};
int main(int argc, char* argv[]) {
gameHandler handler; //This alone makes my screen brighter.
//Uncomment every function and let mainLoop() run, and it crashes.
//Although many attempts at making this exception safe, it did not work.
//handler.mainLoop();
return 0;
}

SDL Button not Displaying

Recently I have been trying to make a button using the lazyfoo.net tutorials. The button example they code didn't fit what I needed (especially since I modified the LTexture class) so I modified it... and, of course, it didn't work.
So here is the modified LTexture class(now dubbed Texture):
#pragma once
//Using SDL, SDL_image, standard IO, and strings
#include <xstring>
#include <SDL.h> //SDL header file
#include <SDL_image.h> //SDL image file
#include <stdio.h> //standard C ouput
#include <string> //standard c++ string
#include <map>
#include <SDL_ttf.h>
using namespace std;
typedef Uint8 u8;
//Texture wrapper class (originally from lazyfoo.net)
class Texture
{
public:
//Initializes variables
Texture();
//Deallocates memory
~Texture();
//Loads image at specified path
bool loadFromFile(std::string path);
//Deallocates texture
void free();
//Renders texture at given point
void render();
//Sets the size of the image
void setSize(int width, int height);
//Adds a clip to the clips map
void addClip(string name, SDL_Rect* aclip);
//Sets the clip
void setClip(string name);
void setNullClip();
//Sets the placement of the object
void setPos(int newx, int newy);
//Moves the position of the object
void movePos(int addx, int addy);
//Gets image dimensions
int getWidth();
int getHeight();
//Sets the color
void setColor(Uint8 red, u8 green, u8 blue);
//Set blending
void setBlendMode(SDL_BlendMode blending);
//Set alpha modulation
void setAlpha(Uint8 alpha);
//Creates image from font string
bool loadFromRenderedText(std::string textureText, SDL_Color textColor);
protected:
//The actual hardware texture
SDL_Texture* mTexture;
//Image dimensions
int mWidth;
int mHeight;
//Image bottom left coordinates
int x;
int y;
//Current clip of image
SDL_Rect* clip;
//Available image clips
map<string, SDL_Rect*> clips;
};
And the function definitions:
#include "Texture.h"
#include "Univar.h"
extern SDL_Renderer* Renderer;
extern TTF_Font* Font;
Texture::Texture()
{
//Initialize
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
Texture::~Texture()
{
//Deallocate
free();
}
bool Texture::loadFromFile(std::string path)
{
//Get rid of preexisting texture
free();
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load(path.c_str());
if (loadedSurface == NULL)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
}
else
{
//Color key image
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0, 0xFF, 0xFF));
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface(Renderer, loadedSurface);
if (newTexture == NULL)
{
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
}
else
{
//Get image dimensions
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
}
//Return success
mTexture = newTexture;
return mTexture != NULL;
}
void Texture::free()
{
//Free texture if it exists
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void Texture::render()
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
//Set clip rendering dimensions
if (clip != NULL)
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
SDL_RenderCopy(Renderer, mTexture, clip, &renderQuad);
}
void Texture::setSize(int width, int height)
{
mWidth = width;
mHeight = height;
}
void Texture::addClip(string name, SDL_Rect * aclip)
{
clips[name] = aclip;
}
void Texture::setClip(string name)
{
clip = clips[name];
}
void Texture::setNullClip()
{
clip = NULL;
}
void Texture::setPos(int newx, int newy)
{
x = newx;
y = newy;
}
void Texture::movePos(int addx, int addy)
{
x += x;
y += y;
}
int Texture::getWidth()
{
return mWidth;
}
int Texture::getHeight()
{
return mHeight;
}
void Texture::setColor(Uint8 red, u8 green, u8 blue)
{
//Modulate texture
SDL_SetTextureColorMod(mTexture, red, green, blue);
}
void Texture::setBlendMode(SDL_BlendMode blending)
{
//Set blending function
SDL_SetTextureBlendMode(mTexture, blending);
}
void Texture::setAlpha(Uint8 alpha)
{
//Modulate texture alpha
SDL_SetTextureAlphaMod(mTexture, alpha);
}
bool Texture::loadFromRenderedText(std::string textureText, SDL_Color textColor)
{
//Get rid of preexisting texture
free();
//Render text surface
SDL_Surface* textSurface = TTF_RenderText_Solid(Font, textureText.c_str(), textColor);
if (textSurface == NULL)
{
printf("Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError());
}
else
{
//Create texture from surface pixels
mTexture = SDL_CreateTextureFromSurface(Renderer, textSurface);
if (mTexture == NULL)
{
printf("Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError());
}
else
{
//Get image dimensions
mWidth = textSurface->w;
mHeight = textSurface->h;
}
//Get rid of old surface
SDL_FreeSurface(textSurface);
}
//Return success
return mTexture != NULL;
}
Then here is the button class:
#pragma once
#include "Texture.h"
enum MouseState {
Out,
Hover
};
enum Press {
LClick,
RClick,
None
};
class Button : public Texture{
int w;
int h;
int x;
int y;
public:
//Inits the variables
Button(int aw, int ah);
//Handles events
Press handleEvent(SDL_Event* e);
};
And the function definitions:
#include "Button.h"
Button::Button(int aw, int ah) : w(aw), h(ah)
{
setSize(aw, ah);
}
Press Button::handleEvent(SDL_Event * e)
{
//If mouse event happened
if (e->type == SDL_MOUSEMOTION || e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEBUTTONUP)
{
//Get mouse position
int ax, ay;
SDL_GetMouseState(&ax, &ay);
//Check if mouse is in button
bool inside = true;
//Mouse is left of the button
if (ax < x)
{
inside = false;
}
//Mouse is right of the button
else if (ax > x + w)
{
inside = false;
}
//Mouse above the button
else if (ay < y)
{
inside = false;
}
//Mouse below the button
else if (ay > y + h)
{
inside = false;
}
//Mouse is outside button
if (!inside)
{
setClip("out");
return None;
}
//Mouse is inside button
else
{
setClip("Hover");
//Set mouse over sprite
switch (e->button.button)
{
case SDL_BUTTON_LEFT:
return LClick;
break;
case SDL_BUTTON_RIGHT:
return RClick;
break;
default:
return None;
break;
}
}
}
else {
return None;
}
}
And when I run this, I get nothing (well I get a window but without the button in it)! If the button class seams barebones, that's because I'm pretty sure I've narrowed down the error to handleEvent(). I looked through it and couldn't find the error.
I figured out the error. The reason is I'm not used to SDL's coordinate system.
In SDL, the top left is 0,0.
In regular coordinate grids, the bottom left is 0,0.
:(P

Collision with more than 1 Object SDL 2.0-C++

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.

SDL render not working

I have a problem creating this second class in my game, this is a class for player but when I call the texturemanager to draw the play, it's not working, but when i directly call the texturemanager to draw the player it was working. this is my class.
Game.h
#pragma once
#include <SDL/SDL.h>
#include "TextureManager.h"
#include "Player.h"
class Game
{
public:
Game(void);
~Game(void);
void startGame();
void init();
void gameLoop();
void eventHandler();
void render();
void exitGame();
private:
bool _isRunning;
SDL_Window* _window;
SDL_Renderer* _renderer;
SDL_Rect _spriteClips[2];
TextureManager _textureManager;
Player _player;
};
Game.cpp
#include "Game.h"
#include "Error.h"
Game::Game(void)
{
_window = nullptr;
_isRunning = true;
}
Game::~Game(void)
{
}
void Game::startGame()
{
init();
gameLoop();
}
void Game::init()
{
if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
_window = SDL_CreateWindow("Renderer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480, SDL_WINDOW_SHOWN);
if (_window != nullptr)
{
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(_renderer!= nullptr)
{
SDL_SetRenderDrawColor(_renderer, 255, 255, 255, 255);
}
else
fatalError("Failed to create renderer");
}
else
fatalError("Failed to create window!");
}
else
fatalError("Failed to initialize SDL!");
// temp image load
_textureManager.loadFromFile("assets/tiles.png", _renderer);
_spriteClips[0].x = 0;
_spriteClips[0].y = 160;
_spriteClips[0].w = 80;
_spriteClips[0].h = 80;
_spriteClips[1].x = 0;
_spriteClips[1].y = 80;
_spriteClips[1].w = 80;
_spriteClips[1].h = 80;
}
void Game::gameLoop()
{
while (_isRunning != false)
{
eventHandler();
render();
}
exitGame();
}
void Game::eventHandler()
{
SDL_Event evnt;
while (SDL_PollEvent(&evnt))
{
switch (evnt.type)
{
case SDL_QUIT:
_isRunning = false;
break;
}
}
}
void Game::render()
{
SDL_RenderClear(_renderer);
_textureManager.draw(0, 0, &_spriteClips[0], _renderer);
_player.draw(200, 200, &_spriteClips[1], _renderer);
// when i used this, it is working
//_textureManager.draw(200, 200, &_spriteClips[1], _renderer);
SDL_RenderPresent(_renderer);
}
void Game::exitGame()
{
SDL_DestroyRenderer(_renderer);
SDL_DestroyWindow(_window);
_window = nullptr;
_renderer = nullptr;
SDL_Quit();
}
TextureManager.h
#pragma once
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <string>
class TextureManager
{
public:
TextureManager(void);
~TextureManager(void);
bool loadFromFile(std::string filePath, SDL_Renderer* renderer);
void free();
void draw(int x, int y, SDL_Rect* clip, SDL_Renderer* renderer);
int getWidth() { return _width; }
int getHeight() { return _height; }
private:
SDL_Texture* _texture;
int _width;
int _height;
};
TextureManager.cpp
#include "TextureManager.h"
#include "Error.h"
TextureManager::TextureManager(void)
{
_texture = nullptr;
_width = 0;
_height = 0;
}
TextureManager::~TextureManager(void)
{
free();
}
bool TextureManager::loadFromFile(std::string filePath , SDL_Renderer* renderer)
{
free();
SDL_Texture* newTexture = nullptr;
SDL_Surface* loadedSurface = IMG_Load(filePath.c_str());
if(loadedSurface != nullptr)
{
SDL_SetColorKey(loadedSurface, SDL_TRUE, SDL_MapRGB(loadedSurface->format, 0, 0xFF, 0xFF));
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if(newTexture != nullptr)
{
_width = loadedSurface->w;
_height = loadedSurface->h;
}
else
fatalError("unable to create texture from surface!");
SDL_FreeSurface(loadedSurface);
}
else
fatalError("unable to load image path " + filePath);
_texture = newTexture;
return _texture != nullptr;
}
void TextureManager::draw(int x, int y, SDL_Rect* clip, SDL_Renderer* renderer)
{
SDL_Rect renderQuad = { x, y, _width, _height };
if (clip != nullptr)
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
SDL_RenderCopy(renderer, _texture, clip, &renderQuad);
}
void TextureManager::free()
{
if (_texture != nullptr)
{
SDL_DestroyTexture(_texture);
_texture = nullptr;
_width = 0;
_height = 0;
}
}
Player.h
#pragma once
#include "TextureManager.h"
class Player
{
public:
Player(void);
~Player(void);
void draw(int x, int y, SDL_Rect* clip, SDL_Renderer* renderer);
private:
TextureManager _textureManager;
};
Player.cpp
#include "Player.h"
Player::Player(void)
{
}
Player::~Player(void)
{
}
void Player::draw(int x, int y, SDL_Rect* clip, SDL_Renderer* renderer)
{
_textureManager.draw(x, y, clip, renderer);
}
That's because Game and Player have two different texture managers. The game initializes its texture manager, that's why when you use it directly it works. The Player never initializes its manager, that's why nothing is drawn when you use it.
To fix it, you might want to only have one texture manager, the one that is in the Game class, and have Player just store a pointer or a reference to it. Here's one way to fix it:
Change the type of the _textureManager in the Player class (but not in the Game class) to be a reference:
TextureManager& _textureManager;
Make Player class accept a TextureManager reference in its constructor, and use it to initialize the private member:
Player::Player(TextureManager& textureManager)
: _textureManager(textureManager)
{
}
Make the Game object properly initialize the player in its constructor:
Game::Game(void)
: _player(_textureManager)
{
...
With these changes your code should now work.