I am making a tile-based game using C++ and SDL. I've been writing a library to make certain parts of it easier. My current problem is that I have a player that has a spritesheet that has images for each possible direction. Its dimensions are 128x32, with each sprite being 32x32. The rpoblem is that if i try to access anything besides the sprite at the first position at vector, it doesn't return an image. I also have a spritesheet for the terrain, but it renders fine no matter which sprite I choose, but it is 512x512.
Spritesheet.hpp
#ifndef SPRITESHEET_HPP_INCLUDED
#define SPRITESHEET_HPP_INCLUDED
#include <vector>
#include "Image.hpp"
#include "Primitives.hpp"
#include "General.hpp"
/**
* \file
* \brief File that contains everything needed to load nad handle a spritesheet.
* \author Dante12129
* \version 1.0
*/
namespace grnbll
{
class Spritesheet : public Applyable
{
public:
//Constructors and destructor
Spritesheet();
Spritesheet(std::string filename, unsigned int width, unsigned int height, unsigned int sprite_width, unsigned int sprite_height);
~Spritesheet();
//Getters
unsigned int GetSpriteWidth();
unsigned int GetSpriteHeight();
Rectangle& GetSprite(int spritenumber);
SDL_Surface* GetSurface();
//Manipulation Functions
int MakeTransparent(uint8_t r, uint8_t g, uint8_t b);
private:
//Container of all the coordinates of the images
std::vector<Rectangle> sprites;
//Height and width of the whole image
unsigned int whole_width, whole_height;
//Height and width of a single sprite
unsigned int m_sprite_width, m_sprite_height;
//The image of the spritesheet
Image m_img_whole;
//Number of sprites in the image
int m_num_of_sprites, m_sprites_per_row, m_sprites_per_column;
//The name of the spritesheet for the file
std::string m_filename;
};
}
#endif // SPRITESHEET_HPP_INCLUDED
Spritesheet.cpp
#include "Spritesheet.hpp"
//Spritesheet
//Constructors and destructor
grnbll::Spritesheet::Spritesheet()
{
//Initalize all sizes to 0
whole_width = 0; whole_height = 0; m_sprite_width = 0; m_sprite_height = 0;
m_num_of_sprites = 0; m_sprites_per_row = 0; m_sprites_per_column = 0;
//The image and vector don't contain anything
//Set the filename to nothing
m_filename = "";
}
grnbll::Spritesheet::Spritesheet(std::string filename, unsigned int width, unsigned int height, unsigned int sprite_width, unsigned int sprite_height)
{
//Initalize the sizes
whole_width = width; whole_height = height; m_sprite_width = sprite_width; m_sprite_height = sprite_height;
m_sprites_per_row = whole_width/m_sprite_width; m_sprites_per_column = whole_height/m_sprite_height; m_num_of_sprites = m_sprites_per_row*m_sprites_per_column;
//Initialize the image
m_img_whole = Image(width, height, filename);
//Initialize the vector so that sprites can be accessed
if(m_sprites_per_column == 1)
{
for(int i = 0; i < m_sprites_per_row; i++)
{
sprites.push_back(Rectangle(i*m_sprite_width, 0, m_sprite_width, m_sprite_height));
}
}
else if(m_sprites_per_row == 1)
{
for(int i = 0; i < m_sprites_per_column; i++)
{
sprites.push_back(Rectangle(0, i*m_sprite_width, m_sprite_width, m_sprite_height));
}
}
else
{
for(int i = 0; i < m_sprites_per_row; i++)
{
for(int j = 0; j < m_sprites_per_column; j++)
{
sprites.push_back(Rectangle(j*m_sprite_width, i*m_sprite_height, m_sprite_width, m_sprite_height));
}
}
}
}
grnbll::Spritesheet::~Spritesheet() = default;
//Getters
unsigned int grnbll::Spritesheet::GetSpriteWidth() { return m_sprite_width; }
unsigned int grnbll::Spritesheet::GetSpriteHeight() { return m_sprite_height; }
grnbll::Rectangle& grnbll::Spritesheet::GetSprite(int spritenumber){ return sprites.at(spritenumber); }
SDL_Surface* grnbll::Spritesheet::GetSurface() { return m_img_whole.GetSurface(); }
//Manipulation functions
int grnbll::Spritesheet::MakeTransparent(uint8_t r, uint8_t g, uint8_t b)
{
return m_img_whole.MakeTransparent(r, g, b);
}
Player.hpp
#ifndef PLAYER_HPP_INCLUDED
#define PLAYER_HPP_INCLUDED
#include "New_Engine.hpp"
namespace survgame
{
enum class Directions
{
Up = 3,
Down = 1,
Left = 2,
Right = 0
};
class Player : public grnbll::Applyable
{
public:
//Constructors and destructor
Player(int start_x, int start_y, Directions starting_direction, std::string filename);
~Player();
//Getters
int GetX();
int GetY();
int GetXOld();
int GetYOld();
//Setters
void SetX(int x);
void SetY(int y);
void SetXOld(int x);
void SetYOld(int y);
//Handlers
void HandleEvents(grnbll::Event& event);
SDL_Surface* GetSurface();
grnbll::Rectangle& GetDirection();
private:
//Position variables
int x_pos, y_pos;
int x_old, y_old;
Directions facing_direction;
//The spritesheet for the player
grnbll::Spritesheet player_sprites;
};
}
#endif // PLAYER_HPP_INCLUDED
Player.cpp
#include "Player.hpp"
//Player
//Constructors and destructor
survgame::Player::Player(int start_x, int start_y, Directions starting_direction, std::string filename)
{
//Initialize the positions and the direction.
x_pos = start_x; y_pos = start_y;
x_old = start_x; y_old = start_y;
facing_direction = starting_direction;
//Load the spritesheet.
player_sprites = grnbll::Spritesheet(filename, 128, 32, 32 ,32);
player_sprites.MakeTransparent(0xED, 0x0B, 0xB5);
}
survgame::Player::~Player() = default;
//Getters
int survgame::Player::GetX() { return x_pos; }
int survgame::Player::GetY() { return y_pos; }
int survgame::Player::GetXOld() { return x_old; }
int survgame::Player::GetYOld() { return y_old; }
//Setters
void survgame::Player::SetX(int x) { x_pos = x; }
void survgame::Player::SetY(int y) { y_pos = y; }
void survgame::Player::SetXOld(int x) { x_old = x; }
void survgame::Player::SetYOld(int y) { y_old = y; }
//Handlers
void survgame::Player::HandleEvents(grnbll::Event& event)
{
x_old = x_pos;
y_old = y_pos;
if(event.GetOther().other == grnbll::OtherEvents::KeyPress)
{
switch(event.GetKeyboard().key)
{
case grnbll::Keys::Left:
x_pos--;
facing_direction = Directions::Left;
break;
case grnbll::Keys::Right:
x_pos++;
facing_direction = Directions::Right;
break;
case grnbll::Keys::Up:
y_pos--;
facing_direction = Directions::Up;
break;
case grnbll::Keys::Down:
y_pos++;
facing_direction = Directions::Down;
break;
}
}
}
SDL_Surface* survgame::Player::GetSurface() { return player_sprites.GetSurface(); }
grnbll::Rectangle& survgame::Player::GetDirection() { return player_sprites.GetSprite(0); }
main.cpp
#include <fstream>
#include <cstdlib>
#include "New_Engine.hpp"
#include "Player.hpp"
int main ( int argc, char* argv[] )
{
//Variables necessary to the screen and program
grnbll::Screen screen(512, 612, "Game");
grnbll::Event event;
grnbll::FPSRegulator fps(60); fps.Start();
bool running = true;
//Spritesheets
grnbll::Spritesheet terrain("Terrain.png", 512, 512, 32, 32);
terrain.MakeTransparent(0xED, 0x0B, 0xB5);
//Map file
std::ifstream map_file("World1.map");
//Player Info
survgame::Player player(4, 0, survgame::Directions::Down, "Player.png");
//Others
//Load the map
int map_array[16][16];
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 16; j++)
{
char current_map_piece;
map_file >> current_map_piece;
map_array[j] = current_map_piece - '0';
}
}
//Setup the screen
screen.SetBackgroundColor(SDL_MapRGB(SDL_GetVideoSurface()->format, 0xFF, 0xFF, 0xFF));
if(map_file.is_open())
{
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 16; j++)
{
screen.Apply(terrain, j*32, i*32, terrain.GetSprite(map_array[j]));
}
}
screen.Flip();
}
while(running)
{
//Event handling
while(event.Poll())
{
if(event.GetOther().other == grnbll::OtherEvents::Quit)
{
running = false;
}
player.HandleEvents(event);
}
//Logic
if(map_array[player.GetX()][player.GetY()] == 3)
{
running = false;
}
//Rendering
if((player.GetX() > 15) || (player.GetX() < 0) || (player.GetY() > 15) || (player.GetY() < 0) || (map_array[player.GetX()][player.GetY()] == 1))
{
player.SetX(player.GetXOld());
player.SetY(player.GetYOld());
screen.Apply(player, player.GetX()*32, player.GetY()*32, player.GetDirection());
screen.Flip();
}
else
{
screen.Apply(terrain, player.GetXOld()*32, player.GetYOld()*32, terrain.GetSprite(map_array[player.GetXOld()][player.GetYOld()]));
screen.Apply(player, player.GetX()*32, player.GetY()*32, player.GetDirection());
screen.Flip();
}
fps.Delay();
}
return 0;
}
The rectangles are constructed like (x, y, w, h).
The apply function takes a reference to an Applyable class so that it can get a pointer for blitting, the x and y positions to blit, and then a rectangle of what part of the source image to blit.
If I replace the "0" in Player::GetDirection() with an int between one and three or static_cast<int>(facing_direction), it won't give me the correct part of the spritesheet. I was wondering if this has to do with the player spritesheet having its sprite height and whole height equal instead of the terrain spritesheet, where they aren't equal.