Im constantly getting a redefinition of default argument parameter 1 error and its preventing from building the project successfully to test code as I include it. Im relatively new to C++ and this form of building a game, having multiple header and cpp files referencing eachother.
Texture2D.cpp:
#include <iostream>
#include <SDL_image.h>
#include <string>
#include "Texture2D.h"
#include "Constants.h"
#include "Commons.h"
using namespace::std;
Texture2D::Texture2D(SDL_Renderer* renderer)
{
SDL_Renderer* mRenderer = NULL;
SDL_Texture* mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
Texture2D::~Texture2D()
{
Free();
mRenderer = NULL;
}
bool Texture2D::LoadFromFile(string path)
{
//remove the memory used for a previous texture
Free();
SDL_Texture* mTexture = NULL;
//load the image
SDL_Surface* pSurface = IMG_Load(path.c_str());
mWidth = pSurface->w;
mHeight = pSurface->h;
if (pSurface != NULL)
{
mTexture = SDL_CreateTextureFromSurface(mRenderer, pSurface);
if (mTexture == NULL)
{
cout << "Unable to create texture from surface. Error: " << SDL_GetError() << endl;
}
//Color key the image - The color to be transparent
SDL_SetColorKey(pSurface, SDL_TRUE, SDL_MapRGB(pSurface->format, 0, 0xFF, 0xFF));
SDL_FreeSurface(pSurface);
return mTexture;
}
else
{
cout << "Unable to create texture from surface. Error: " << IMG_GetError() << endl;
}
}
void Texture2D::Render(Vector2D newPosition, SDL_RendererFlip flip, double angle = 0.0f)
{
//clear the screen
SDL_SetRenderDrawColor(mRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(mRenderer);
//set where to render the texture
SDL_Rect renderLocation = { 0, 0, mWidth, mHeight };
//render to screen
SDL_RenderCopyEx(mRenderer, mTexture, NULL, &renderLocation, 0, NULL, SDL_FLIP_NONE);
SDL_RenderPresent(mRenderer);
}
void Texture2D::Free()
{
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
Texture2D.h:
#pragma once
#ifndef _TEXTURE2D_H
#define _TEXTURE2D_H
#include <SDL.h>
#include <SDL_image.h>
#include <map>
#include <string>
#include "Commons.h"
class Texture2D
{
public:
Texture2D(SDL_Renderer* renderer);
~Texture2D();
bool LoadFromFile(std::string path);
void Free();
void Render(Vector2D newPosition, SDL_RendererFlip flip, double angle = 0.0f);
int GetWidth() { return mWidth; }
int GetHeight() { return mHeight; }
private:
SDL_Renderer* mRenderer;
SDL_Texture* mTexture;
int mWidth;
int mHeight;
};
#endif //_TEXTURE2D_H
Commons.h:
#pragma once
#ifndef _COMMONS_H
#define _COMMONS_H
struct Vector2D
{
Vector2D()
{
x = 0.0f;
y = 0.0f;
}
float x;
float y;
};
struct InitialVector2D
{
InitialVector2D()
{
initialx = 0.0f;
initialy = 0.0f;
}
float initialx;
float initialy;
};
enum SCREENS
{
SCREEN_INTRO = 0,
SCREEN_MENU,
SCREEN_LEVEL1,
SCREEN_LEVEL2,
SCREEN_GAMEOVER,
SCREEN_HIGHSCORES
};
#endif //_COMMONS_H
When giving a default parameter, you should only add the default in the header declaration. So, changing:
void Texture2D::Render(Vector2D newPosition, SDL_RendererFlip flip, double angle = 0.0f)
to:
void Texture2D::Render(Vector2D newPosition, SDL_RendererFlip flip, double angle)
should fix the error.
Simply remove the default specification here: void Texture2D::Render(Vector2D newPosition, SDL_RendererFlip flip, double angle = 0.0f) As the compiler tells you, that was already given in the function declaration. – πάντα ῥεῖ 47 mins ago
Related
I keep getting this issue when I run my program. My images fail to load in with the error: "Invalid texture". The program used to work fine. I'm working on it in linux ubuntu with all of my drivers updated. Here is the code where the renderer is made and the images are loaded.
//init.h
//#pragma once
#ifndef INIT_H
#define INIT_H
static const int SCREEN_WIDTH = 480;
static const int SCREEN_HEIGHT = 480;
static SDL_Surface* currentSurface = NULL;
static SDL_Window* window = NULL;
static SDL_Surface* screenSurface = NULL;
static SDL_Renderer* renderer = NULL;
//static SDL_Surface *SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 0, SDL_ANYFORMAT);
bool init();
void close();
//void SetColor(int value);
#endif // INIT_H
//init.cpp
//#include "stdafx.h"
#include <stdio.h>
#include "tchar.h"
#include <SDL2/SDL.h>
#include <iostream>
#include <SDL2/SDL_image.h>
#include "main.h"
#include "init.h"
#include "load.h"
//#include <conio.h>
//#include <Windows.h>
#include <string>
#include <SDL2/SDL_ttf.h>
#include <cmath>
bool init()
{
bool boot = 1;
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
//SetColor(4);
printf("SDL failed to initialize \n");
//SetColor(7);
boot = 0;
}
else {
printf("SDL initialized!\n");
window = SDL_CreateWindow("Light Development Project", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (window == NULL)
{
//SetColor(4);
printf("SDL failed to create the window \n");
//SetColor(7);
boot = 0;
}
else {
printf("Window created!\n");
//screenSurface = SDL_GetWindowSurface(window);
printf("Screen surface created!\n");
}
printf("Initializing SDL_image...\n");
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
//SetColor(4);
printf("Failed to initialize SDL_image\n");
//SetColor(7);
boot = 0;
}
else {
printf("SDL_image initialized!\n");
}
printf("Initializing TTF...\n");
if (TTF_Init() == -1)
{
//SetColor(4);
printf("Failed to initialize TTF\n");
//SetColor(7);
boot = 0;
}
else {
printf("TTF initialized!\n");
}
printf("Creating renderer...\n");
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL)
{
//SetColor(4);
printf("Failed to create renderer. Error: %s\n", SDL_GetError());
//SetColor(7);
boot = 0;
} else
printf("Renderer created!\n");
printf("Setting render draw color...\n");
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
printf("Render draw color set!\n");
}
//printf("Done!\n");
return boot;
}
void close()
{
printf("\nShutting down...\nFreeing SDL surfaces...\nDetroying textures and renderers...\n");
SDL_DestroyTexture(texture);
texture = NULL;
SDL_DestroyRenderer(renderer);
renderer = NULL;
printf("SDL surfaces, textures, and renderers freed from memory!\nDestroying SDL window...\n");
SDL_DestroyWindow(window);
//TTF_CloseFont(font);
//font = NULL;
window = NULL;
printf("SDL window detroyed!\nQuitting SDL subsystems...\n");
IMG_Quit();
SDL_Quit();
//TTF_Quit();
printf("All SDL subsystems shutdown!\n");
}
/*void SetColor(int value) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), value);
/*
1: Blue
2: Green
3: Cyan
4: Red
5: Purple
6: Yellow (Dark)
7: Default white
8: Gray/Grey
9: Bright blue
10: Brigth green
11: Bright cyan
12: Bright red
13: Pink/Magenta
14: Yellow
15: Bright white
}
*/
//load.h
//#pragma once
#ifndef LOAD_H
#define LOAD_H
enum KeyPressSurfacese
{
KEY_PRESS_SURFACE_DEFUALT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
KEY_PRESS_SURFACE_TOTAL
};
class cTexture {
public:
cTexture();
~cTexture();
bool loadFromFile(std::string path);
void free();
void render(int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE);
void loadFromRenderedText(std::string text, SDL_Color color);
void setColor(Uint8 red, Uint8 green, Uint8 blue);
void setBlendMode(SDL_BlendMode blending);
void setAlpha(Uint8 alpha);
int getWidth();
int getHeight();
private:
SDL_Texture * hTexture;
int hWidth;
int hHeight;
};
static cTexture keyPresses[KEY_PRESS_SURFACE_TOTAL];
static cTexture sprite;
static cTexture text;
static SDL_Texture* loadTexture(std::string path);
static SDL_Rect spriteClips[4];
//TTF_Font* font = NULL;
static SDL_Color textColor = { 0, 0, 0 };
void loadAssets();
#endif //LOAD_H
//load.cpp
//#include "stdafx.h"
#include <stdio.h>
#include "tchar.h"
#include <SDL2/SDL.h>
#include <iostream>
#include <SDL2/SDL_image.h>
#include "main.h"
#include "init.h"
#include "load.h"
//#include <conio.h>
//#include <Windows.h>
#include <string>
#include <SDL2/SDL_ttf.h>
#include <cmath>
cTexture::cTexture()
{
//printf("Constructing texture wrapper class...\n");
hTexture = NULL;
hWidth = 0;
hHeight = 0;
}
cTexture::~cTexture()
{
//printf("Destroying texture wrapper class...\n");
free();
}
void cTexture::free()
{
//if (hTexture != NULL)
SDL_DestroyTexture(hTexture);
hTexture = NULL;
hWidth = 0;
hHeight = 0;
}
bool cTexture::loadFromFile(std::string path)
{
free();
SDL_Texture* newTexture = NULL;
SDL_Surface* loadedSurface = IMG_Load(path.c_str());
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if(newTexture == NULL)
//printf("fail. error: %s\n", SDL_GetError());
hWidth = loadedSurface->w;
hHeight = loadedSurface->h;
SDL_FreeSurface(loadedSurface);
hTexture = newTexture;
return hTexture != NULL;
}
void cTexture::render(int x, int y, SDL_Rect * clip, double angle, SDL_Point * center, SDL_RendererFlip flip)
{
//SDL_Rect renderQuad = { x, y, hWidth, hHeight };
SDL_Rect renderQuad = { x, y, 480, 480 };
if (clip != NULL)
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
SDL_RenderCopyEx(renderer, hTexture, clip, &renderQuad, angle, center, flip);
}
/*
void cTexture::loadFromRenderedText(std::string text, SDL_Color color)
{
free();
SDL_Surface* textSurface = TTF_RenderText_Solid(font, text.c_str(), textColor);
hTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
hWidth = textSurface->w;
hHeight = textSurface->h;
SDL_FreeSurface(textSurface);
}
*/
void cTexture::setColor(Uint8 red, Uint8 green, Uint8 blue)
{
SDL_SetTextureColorMod(hTexture, red, green, blue);
}
void cTexture::setBlendMode(SDL_BlendMode blending)
{
SDL_SetTextureBlendMode(hTexture, blending);
}
void cTexture::setAlpha(Uint8 alpha)
{
SDL_SetTextureAlphaMod(hTexture, alpha);
}
int cTexture::getWidth() { return hWidth; }
int cTexture::getHeight() { return hHeight; }
void loadAssets()
{
printf("Loading image assets in loadAssets()...\n");
if (!keyPresses[KEY_PRESS_SURFACE_DEFUALT].loadFromFile("carrot.png"))
{
//SetColor(4);
printf("Failed to load image. Error: %s\n", SDL_GetError());
//SetColor(7);
} else
printf("Image loaded\n");
if(!keyPresses[KEY_PRESS_SURFACE_UP].loadFromFile("smIamLU.jpg"))
{
//SetColor(4);
printf("Failed to load image\n");
//SetColor(7);
}
else {
//keyPresses[KEY_PRESS_SURFACE_UP].setBlendMode(SDL_BLENDMODE_BLEND);
printf("Image loaded\n");
}
if(!keyPresses[KEY_PRESS_SURFACE_DOWN].loadFromFile("down.bmp"))
{
//SetColor(4);
printf("Failed to load image\n");
//SetColor(7);
} else
printf("Image loaded\n");
if(!keyPresses[KEY_PRESS_SURFACE_LEFT].loadFromFile("left.bmp"))
{
//SetColor(4);
printf("Failed to load image\n");
//SetColor(7);
}else
printf("Image loaded\n");
if(!keyPresses[KEY_PRESS_SURFACE_RIGHT].loadFromFile("right.bmp"))
{
//SetColor(4);
printf("Failed to load image\n");
//SetColor(7);
}else
printf("Image loaded\n");
if (!sprite.loadFromFile("foo.png"))
{
//SetColor(4);
printf("Failed to load image\n");
//SetColor(7);
}else
printf("Image loaded\n");
spriteClips[0].x = 0;
spriteClips[0].y = 0;
spriteClips[0].w = 64;
spriteClips[0].h = 205;
spriteClips[1].x = 64;
spriteClips[1].y = 0;
spriteClips[1].w = 64;
spriteClips[1].h = 205;
spriteClips[2].x = 128;
spriteClips[2].y = 0;
spriteClips[2].w = 64;
spriteClips[2].h = 205;
spriteClips[3].x = 192;
spriteClips[3].y = 0;
spriteClips[3].w = 64;
spriteClips[3].h = 205;
//font = TTF_OpenFont("Ubuntu-L.ttf", 28);
//text.loadFromRenderedText("text", textColor);
printf("Done!\n");
}
With the renderer I've tried making it with differnt flags such as SDL_RENDERER_ACCELERATED or SDL_RENDERER_SOFTWARE but neither work. The error is specifically coming from the load.cpp file
newTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
This is the line that fails. The error generated by SDL reads "Invalid texture". The renderer is declared correctly but I can't get it to work.
I'm so confused why it isn't working because it used to work fine. I abandoned the project for a few months and it was working when I stopped, came back, and now it doesn't work. Not to mention that I had a bunch of more problems that I already worked out, but this one I can't.
I figured it out and it's the strangest fix I've ever done. I added an error check for the renderer in the load function and it started working again. If I remove the error check if statement it goes back to not working. Seems like a strange bug but I'm glad it's working again.
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
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.
So I'm basically following a book called SDL Game Development by Shaun Mitchell.
I'm current on page 58, where it tells us how to implement polymorphism.
So far what I have down are:
- Create the main code where we do all our rendering updating etc. (Game.cpp and Game.h)
- Create a Texture manager as a singleton (TextureManager.h and TextureManager.cpp)
- Create a GameObject (GameObject.h and GameObject.cpp)
- Create a Player that inherits GameObject (Player.h and Player.cpp)
So my GameObject class basically has 3 methods: load, draw and update.
Load basically loads an image, and I use my TextureManager to do so.
Draw draws it and update just changes it positions and current frame.
I pass the name of the image which is basically the directory, the renderer and the textureID from the Game class where I call them.
Essentially the problem is that I pass in two different directories into a GameObject
and a Player, but it only loads up the last directory I pass in. As in both GameObject and Player becomes the same image.
So I think the problem lies in Game class, Player class or GameObject class.
I create the objects in Game class, and push them in vector at Game.cpp in init function
Where it says
m_go->load(100, 100, 96, 60, "assets/simba.bmp", "animate",m_pRenderer);
m_player->load(300, 300, 96, 60, "assets/download.bmp", "animate",m_pRenderer);
GameObject.h
#ifndef GAMEOBJECT_H
#define GAMEOBJECT_H
#include <string>
#include <iostream>
#include "SDL_image.h"
#include "TextureManager.h"
class GameObject
{
public:
virtual bool load(int x, int y, int width, int height, std::string name, std::string textureID, SDL_Renderer* pRenderer);
virtual void draw(SDL_Renderer* pRenderer);
virtual void update();
virtual void clean();
protected:
std::string m_textureID;
int m_currentFrame;
int m_currentRow;
int m_x;
int m_y;
int m_width;
int m_height;
};
#endif // GAMEOBJECT_H
GameObject.cpp
#include "GameObject.h"
bool GameObject::load(int x, int y, int width, int height, std::string name, std::string textureID, SDL_Renderer* pRenderer)
{
m_x = x;
m_y = y;
m_width = width;
m_height = height;
m_textureID = textureID;
m_currentRow = 1;
m_currentFrame = 1;
if(!TextureManager::Instance()->load(name, textureID, pRenderer))
{
return false;
}
return true;
}
void GameObject::draw(SDL_Renderer* pRenderer)
{
TextureManager::Instance()->drawFrame(m_textureID, m_x, m_y,m_width, m_height, m_currentRow, m_currentFrame, pRenderer);
}
void GameObject::update()
{
m_x += 1;
m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
}
void GameObject::clean()
{
}
In my Player class, I do the same thing except I use the methods that are already made in GameObject
Player.h
#ifndef PLAYER_H
#define PLAYER_H
#include "GameObject.h"
class Player : public GameObject
{
public:
bool load(int x, int y, int width, int height, std::string name, std::string textureID, SDL_Renderer* pRenderer);
void draw(SDL_Renderer* pRenderer);
void update();
void clean();
};
#endif // PLAYER_H
Player.cpp
#include "Player.h"
bool Player::load(int x, int y, int width, int height, std::string name, std::string textureID, SDL_Renderer* pRenderer)
{
if(!GameObject::load(x, y, width, height, name, textureID, pRenderer))
{
return false;
}
return true;
}
void Player::draw(SDL_Renderer* pRenderer)
{
GameObject::draw(pRenderer);
}
void Player::update()
{
m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
m_x -= 1;
}
void Player::clean()
{
}
This is the part where the images doesn't load the same thing happens in Game.cpp
So I basically created a vector that holds GameObjects, it told me to use it so that I could just for loop through it whenever I want to draw objects
Game.h
#ifndef GAME_H
#define GAME_H
#include <SDL.h>
#include <SDL_image.h>
#include <string.h>
#include <iostream>
#include <vector>
#include "TextureManager.h"
#include "Player.h"
class Game
{
public:
Game() {}
~Game() {}
bool init(const char* title, int xpos, int ypos, int width, int height, int flags);
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;
int m_currentFrame;
bool m_bRunning;
GameObject* m_go;
GameObject* m_player;
std::vector<GameObject*> m_gameObjects;
};
#endif
Game.cpp
#include "Game.h"
typedef TextureManager TheTextureManager; // Singleton TextureManager
Game* g_game = 0; // Game Object
bool Game::init(const char* title, int xpos, int ypos, int width,int height, int flags)
{
// attempt to initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
std::cout << "SDL init success\n";
// init the window
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,255,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_go = new GameObject();
m_player = new Player();
m_go->load(100, 100, 96, 60, "assets/simba.bmp", "animate",m_pRenderer);
m_player->load(300, 300, 96, 60, "assets/download.bmp", "animate",m_pRenderer);
m_gameObjects.push_back(m_go);
m_gameObjects.push_back(m_player);
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
//m_go.draw(m_pRenderer);
//m_player.draw(m_pRenderer);
for(std::vector<GameObject*>::size_type i = 0; i != m_gameObjects.size(); i++)
{
m_gameObjects[i]->draw(m_pRenderer);
}
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;
if(SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
m_bRunning = false;
break;
default:
break;
}
}
}
void Game::update()
{
//m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
//m_go.update();
//m_player.update();
for(std::vector<GameObject*>::size_type i = 0; i != m_gameObjects.size(); i++)
{
m_gameObjects[i]->update();
}
}
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->render();
g_game->handleEvents();
g_game->update();
SDL_Delay(10); // add the delay
}
g_game->clean();
return 0;
}
As you can see at the end of the init function, I have m_go load up simba, and m_player load up download. Even though they move in different directions (GameObject moves to the right and Player moves to the left as you can see in the classes in update method).
My program only loads download for both.
I'm not sure if the TextureManager class is related but I'll post it anyway
TextureManager.h
#ifndef TEXTUREMANAGER_H
#define TEXTUREMANAGER_H
#include <SDL.h>
#include <SDL_image.h>
#include <string.h>
#include <iostream>
#include <map>
class TextureManager
{
public:
bool load(std::string fileName,std::string id,SDL_Renderer* pRenderer);
void draw(std::string id, int x, int y, int width, int height, SDL_Renderer* pRenderer, SDL_RendererFlip flip = SDL_FLIP_NONE);
void drawFrame(std::string id, int x, int y, int width, int height, int currentRow, int currentFrame, SDL_Renderer* pRenderer, SDL_RendererFlip flip = SDL_FLIP_NONE);
std::map <std::string, SDL_Texture*> m_textureMap;
static TextureManager* Instance()
{
if(s_pInstance == 0)
{
s_pInstance = new TextureManager();
return s_pInstance;
}
return s_pInstance;
}
//typedef TextureManager TheTextureManager;
protected:
private:
TextureManager(){}
static TextureManager* s_pInstance;
};
#endif // TEXTUREMANAGER_H
TextureManager.cpp
#include "TextureManager.h"
TextureManager* TextureManager::s_pInstance = 0;
bool TextureManager::load(std::string fileName, std::string id, SDL_Renderer* pRenderer)
{
SDL_Surface* pTempSurface = IMG_Load(fileName.c_str());
if(pTempSurface == 0)
{
return false;
}
SDL_Texture* pTexture =
SDL_CreateTextureFromSurface(pRenderer, pTempSurface);
SDL_FreeSurface(pTempSurface);
// everything went ok, add the texture to our list
if(pTexture != 0)
{
m_textureMap[id] = pTexture;
return true;
}
// reaching here means something went wrong
return false;
}
void TextureManager::draw(std::string id, int x, int y, int width, int height, SDL_Renderer* pRenderer, SDL_RendererFlip flip)
{
SDL_Rect srcRect;
SDL_Rect destRect;
srcRect.x = 0;
srcRect.y = 0;
srcRect.w = destRect.w = width;
srcRect.h = destRect.h = height;
destRect.x = x;
destRect.y = y;
SDL_RenderCopyEx(pRenderer, m_textureMap[id], &srcRect,
&destRect, 0, 0, flip);
}
void TextureManager::drawFrame(std::string id, int x, int y, int width, int height, int currentRow, int currentFrame, SDL_Renderer *pRenderer, SDL_RendererFlip flip)
{
SDL_Rect srcRect;
SDL_Rect destRect;
srcRect.x = width * currentFrame;
srcRect.y = height * (currentRow - 1);
srcRect.w = destRect.w = width;
srcRect.h = destRect.h = height;
destRect.x = x;
destRect.y = y;
SDL_RenderCopyEx(pRenderer, m_textureMap[id], &srcRect,
&destRect, 0, 0, flip);
}
You are using "animate" more than once for the textureID - this needs to be unique
Your Code:
m_go->load(100, 100, 96, 60, "assets/simba.bmp", "animate", m_pRenderer);
m_player->load(300, 300, 96, 60, "assets/download.bmp", "animate", m_pRenderer)
What happens is the texture is loaded but it overwrites the existing texture which has the "animate" key in the map. Make them unique and this should resolve your issue.
For some strange reason whenever I try to split a larger image file into (in my case) a 32x32 picture, but instead I get the entire picture that seems to be squished down into 32x32(the picture as a whole). Although after playing around with the values I realized that for some reason the SDL has completely ignored my request to use the SDL_Rect source(src).
Meaning that every value that I change the source(src) rectangle to doesn't change the actual image when I run the program (even a ridiculous value).
Sprite.h
#ifndef SPRITE_H_
#define SPRITE_H_
#pragma once
#include "Game.h"
struct Game;
struct Sprite
{
//Needs to be fixed :/
//Sprite(const std::string& filepath,int x,int y,int width, int height,Game*game);
Sprite();
~Sprite();
void Load(const std::string& filepath, int x, int y,int width,int height, Game*game);
void Draw(Game*game);
SDL_Rect*getDstRect(){ return &dst; }
SDL_Rect*getSrcRect(){ return &src; }
private:
SDL_Surface*surface = NULL;
SDL_Texture*texture = NULL;
SDL_Rect src;
SDL_Rect dst;
int img_width;
int img_height;
};
#endif // SPRITE_H_
Sprite.cpp
#include "Sprite.h"
Sprite::Sprite()
{
}
Sprite::~Sprite()
{
SDL_DestroyTexture(texture);
surface = NULL;
texture = NULL;
}
void Sprite::Load(const std::string& filepath, int x, int y, int width, int height, Game*game)
{
bool success = true;
surface = IMG_Load(filepath.c_str());
if (surface == NULL)
{
game->getConsole()->Error("SPRITE::Surface Is Not Loaded");
success = false;
}
else
game->getConsole()->Text("SPRITE::Surface Is Loaded");
texture = SDL_CreateTextureFromSurface(game->getRenderer(), surface);
if (texture == NULL)
{
game->getConsole()->Error("SPRITE::Texture Is Not Loaded");
success = false;
}
else
game->getConsole()->Text("SPRITE::Texture is Loaded");
dst.x = x;
dst.y = y;
dst.w = height;
dst.h = height;
src.x = 0;
src.y = 0;
src.w = 0;
src.h = 0;
SDL_QueryTexture(texture, NULL, NULL, &src.w, &src.h);
SDL_FreeSurface(surface);
if (success)
game->getConsole()->Text("Loaded Sprite at " + filepath);
else
game->getConsole()->Error("SPRITE::Failed To Load Sprite at " + filepath);
}
void Sprite::Draw(Game*game)
{
SDL_RenderCopy(game->getRenderer(), texture, &src,&dst);
}
Part of the Map Class
testPlayer.Load("bin/sprites/player.png", 200,200,32,32, game);
This is where I have tried to change the values of the destination(dst) rectangle after messing with the source(src) rectangle.
https://wiki.libsdl.org/SDL_RenderCopy
dstrect - the destination SDL_Rect structure or NULL for the entire rendering target. The texture will be stretched to fill the given rectangle.
Short version - adjust source rect to have the same width and height as destination rect, and {x, y} to have starting position of fragment you want to extract.