Related
so i've been working on a game system/engine, for my 2D Platformer, and when i press the w, a, s, or d keys it won't move when called in the main loop event.
Here is all of my project files and everything that i've written:
main.cpp:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
#include "RenderWindow.hpp"
#include "Entity.hpp"
#include "Utils.hpp"
int main(int argc, char const *argv[])
{
if (SDL_Init(SDL_INIT_VIDEO) > 0)
std::cout << "ERROR: SDL_Init() HAS FAILED: SDL_ERROR => " << SDL_GetError() << std::endl;
if (!(IMG_Init(IMG_INIT_PNG)))
std::cout << "ERROR: IMG_Init() HAS FAILED: SDL_ERROR => " << SDL_GetError() << std::endl;
RenderWindow window("GAME v1.0", 1280, 720);
SDL_Texture* grassTexture = window.loadTexture("res/gfx/ground_grass.png");
SDL_Texture* playerTexture = window.loadTexture("res/gfx/ghost.png");
std::vector<Entity> platforms = {Entity(Vector2f(0, 30), grassTexture),
Entity(Vector2f(30, 30), grassTexture),
Entity(Vector2f(30, 30), grassTexture),
Entity(Vector2f(60, 30), grassTexture)};
Entity player(Vector2f(30, 8), playerTexture);
bool gameRunning = true;
SDL_Event event;
const float timeStep = 0.01f;
float accumulator = 0.0f;
float currentTime = utils::hireTimeInSeconds();
while(gameRunning)
{
int startTicks = SDL_GetTicks();
float newTime = utils::hireTimeInSeconds();
float frameTime = newTime - currentTime;
currentTime = newTime;
accumulator += frameTime;
while(accumulator >= timeStep)
{
// Get out controls and events
while(SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
gameRunning = false;
break;
// window.freeTexture(grassTexture);
// window.freeTexture(playerTexture);
}
// Add code to move the player texture
const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL);
Vector2f& playerPos = player.getPos();
if(currentKeyStates[SDL_SCANCODE_W]) {
playerPos.y -= 1;
break;
}
if(currentKeyStates[SDL_SCANCODE_S]) {
playerPos.y += 1;
break;
}
if(currentKeyStates[SDL_SCANCODE_A]) {
playerPos.x -= 1;
break;
}
if(currentKeyStates[SDL_SCANCODE_D]) {
playerPos.x += 1;
break;
}
}
window.clear();
for (Entity& e : platforms)
{
window.render(e);
window.render(player);
}
window.display();
// // Add code to move the player texture
// const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL);
// Vector2f& playerPos = player.getPos();
// if(currentKeyStates[SDL_SCANCODE_W]) {
// playerPos.y -= 1;
// }
// if(currentKeyStates[SDL_SCANCODE_S]) {
// playerPos.y += 1;
// }
// if(currentKeyStates[SDL_SCANCODE_A]) {
// playerPos.x -= 1;
// }
// if(currentKeyStates[SDL_SCANCODE_D]) {
// playerPos.x += 1;
// }
//playerPos.print();
accumulator -= timeStep;
// std::cout << accumulator << std::endl;
}
// const float alpha = accumulator / timeStep; // 50%?
// window.freeTexture(grassTexture);
// window.freeTexture(playerTexture);
int frameTicks = SDL_GetTicks() - startTicks;
if (frameTicks < 1000 / window.getRefreshRate())
SDL_Delay(100 / window.getRefreshRate() - frameTicks);
}
window.cleanUp();
SDL_Quit();
return 0;
}
renderwindow.hpp:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "Entity.hpp"
class RenderWindow
{
public:
RenderWindow(const char* p_title, int p_w, int p_h);
SDL_Texture* loadTexture(const char* p_filePath);
int getRefreshRate();
void cleanUp();
void clear();
void render(Entity& p_entity);
//void freeTexture(SDL_Texture* p_tex);
void display();
private:
SDL_Window* window;
SDL_Renderer* renderer;
};
renderwindow.cpp:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include "RenderWindow.hpp"
#include "Entity.hpp"
RenderWindow::RenderWindow(const char* p_title, int p_w, int p_h)
:window(NULL), renderer(NULL)
{
window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if (window == NULL)
{
std::cout << "ERROR: Window has failed to init! SDL_Error: " << SDL_GetError() << std::endl;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
}
SDL_Texture* RenderWindow::loadTexture(const char* p_filePath)
{
SDL_Texture* texture = NULL;
texture = IMG_LoadTexture(renderer, p_filePath);
if (texture == NULL)
std::cout << "ERROR: Failed to load texture! SDL_Error: " << SDL_GetError() << std::endl;
return texture;
}
int RenderWindow::getRefreshRate()
{
int displayIndex = SDL_GetWindowDisplayIndex(window);
SDL_DisplayMode mode;
SDL_GetDisplayMode(displayIndex, 0, &mode);
return mode.refresh_rate;
}
void RenderWindow::cleanUp()
{
SDL_DestroyWindow(window);
}
void RenderWindow::clear()
{
SDL_RenderClear(renderer);
}
void RenderWindow::render(Entity& p_entity)
{
SDL_Rect src;
src.x = p_entity.getCurrentFrame().x;
src.y = p_entity.getCurrentFrame().y;
src.w = p_entity.getCurrentFrame().w;
src.h = p_entity.getCurrentFrame().h;
SDL_Rect dst;
dst.x = p_entity.getPos().x * 4;
dst.y = p_entity.getPos().y * 4;
dst.w = p_entity.getCurrentFrame().w * 4;
dst.h = p_entity.getCurrentFrame().h * 4;
SDL_RenderCopy(renderer, p_entity.getTex(), &src, &dst);
}
// void RenderWindow::freeTexture(SDL_Texture* p_tex) {
// SDL_DestroyTexture(p_tex);
// }
void RenderWindow::display()
{
SDL_RenderPresent(renderer);
}
Entity.hpp:
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "Math.hpp"
class Entity
{
public:
Entity(Vector2f p_pos, SDL_Texture* p_tex);
Vector2f& getPos()
{
return pos;
}
void setPos(Vector2f p_pos)
{
pos = p_pos;
}
SDL_Texture* getTex();
SDL_Rect getCurrentFrame();
private:
Vector2f pos;
SDL_Rect currentFrame;
SDL_Texture* tex;
};
entity.cpp:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "Entity.hpp"
#include "Math.hpp"
Entity::Entity(Vector2f p_pos, SDL_Texture* p_tex)
:pos(p_pos), tex(p_tex)
{
currentFrame.x = 0;
currentFrame.y = 0;
currentFrame.w = 32;
currentFrame.h = 32;
}
SDL_Texture* Entity::getTex()
{
return tex;
}
SDL_Rect Entity::getCurrentFrame()
{
return currentFrame;
}
math.hpp:
#pragma once
#include <iostream>
struct Vector2f
{
Vector2f()
:x(0.0f), y(0.0f)
{}
Vector2f(float p_x, float p_y)
:x(p_x), y(p_y)
{}
void print()
{
std::cout << x << ", " << y << std::endl;
}
float x, y;
};
Utils.hpp:
#pragma once
#include <SDL2/SDL.h>
namespace utils
{
inline float hireTimeInSeconds()
{
float t = SDL_GetTicks();
t *= 0.001f;
return t;
}
}
Thanks!
This is an updated version of my code, i've figured it out.
It turns out the problem was:
if (frameTicks < 1000 / window.getRefreshRate())
SDL_Delay(100 / window.getRefreshRate() - frameTicks);
was actually delaying it by 100 instead of 1000.
Rendering individual textures was no problem at all, though after i wrapped these textures in an entity class, and put these in a vector, things just didn't work anymore (renders black screen). Anyone got a clue why?
main.cpp
#include "RenderWindow.hpp"
#include "vec.h"
#include "entity.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>
#include <vector>
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) > 0) {
std::cout << "Could not Init VIDEO, Error: " << SDL_GetError() << std::endl;
return 0;
}
if (!IMG_Init(IMG_INIT_PNG)) {
std::cout << "Could not Init IMG, Error: " << SDL_GetError() << std::endl;
return 0;
}
RenderWindow r("Bread.", 600, 600);
// entity vector
std::vector<Entity> entities = {Entity(Vec2i{5, 5}, r.CreateTexture("res/gfx/bob.png"))};
// single entity
Entity bob(Vec2i{5, 5}, r.CreateTexture("res/gfx/bob.png"));
bool running = true;
SDL_Event event;
while (running) {
Uint64 start = SDL_GetPerformanceCounter();
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
}
r.Clear();
// doesn't render (black screen)
for (const Entity& e : entities) {
r.RenderEntity(e);
}
// renders fine
r.RenderEntity(bob);
r.Display();
Uint64 end = SDL_GetPerformanceCounter();
float elapsedMS = (end - start) / (float)SDL_GetPerformanceFrequency() * 1000.0f;
SDL_Delay(floor(16.666f - elapsedMS));
}
return 0;
}
RenderWindow.cpp
#include "RenderWindow.hpp"
#include <iostream>
RenderWindow::RenderWindow(const char* p_title, int32_t p_w, int32_t p_h)
: window(NULL), renderer(NULL) {
this->window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if (this->window == NULL) {
std::cout << "Failed to initialize window, Error: " << SDL_GetError() << std::endl;
}
this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED);
if (this->renderer == NULL) {
std::cout << "Failed to initialize renderer, Error: " << SDL_GetError() << std::endl;
}
}
RenderWindow::~RenderWindow() {
SDL_DestroyWindow(this->window);
SDL_DestroyRenderer(this->renderer);
SDL_Quit();
}
SDL_Texture* RenderWindow::CreateTexture(const char* p_path) {
return IMG_LoadTexture(this->renderer, p_path);
}
void RenderWindow::Clear() {
SDL_RenderClear(this->renderer);
}
void RenderWindow::RenderTexture(SDL_Texture* p_texture) {
SDL_RenderCopy(this->renderer, p_texture, NULL, NULL);
}
// **mentioned method**
// takes const Entity& and renders it's texture
void RenderWindow::RenderEntity(const Entity& p_entity) {
SDL_RenderCopy(this->renderer, p_entity.GetTexture(), NULL, NULL);
}
void RenderWindow::Display() {
SDL_RenderPresent(this->renderer);
}
and finally entity.cpp
#include "entity.h"
Entity::Entity(Vec2i p_pos, SDL_Texture* p_texture)
: pos(p_pos), texture(p_texture) {}
Entity::Entity()
: pos(Vec2i{0, 0}), texture(NULL) {}
Entity::~Entity() {
SDL_DestroyTexture(this->texture);
}
void Entity::SetPos(Vec2i p_pos) { this->pos = p_pos; }
const Vec2i& Entity::GetPos() const { return this->pos; }
void Entity::SetTexture(SDL_Texture* p_texture) { this->texture = p_texture; }
// used to get texture of entity to pass to renderer
SDL_Texture* Entity::GetTexture() const { return this->texture; }
void Entity::Move(Vec2i p_pos) {
this->pos = p_pos;
}
void Entity::Move(size_t p_x, size_t p_y) {
this->pos.x += p_x;
this->pos.y += p_y;
}
The creation of entities requires a temporary Entity, which is destroyed afterwards. Since you did not implement a copy constructor, this leaves the new Entity with a dangling pointer to a freed object.
The quickest fix is to change the type of Entity::texture to std::shared_ptr<SDL_Texture>.
Alternatively, you can create a move constructor and prevent copy constructors:
Entity::Entity(const Entity&) = delete;
Entity::Entity(Entity&& other)
: pos(other.pos), texture(nullptr) {
std::swap(texture, other.texture);
}
The problem I'm having is that when I change an attribute of an Object the change isn't 'saving'. Easier to show you what's happening.
I'm learning c++ and decided to build a small chess app. Each Piece is a seperate Object.
They're stored in a std::vector as such
std::vector<Piece> pieces;
They're initialised like so
for (int i = 0; i < 2; i++)
{
Piece p;
p.Init(i*2+1, 1, renderer, SQUARE_SIZE, "king");
pieces.push_back(p);
}
When I click the mouse I want to select all pieces (temporarily)
for (int i = 0; i < pieces.size(); i++)
{
Piece p = pieces[i];
p.Select();
}
The issue is that while the Select() function is being called, by the time I get to rendering their selected attribute is false. Strangely this does not happen to the piece not contained within in the vector, referred to as k.
Before you ask there is nowhere in my code that I set selected to false :) (Except the constructor :P )
Also if you feel like downvoting, send me a comment first and I'll try fix whatever it is!
Here are the entire files. (not sure if this is the proper way to insert them)
Piece.h
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDl_image.h>
#include <array>
#include <vector>
class Piece
{
public:
Piece();
void Init(int _x, int _y, SDL_Renderer* renderer, int SQUARE_SIZE, std::string type);
void SetPos(int _x, int _y, int _w);
void LoadTexture(SDL_Renderer* renderer, std::string type);
void LoadMovementVector(std::string type);
void Render(SDL_Renderer* renderer);
void Select(){ selected = true; std::cout << "called\n";}
bool isSelected(){ return selected; }
int GetX(){ return x; } // SDL_Point
int GetY(){ return y; }
private:
int x, y;
std::vector<int> move_vector;
bool selected;
SDL_Rect rect;
SDL_Texture* texture;
};
Piece.cpp
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDl_image.h>
#include <vector>
#include "Piece.h"
Piece::Piece()
: x(0)
, y(0)
, selected(false)
{
}
void Piece::Init(int _x, int _y, SDL_Renderer* renderer, int SQUARE_SIZE, std::string type)
{
SetPos(_x, _y, SQUARE_SIZE);
LoadTexture(renderer, type);
LoadMovementVector(type);
}
void Piece::Render(SDL_Renderer* renderer)
{
//selected = true;
//std::cout << selected << std::endl;
if (selected)
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
if (texture != nullptr)
{
SDL_RenderCopy(renderer, texture, nullptr, &rect);
}
else
{
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL_RenderFillRect(renderer, &rect);
}
}
void Piece::LoadMovementVector(std::string type)
{
if (type == "king"){ // There literally has to be a better way to init std::vector
int arr[4] = {1,1,1,0};
for (int i = 0; i < 4; i++){ move_vector.push_back(arr[i]); }
}
for (int i = 0; i < move_vector.size(); i++)
{
std::cout << move_vector[i];
}
std::cout << std::endl;
}
void Piece::LoadTexture(SDL_Renderer* renderer, std::string type)
{
std::string source;
if (type == "king"){
source = "wk.png";
}
texture = IMG_LoadTexture(renderer, "res/wk.png");
}
void Piece::SetPos(int _x, int _y, int _w)
{
x = _x;
y = _y;
rect.x = _w*(_x-1);
rect.y = _w*(8-_y);
rect.w = _w;
rect.h = _w;
std::cout << x << y << std::endl;
}
Main.cpp
#include <iostream>
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDl_image.h>
#include "Piece.h"
using namespace std::chrono;
// Would be 'const int' but I want to make the board resizeable
int SCREEN_WIDTH = 800;
int SCREEN_HEIGHT = 800;
int BOARD_WIDTH, BOARD_HEIGHT, SQUARE_SIZE;
SDL_Window* window;
SDL_Renderer* renderer;
std::vector<Piece> pieces;
Piece k;
bool InitEverything();
bool InitSDL();
bool CreateWindow();
bool CreateRenderer();
void SetupRenderer();
void Quit();
void RunGame();
void Render();
void HandleInput();
void UpdateDimensions();
double GetDelta();
void RenderGameBoard();
bool loop = true;
auto timePrev = high_resolution_clock::now();
int main(int argc, char* args[])
{
if (!InitEverything())
return -1;
std::cout << "Running Game..." << std::endl;
for (int i = 0; i < 2; i++)
{
Piece p;
p.Init(i*2+1, 1, renderer, SQUARE_SIZE, "king");
pieces.push_back(p);
}
k.Init(5, 1, renderer, SQUARE_SIZE, "king");
RunGame();
Quit();
return 0;
}
void RunGame()
{
while (loop)
{
HandleInput();
Render();
double delta = GetDelta();
}
}
void Render()
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderClear(renderer);
RenderGameBoard();
for (int i = 0; i < pieces.size(); i++)
{
pieces[i].Render(renderer);
}
k.Render(renderer);
SDL_RenderPresent(renderer);
}
void RenderGameBoard()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if ((j%2==0&&i%2==0)||(j%2!=0&&i%2!=0))
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
else
SDL_SetRenderDrawColor(renderer, 180, 180, 180, 255);
SDL_Rect r = {i*SQUARE_SIZE, j*SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE};
SDL_RenderFillRect(renderer, &r);
}
}
}
void HandleInput()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
loop = false;
else if (event.type == SDL_KEYDOWN)
{
}
else if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
k.Select();
for (int i = 0; i < pieces.size(); i++)
{
Piece p = pieces[i];
p.Select();
}
int x = floor(event.button.x/SQUARE_SIZE)+1;
int y = 8-floor(event.button.y/SQUARE_SIZE);
for (int i = 0; i < pieces.size(); i++)
{
Piece p = pieces[i];
if (p.GetX() == x && p.GetY() == y)
{
p.Select();
}
}
}
}
}
}
void UpdateDimensions()
{
BOARD_WIDTH = SCREEN_WIDTH;
BOARD_HEIGHT = SCREEN_HEIGHT;
SQUARE_SIZE = BOARD_WIDTH/8;
}
double GetDelta()
{
auto timeCurrent = high_resolution_clock::now();
auto timeDiff = duration_cast< nanoseconds >( timeCurrent - timePrev );
double delta = timeDiff.count();
delta /= 1000000000;
timePrev = timeCurrent;
return delta;
}
bool InitEverything()
{
if (!InitSDL())
return false;
if (!CreateWindow())
return false;
if (!CreateRenderer())
return false;
SetupRenderer();
UpdateDimensions();
return true;
}
bool InitSDL()
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL failed to initialize : " << SDL_GetError() << std::endl;
return false;
}
return true;
}
bool CreateWindow()
{
window = SDL_CreateWindow("Chess", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (!window)
{
std::cout << "Failed to create window : " << SDL_GetError() << std::endl;
return false;
}
return true;
}
bool CreateRenderer()
{
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer)
{
std::cout << "Failed to create renderer : " << SDL_GetError() << std::endl;
return false;
}
return true;
}
void SetupRenderer()
{
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
}
void Quit()
{
SDL_DestroyWindow(window);
SDL_Quit();
}
This:
Piece p = pieces[i];
is creating a copy of the piece at index i in the vector.
Any methods you call after that are operating on the copy, not on the piece in the array.
Instead, take a reference to it:
Piece& p = pieces[i];
After that, p is a reference to element i in the vector and any operations you perform on it are performed on the vector element.
i am following SDL game development book by shaun mitcchel and was trying to compile the code and was getting error of constructor is private. i am using mingw for compiling.
main.cpp
#include "game.h"
game* g_game = 0;
int main(int argc, char* args[])
{
g_game = new game;
g_game->init("SDL",100,100,640,480,SDL_WINDOW_SHOWN);
while(g_game->running())
{
g_game->handleEvents();
g_game->update();
g_game->render();
}
g_game->clean();
return 0;
}
game.h
#ifndef GAME_H
#define GAME_H
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>
#include "TextureManager.h"
class game
{
public:
game(){}
virtual ~game();
bool init(char* title, int xpos, int ypos, int width, int height, int flags);
void render();
void update();
void handleEvents();
void clean();
bool running()
{
return m_bRunning;
}
protected:
private:
SDL_Window* m_pWindow;
SDL_Renderer* m_pRenderer;
int m_currentFrame;
textureManager m_textureManager;
bool m_bRunning;
};
#endif // GAME_H
game.cpp
#include "game.h"
bool game::init(char* title,int xpos, int ypos, int width, int height,int flags)
{
//initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING)== 0)
{
std::cout << "SDL init success\n";
//init window
m_pWindow = SDL_CreateWindow(title,xpos,ypos,width,height,flags);
if(m_pWindow != 0)
{
std::cout << "window creation successful\n";
m_pRenderer = SDL_CreateRenderer(m_pWindow,-1,0);
if(m_pRenderer != 0) {
std::cout << "render init success\n";
SDL_SetRenderDrawColor(m_pRenderer,255,0,0,255);
}
else {
std::cout << "render init fail\n";
return false;
}
}
else {
std::cout << "Window init fail\n";
return false;
}
}
else {
std::cout << "Sdl init failed\n";
return false;
}
std::cout << "init success\n";
m_bRunning = true;
//to load
if(!ThetextureManager::Instance()->load("assets/animate- alpha.png","animate",m_pRenderer))
{
return false;
}
}
void game::render()
{
SDL_RenderClear(m_pRenderer);
ThetextureManager::Instance()->draw("animate", 0, 0,128,82,m_pRenderer);
ThetextureManager::Instance()->drawFrame("animate", 100,100,128,82,1,m_currentFrame,m_pRenderer);
SDL_RenderPresent(m_pRenderer);
}
void game::handleEvents()
{
SDL_Event event;
if(SDL_PollEvent(&event)) {
switch(event.type)
{
case SDL_QUIT:
m_bRunning = false;
break;
default:
break;
}
}
}
void game::clean()
{
std::cout << "cleaning game\n";
SDL_DestroyRenderer(m_pRenderer);
SDL_DestroyWindow(m_pWindow);
SDL_Quit();
}
void game::update()
{
m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
}
TextureManager.h
#ifndef TEXTUREMANAGER_H_INCLUDED
#define TEXTUREMANAGER_H_INCLUDED
#include <iostream>
#include<map>
#include<SDL.h>
#include<SDL_image.h>
class textureManager {
public:
static textureManager* Instance()
{
if(s_pInstance == 0)
{
s_pInstance = new textureManager();
return s_pInstance;
}
return s_pInstance;
}
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);
void drawFrame(std::string id, int x, int y, int width, int height, int currentRow, int currentFrame, SDL_Renderer* pRenderer,SDL_RendererFlip flip);
std::map<std::string, SDL_Texture*> m_textureMap;
private:
textureManager() {}
textureManager(const textureManager&);
textureManager& operator=(const textureManager&);
static textureManager* s_pInstance;
};
typedef textureManager ThetextureManager;
#endif // TEXTUREMANAGER_H_INCLUDED
texturemanagement.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);
if(pTexture != 0)
{
m_textureMap[id] = pTexture;
return true;
}
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);
}
errors
C:\Users\lenovo\Desktop\node project\sdl\TextureManager.h||In constructor 'game::game()':|
C:\Users\lenovo\Desktop\node project\sdl\TextureManager.h|28|error: 'textureManager::textureManager()' is private|
C:\Users\lenovo\Desktop\node project\sdl\game.h|12|error: within this context|
C:\Users\lenovo\Desktop\node project\sdl\game.cpp||In member function 'void game::render()':|
C:\Users\lenovo\Desktop\node project\sdl\game.cpp|46|error: no matching function for call to 'textureManager::draw(const char [8], int, int, int, int, SDL_Renderer*&)'|
C:\Users\lenovo\Desktop\node project\sdl\game.cpp|47|error: no matching function for call to 'textureManager::drawFrame(const char [8], int, int, int, int, int, int&, SDL_Renderer*&)'|
You have textureManager m_textureManager member in class game (file game.h)
But in game.cpp you always use ThetextureManager::Instance()
You just need to remove m_textureManager member.
So I am making a 2D platformer using SDL. I have experience in C/C++, but I haven't really written anything with it in the past 8 months. I'm using SDL to render my graphics, and I get an entirely blank screen, and I can't really seem to figure out why. Can anybody help me figure out why this isn't rendering?
EDIT: I added the extra code that was missing.
Map.cpp
#include "Map.h"
int map[10][10] = { {0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0}
};
Map::Map()
: g( Graphics() )
{
grassTile = SDL_LoadBMP("grass.bmp");
}
Map::~Map()
{
}
void Map::renderMap()
{
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
int newPos = map[y][x];
if (newPos == 0)
{
g.drawImage(x * 32, y * 32, grassTile);
}
}
}
}
Graphics.cpp
#include "Graphics.h"
#include <iostream>
#include <SDL.h>
#include <Windows.h>
using namespace std;
Graphics::Graphics()
: count( 0 )
{
}
Graphics::~Graphics()
{
}
int Graphics::getWidth(int i)
{
return this->width = i;
}
int Graphics::getHeight(int i)
{
return this->height = i;
}
void Graphics::initScreen(int width,int height, char* title)
{
if (!SDL_Init(SDL_INIT_EVERYTHING) == 1)
{
cout << "SDL is running" << endl;
}
SDL_WM_SetCaption(title,NULL);
screen = SDL_SetVideoMode(width,height,8,NULL);
getWidth(width);
getHeight(height);
}
void Graphics::beginFrame()
{
SDL_FillRect(screen,NULL,0x000000);
}
void Graphics::repaint()
{
SDL_Flip(screen);
}
void Graphics::loadImage(char* location, SDL_Surface* sur)
{
sur = SDL_LoadBMP(location);
}
void Graphics::renderTileMap(SDL_Surface* sur, int width, int height, int amountX, int amountY)
{
for (int y = 0; y < amountY; y++)
{
for (int x = 0; x < amountX; x++)
{
drawImage(x * width, y * height, sur);
}
}
}
void Graphics::pixel(int x,int y, int r,int g, int b)
{
if (screen != NULL)
{
if (screen->pixels != NULL)
{
Uint8* pixels = (Uint8*)screen->pixels;
Uint8* indevidualPixel = pixels + (y * screen->pitch) + x;
*indevidualPixel = SDL_MapRGB(screen->format,r,g,b);
}
}
}
void Graphics::drawImage(int x,int y, SDL_Surface* sur)
{
SDL_Rect rect;
rect.x = x;
rect.y = y;
SDL_BlitSurface(sur,NULL,screen,&rect);
}
Main.cpp>
#include <SDL.h>
#include <cstdio>
#include "Graphics.h"
#include "Keyboard.h"
#include "Game.h"
SDL_Event event;
bool running = true;
Game game = Game();
int main(int argc, char* argv[])
{
game.k = Keyboard();
game.g.initScreen(900,500, "theDevCorner's SDL Tutorials!!!");
while (running)
{
SDL_PollEvent(&event);
if (event.type == SDL_QUIT)
{
running = false;
}
if (event.type == SDL_KEYUP)
{
SDLKey keyReleased = event.key.keysym.sym;
if (keyReleased == SDLK_RIGHT)
{
game.k.right = false;
}
if (keyReleased == SDLK_LEFT)
{
game.k.left = false;
}
if (keyReleased == SDLK_DOWN)
{
game.k.down = false;
}
if (keyReleased == SDLK_UP)
{
game.k.up = false;
}
}
if (event.type == SDL_KEYDOWN)
{
SDLKey keyPressed = event.key.keysym.sym;
if (keyPressed == SDLK_RIGHT)
{
game.k.right = true;
}
if (keyPressed == SDLK_LEFT)
{
game.k.left = true;
}
if (keyPressed == SDLK_DOWN)
{
game.k.down = true;
}
if (keyPressed == SDLK_UP)
{
game.k.up = true;
}
}
game.g.beginFrame();
game.render();
game.g.repaint();
}
return 0;
};
Game.cpp
#include "Game.h"
Game::Game()
: g(Graphics()),
x( 0 ),
y( 0 ),
m( Map() )
{
image = SDL_LoadBMP("grass.bmp");
}
Game::~Game()
{
}
void Game::keyLogic()
{
if (k.right)
{
x += 5;
}
if (k.left)
{
x -= 5;
}
if (k.down)
{
y += 5;
}
if (k.up)
{
y -= 5;
}
}
void Game::update()
{
if (count < 10)
{
count++;
}
if (count == 10)
{
keyLogic();
count = 0;
}
}
void Game::render()
{
update();
m.renderMap();
}
You have two instances of Graphics, one in Game and one in Map. You call Graphics::initScreen on the one in the Game instance game, but later you try to render in the Graphics instance of the Map instance game.m, where the SDL surface screen is uninitialized. Specifically game.render(); calls game.m.renderMap();, which calls game.m.g.drawImage(...).
Decide for one location of the Graphics instance or use references.