SDL_Surface disappears after game runs for several minutes? - c++

after running my asteroids game for several minutes the SDL_Surface representing my ship disappears. Somehow the surface that holds the rotated image (rot) of the ship is getting set to NULL. I can't figure out why! Before I added the line if(rot != NULL && image != NULL) the program would crash after running for a about a minute an thirty seconds, but now the image just disappears. I can't seem to figure out whats wrong! Thanks in advance!
Sprite Class functions involving rotation and rendering.
void Sprite::Rotate(double angleAdd)
{
rotated = true;
double temp = 0;
angle += angleAdd;
temp = angleAdd + angle;
if (temp >= 360)
angleAdd = temp - 360;
if (temp <= 360)
angleAdd = temp + 360;
rot = rotozoomSurface(image, angle , 1.0, 1);
}
void Sprite::Draw(SDL_Surface* screen)
{
if(image == NULL)
SDL_FillRect(screen, &rect, color);
else
{
if (rotated)
{
rotRect.x = x;
rotRect.y = y;
//Center the image
if(rot != NULL && image != NULL){
rotRect.x -= ((rot->w/2) - (image->w/2));
rotRect.y -= ((rot->h/2) - (image->h/2));
}
SDL_BlitSurface(rot, NULL, screen, &rotRect);
}
else
SDL_BlitSurface(image, NULL, screen, &rect);
}
}
bool Sprite::SetImage(std::string fileName)
{
imageFileName = fileName;
SDL_Surface* loadedImage = NULL;
loadedImage = SDL_LoadBMP(fileName.c_str());
if(loadedImage == NULL)
{
if (debugEnabled)
printf("Failed to load image: %s\n", fileName.c_str());
SDL_FreeSurface(loadedImage);
return false;
}
else
{
image = SDL_DisplayFormat(loadedImage);
SDL_FreeSurface(loadedImage);
return true;
}
}
Main:
if (arrowPressed[0])
{
ship.SetImage(shipFor.GetImage());
if(!phase)
ship.Accel(-moveSpeed);
else
ship.Accel(-moveSpeed * 2);
}
if (arrowPressed[1])
{
ship.Rotate(turnSpeed);
ship.SetImage(shipRig.GetImage());
}
if (arrowPressed[3])
{
ship.Rotate(-turnSpeed);
ship.SetImage(shipLef.GetImage());
}
if (arrowPressed[0] && arrowPressed[1])
ship.SetImage(shipForRig.GetImage());
if (arrowPressed[0] && arrowPressed[3])
ship.SetImage(shipForLef.GetImage());
if (!arrowPressed[0] && !arrowPressed[1] && !arrowPressed[3])
ship.SetImage(shipNor.GetImage());
if (ship.GetCenterX() >= RESX - 40)
ship.SetPosCentered(50, ship.GetCenterY());
if (ship.GetCenterX() <= 40)
ship.SetPosCentered(RESX - 50, ship.GetCenterY());
if (ship.GetCenterY() >= RESY - 40)
ship.SetPosCentered(ship.GetCenterX(), 50);
if (ship.GetCenterY() <= 40)
ship.SetPosCentered(ship.GetCenterX(), RESY - 150);

It seems that you are not freeing the last rotated image. Check for null, and free the surface before creating a new one:
void Sprite::Rotate(double angleAdd)
{
if(rot != NULL)
SDL_FreeSurface(rot);
rotated = true;
double temp = 0;
angle += angleAdd;
temp = angleAdd + angle;
if (temp >= 360)
angleAdd = temp - 360;
if (temp <= 360)
angleAdd = temp + 360;
rot = rotozoomSurface(image, angle , 1.0, 1);
}

Related

Cpp sdl game goes black screen after consistent amount of time [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 15 hours ago.
Improve this question
I am making a Cpp sdl game which launches as it should and is playable but only for about 7 second as after that the screen goes black. If I keep the game running with black screen it eventually shows LLVM ERROR: out of memory. While using local windows debugger in Visual Studio I get:
Exception thrown at 0x71002A85 (SDL2_ttf.dll) in game.exe: 0xC0000005: Access violation reading location 0x00000000
and/or
Unhandled exception at 0x7A6C3ED8 (nvoglv32.dll) in game.exe: Fatal program exit requested
Not sure if this information is of any use but changing SDL_Delay() from 1 to higher value e.g. 100, extends the amount of time it takes before the screen goes black. Also changing the SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED) from '-1' to '1' extends the time it takes for the game to go black screen.
I tried different versions of SDL libraries and I don't think its a hardware issue. I used Visual Studio performance profiler and the CPU and GPU usage was normal. Performance profiler did show a 1.8 GB for process memory which did seem quite high, perhaps it's because of inefficient code(?).
I included some of the code and a snapshot.
main.cpp:
int main(int argc, char **argv)
{
/* initialize SDL */
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
assert(0 && "Failed to initialize video!");
exit(-1);
}
SDL_Window* window = SDL_CreateWindow("Pacman", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, SDL_WINDOW_OPENGL);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); //changing from -1 to 1 increase the amout of time the app runs before black screen
if(!window)
{
assert(0 && "Failed to create window!");
exit(-1);
}
IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
if (TTF_Init() == -1)
{
assert(0 && "Failed to create ttf!");
exit(-1);
}
Drawer* drawer = Drawer::Create(window, renderer);
Pacman* pacman = Pacman::Create(drawer);
float lastFrame = (float) SDL_GetTicks() * 0.001f;
SDL_Event event;
while (SDL_PollEvent(&event) >= 0)
{
float currentFrame = (float) SDL_GetTicks() * 0.001f;
float elapsedTime = currentFrame - lastFrame;
if (!pacman->Update(elapsedTime))
break;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
pacman->Draw();
lastFrame = currentFrame;
SDL_RenderPresent(renderer);
SDL_Delay(1);
}
delete pacman;
delete drawer;
TTF_Quit();
IMG_Quit();
SDL_Quit( );
return 0;
}
Drawer.cpp:
Drawer* Drawer::Create(SDL_Window* aWindow, SDL_Renderer* aRenderer)
{
Drawer* drawer = new Drawer(aWindow, aRenderer);
if (!drawer->Init())
{
delete drawer;
drawer = NULL;
}
return drawer;
}
Drawer::Drawer(SDL_Window* aWindow, SDL_Renderer* aRenderer)
: myWindow(aWindow)
, myRenderer(aRenderer)
, world()
{
}
Drawer::~Drawer(void)
{
}
bool Drawer::Init()
{
if (!myWindow)
return false;
return true;
}
void Drawer::Draw(const char* anImage, int aCellX, int aCellY)
{
SDL_Surface* surface = IMG_Load( anImage ) ;
if (!surface)
return;
SDL_Texture* optimizedSurface = SDL_CreateTextureFromSurface(myRenderer, surface);
SDL_Rect sizeRect;
sizeRect.x = 0 ;
sizeRect.y = 0 ;
sizeRect.w = surface->w ;
sizeRect.h = surface->h ;
SDL_Rect posRect;
posRect.x = aCellX;
posRect.y = aCellY;
posRect.w = sizeRect.w;
posRect.h = sizeRect.h;
SDL_RenderCopy(myRenderer, optimizedSurface, &sizeRect, &posRect);
}
void Drawer::DrawText(const char* aText, const char* aFontFile, int aX, int aY)
{
TTF_Font* font = TTF_OpenFont(aFontFile, 24);
if (font == nullptr) {
// Handle font loading error here (e.g. log an error message, throw an exception, etc.)
return;
}
SDL_Color fg = { 255, 0, 0, 255 };
SDL_Surface* surface = TTF_RenderText_Solid(font, aText, fg);
SDL_Texture* optimizedSurface = SDL_CreateTextureFromSurface(myRenderer, surface);
SDL_Rect sizeRect;
sizeRect.x = 0;
sizeRect.y = 0;
sizeRect.w = surface->w;
sizeRect.h = surface->h;
SDL_Rect posRect;
posRect.x = aX;
posRect.y = aY;
posRect.w = sizeRect.w;
posRect.h = sizeRect.h;
SDL_RenderCopy(myRenderer, optimizedSurface, &sizeRect, &posRect);
SDL_DestroyTexture(optimizedSurface);
SDL_FreeSurface(surface);
TTF_CloseFont(font);
}
world.cpp:
World::World(void)
{
}
World::~World()
{
for (auto tile : myPathmapTiles)
{
delete tile;
}
for (auto dot : myDots)
{
delete dot;
}
for (auto bigDot : myBigDots)
{
delete bigDot;
}
}
void World::Init()
{
InitPathmap();
InitDots();
InitBigDots();
}
bool World::InitPathmap()
{
std::string line;
std::ifstream myfile ("map.txt");
if (myfile.is_open())
{
int lineIndex = 0;
while (! myfile.eof() )
{
std::getline (myfile,line);
for (unsigned int i = 0; i < line.length(); i++)
{
PathmapTile* tile = new PathmapTile(i, lineIndex, (line[i] == 'x'));
myPathmapTiles.push_back(tile);
}
lineIndex++;
}
myfile.close();
}
return true;
}
bool World::InitDots()
{
std::string line;
std::ifstream myfile ("map.txt");
if (myfile.is_open())
{
int lineIndex = 0;
while (! myfile.eof() )
{
std::getline (myfile,line);
for (unsigned int i = 0; i < line.length(); i++)
{
if (line[i] == '.')
{
Dot* dot = new Dot(Vector2f(i * 22.0f, lineIndex * 22.0f));
myDots.push_back(dot);
}
}
lineIndex++;
}
myfile.close();
}
return true;
}
bool World::InitBigDots()
{
std::string line;
std::ifstream myfile ("map.txt");
if (myfile.is_open())
{
int lineIndex = 0;
while (! myfile.eof() )
{
std::getline (myfile,line);
for (unsigned int i = 0; i < line.length(); i++)
{
if (line[i] == 'o')
{
BigDot* dot = new BigDot(Vector2f(i * 22.0f, lineIndex * 22.0f));
myBigDots.push_back(dot);
}
}
lineIndex++;
}
myfile.close();
}
return true;
}
void World::Draw(Drawer* aDrawer)
{
aDrawer->Draw("playfield.png");
for(std::list<Dot*>::iterator list_iter = myDots.begin(); list_iter != myDots.end(); list_iter++)
{
Dot* dot = *list_iter;
dot->Draw(aDrawer);
}
for(std::list<BigDot*>::iterator list_iter = myBigDots.begin(); list_iter != myBigDots.end(); list_iter++)
{
BigDot* dot = *list_iter;
dot->Draw(aDrawer);
}
}
bool World::TileIsValid(int anX, int anY)
{
for(std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
if (anX == tile->myX && anY == tile->myY && !tile->myIsBlockingFlag)
return true;
}
return false;
}
bool World::HasIntersectedDot(const Vector2f& aPosition)
{
for(std::list<Dot*>::iterator list_iter = myDots.begin(); list_iter != myDots.end(); list_iter++)
{
Dot* dot = *list_iter;
if ((dot->GetPosition() - aPosition).Length() < 5.f)
{
myDots.remove(dot);
delete dot;
return true;
}
}
return false;
}
bool World::HasIntersectedBigDot(const Vector2f& aPosition)
{
for(std::list<BigDot*>::iterator list_iter = myBigDots.begin(); list_iter != myBigDots.end(); list_iter++)
{
BigDot* dot = *list_iter;
if ((dot->GetPosition() - aPosition).Length() < 5.f)
{
myBigDots.remove(dot);
delete dot;
return true;
}
}
return false;
}
bool World::HasIntersectedCherry(const Vector2f& aPosition)
{
return true;
}
void World::GetPath(int aFromX, int aFromY, int aToX, int aToY, std::list<PathmapTile*>& aList)
{
PathmapTile* fromTile = GetTile(aFromX, aFromY);
PathmapTile* toTile = GetTile(aToX, aToY);
for(std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
tile->myIsVisitedFlag = false;
}
Pathfind(fromTile, toTile, aList);
}
PathmapTile* World::GetTile(int aFromX, int aFromY)
{
for(std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
if (tile->myX == aFromX && tile->myY == aFromY)
{
return tile;
}
}
return NULL;
}
bool World::ListDoesNotContain(PathmapTile* aFromTile, std::list<PathmapTile*>& aList)
{
for(std::list<PathmapTile*>::iterator list_iter = aList.begin(); list_iter != aList.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
if (tile == aFromTile)
{
return false;
}
}
return true;
}
bool SortFromGhostSpawn(PathmapTile* a, PathmapTile* b)
{
int la = abs(a->myX - 13) + abs(a->myY - 13);
int lb = abs(b->myX - 13) + abs(b->myY - 13);
return la < lb;
}
bool World::Pathfind(PathmapTile* aFromTile, PathmapTile* aToTile, std::list<PathmapTile*>& aList)
{
aFromTile->myIsVisitedFlag = true;
if (aFromTile->myIsBlockingFlag)
return false;
if (aFromTile == aToTile)
return true;
std::list<PathmapTile*> neighborList;
PathmapTile* up = GetTile(aFromTile->myX, aFromTile->myY - 1);
if (up && !up->myIsVisitedFlag && !up->myIsBlockingFlag && ListDoesNotContain(up, aList))
neighborList.push_front(up);
PathmapTile* down = GetTile(aFromTile->myX, aFromTile->myY + 1);
if (down && !down->myIsVisitedFlag && !down->myIsBlockingFlag && ListDoesNotContain(down, aList))
neighborList.push_front(down);
PathmapTile* right = GetTile(aFromTile->myX + 1, aFromTile->myY);
if (right && !right->myIsVisitedFlag && !right->myIsBlockingFlag && ListDoesNotContain(right, aList))
neighborList.push_front(right);
PathmapTile* left = GetTile(aFromTile->myX - 1, aFromTile->myY);
if (left && !left->myIsVisitedFlag && !left->myIsBlockingFlag && ListDoesNotContain(left, aList))
neighborList.push_front(left);
neighborList.sort(SortFromGhostSpawn);
for(std::list<PathmapTile*>::iterator list_iter = neighborList.begin(); list_iter != neighborList.end(); list_iter++)
{
PathmapTile* tile = *list_iter;
aList.push_back(tile);
if (Pathfind(tile, aToTile, aList))
return true;
aList.pop_back();
}
return false;
}
Snapshot:
Snapshot

SDL C++ Collision on multiple objects?

So I was determined to get collision working myself from online resources without asking for help & I successfully followed a tutorial on lazyfoo to get collision working but quickly realised other problems.
So I started trying to get my collision working on my player (just a rect with controls atm) but couldn't actually access the rect inside the player class, I had to initialize it in main & use that for collision which meant transferring my collision function to main (not exactly perfect).
My question: So my collision is limited to two rects which I dedicated to the player & a single asteroid but my idea was to create multiple asteroids coming from the top of the screen, how would I go about altering the below code to accept a vector of "asteroids". Any advice about altering my code to be better object oriented etc is more then welcome but my main problem is collision. Please read collision carefully before posting, the specific X and Y params from the .cpp provides are hardcoded there.
Below Code order:
My current way of defining both player & asteroid for collision
Collision function
Asteroid.cpp & Player.cpp
My new way of loading asteroids - This is what I need collision to work with
Player aPlayer(200, 50, 50, 50);
Asteroid oneAsteroid(200, -50, 50, 50);
bool check_collision(SDL_Rect aPlayer, SDL_Rect oneAsteroid) {
//The sides of the rectangles
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;
//Calculate the sides of rect A
leftA = aPlayer.X;
rightA = aPlayer.X + aPlayer.width;
topA = aPlayer.Y;
bottomA = aPlayer.Y + aPlayer.height;
//Calculate the sides of rect B
leftB = oneAsteroid.X;
rightB = oneAsteroid.X + oneAsteroid.width;
topB = oneAsteroid.Y;
bottomB = oneAsteroid.Y + oneAsteroid.height;
if (bottomA <= topB)
{
return false;
}
if (topA >= bottomB)
{
return false;
}
if (rightA <= leftB)
{
return false;
}
if (leftA >= rightB)
{
return false;
}
//If none of the sides from A are outside B
return true;
}
#include "asteroids.h"
Asteroid::Asteroid()
{
}
Asteroid::~Asteroid()
{
}
Asteroid::Asteroid(int x, int y, int w, int h)
{
X = x; Y = y; width = w; height = h;
//SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Square Constructed with Param(&p)", this);
}
void Asteroid::Render(SDL_Renderer * aRenderer)
{
printf("");
SDL_Rect* aAsteroid = new SDL_Rect();
aAsteroid->x = X; aAsteroid->y = Y; aAsteroid->w = width; aAsteroid->h = height;
SDL_SetRenderDrawColor(aRenderer, 0, 0, 0, 255);
SDL_RenderFillRect(aRenderer, aAsteroid);
}
void Asteroid::Init()
{
velocity.X = 0;
velocity.Y = 5;
}
void Asteroid::Update()
{
Y = Y + velocity.Y;
// printf("%d \n", Astero);
if (Y > 650) {
Y = -50;
}
}
#include "Player.h"
#include "asteroids.h"
using namespace std;
Player::Player()
{
}
Player::~Player()
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Player Destroyed (&p)", this);
}
Player::Player(int x, int y, int w, int h)
{
X = x; Y = y; width = w; height = h;
//SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Square Constructed with Param(&p)", this);
}
void Player::Init()
{
velocity.X = 10;
velocity.Y = 10;
}
void Player::Update()
{
Y = Y + floorStart;
if (X < 0) {
X = 0;
}
if (KEY_RIGHT == true) {
X++;
}
if (X > SCREEN_WIDTH - 50) {
X = SCREEN_WIDTH - 50;
}
if (Y > SCREEN_HEIGHT - 100) {
Y = SCREEN_HEIGHT - 100;
}
if (KEY_LEFT == true) {
X--;
}
}
void Player::Input(SDL_Event event)
{
if (event.type == SDL_KEYDOWN && event.key.repeat == NULL)
{
if (event.key.keysym.sym == SDLK_LEFT) {
KEY_LEFT = true;
}
else {
KEY_LEFT = false;
}
if (event.key.keysym.sym == SDLK_RIGHT) {
KEY_RIGHT = true;
}
else {
KEY_RIGHT = false;
}
}
if (event.type == SDL_KEYUP && event.key.repeat == NULL) {
if (event.key.keysym.sym == SDLK_LEFT) {
KEY_LEFT = false;
}
if (event.key.keysym.sym == SDLK_RIGHT) {
KEY_RIGHT = false;
}
}
}
void Player::Render(SDL_Renderer * aRenderer)
{
SDL_Rect* thePlayer = new SDL_Rect;
thePlayer->x = X; thePlayer->y = Y; thePlayer->w = width; thePlayer->h = height;
SDL_SetRenderDrawColor(aRenderer, 0, 0, 0, 255);
SDL_RenderFillRect(aRenderer, thePlayer);
//SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Rendering (&p)", this);
}
What I need collision to work with, a vector of asteroids:
std::vector<Asteroid*> asteroidList;
asteroidList.push_back(new Asteroid(150, 350, 50, 50));
asteroidList.push_back(new Asteroid(70, 120, 125, 125));
The function to check collision in main.cpp
if (check_collision(aPlayer.thePlayer, oneAsteroid.aAsteroid)) {
printf("#######################");
}
And lastly, how would I go about rendering the array of asteroids?

Array initialization effecting seemingly unrelated classes C++ SDL [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
So I'm nearly done writing my first tic tac toe in C++ and SDL, ad I've run into a slight problem. I use a state machine to switch from title screen to shape choice screen, to player one or two to winning screen and back to the choice screen etc etc. On the choice screen I have two SDL_Rect arrays that act as buttons and the buttons are the X and O sprites I use from my sprite sheet. When the mouse hovers over them, they change colors. Everything is fine and dandy until the game resets to the choice screen after a win lose or tie. When it goes back to the choice screen and the mouse hovers over the button, it does not show the highlighted or mouse hovered sprite it clipped before. I pin pointed this problem to the initialization of my "set_grid_regions()" function. But this array doesn't even interact with the choice screen class in any way. How can this be affecting my hover sprites?
Just so anyone can see, here is the whole of the program:
#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL_image.h"
#include "SDL_mixer.h"
#include <string>
#include <iostream>
//constants
const int SCREEN_HEIGHT = 300;
const int SCREEN_WIDTH = 300;
const int SCREEN_BPP = 32;
const int GRID_WIDTH = 96;
const int GRID_HEIGHT = 96;
//game states
enum States
{
S_NULL,
INTRO,
CHOICE,
START_O,
START_X,
PLAYER_ONE,
PLAYER_TWO,
O_win,
X_win,
Tie,
EXIT,
};
// CLASSES //
class GameState
{
public:
virtual void events() = 0;
virtual void logic() = 0;
virtual void render() = 0;
virtual ~GameState(){};
};
class intro : public GameState
{
private:
//hover variable
bool button_hover = NULL;
//rects and surfaces
SDL_Rect button;
SDL_Surface *title_message = NULL;
public:
void events();
void logic();
void render();
intro();
~intro();
};
class choice : public GameState
{
private:
bool O_hover = NULL;
bool X_hover = NULL;
SDL_Rect shape_O_button;
SDL_Rect shape_X_button;
SDL_Surface *choice_text = NULL;
public:
void events();
void logic();
void render();
choice();
~choice();
};
class playerOne : public GameState
{
public:
void events();
void logic();
void render();
playerOne();
~playerOne();
};
class playerTwo : public GameState
{
public:
void events();
void logic();
void render();
playerTwo();
~playerTwo();
};
class win : public GameState
{
private:
int winner = NULL;
SDL_Surface *Tie = NULL;
SDL_Surface *X_win = NULL;
SDL_Surface *O_win = NULL;
public:
void events();
void logic();
void render();
win(int winner);
~win();
};
class Exit : public GameState
{
public:
void events();
void logic();
void render();
Exit();
~Exit();
};
// GLOBALS //
GameState *currentState = NULL;
int stateID = S_NULL;
int nextState = S_NULL;
//event
SDL_Event event;
//surfaces
SDL_Surface *screen = NULL;
SDL_Surface *sprites = NULL;
//ttf
TTF_Font *font = NULL;
SDL_Color color = { 0, 0, 0 };
SDL_Color win_Color = { 0, 100, 0 };
//arrays
int grid_array[9];
//rects
SDL_Rect sprite_clip[10];
SDL_Rect grid_region[9];
int number_elements = sizeof(grid_region) / sizeof(grid_region[0]);
//bools
bool shape = NULL;
bool invalid = NULL;
bool winner = NULL;
//ints
int highlight = NULL;
int shape_winner = NULL;
// FUCNTIONS //
//load image
SDL_Surface *load_image(std::string filename)
{
//loaded image
SDL_Surface* loadedImage = NULL;
//optimized surface
SDL_Surface* optimizedImage = NULL;
//load image
loadedImage = IMG_Load(filename.c_str());
//if image loaded
if (loadedImage != NULL)
{
//Create optimized image
optimizedImage = SDL_DisplayFormat(loadedImage);
//free old image
SDL_FreeSurface(loadedImage);
//if optimized
if (optimizedImage != NULL)
{
//map color key
Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 255, 255, 0);
//set all pixles of color 0,0,0 to be transparent
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
}
}
return optimizedImage;
}
//apply image
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL)
{
//temp rect
SDL_Rect offset;
//offsets
offset.x = x;
offset.y = y;
//blit
SDL_BlitSurface(source, clip, destination, &offset);
}
//initiate SDL etc
bool init()
{
//initialize all SDL subsystems
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
return false;
}
//set up screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
if (screen == NULL)
{
return false;
}
//check screen
if (screen == NULL)
{
return false;
}
//init TTF
if (TTF_Init() == -1)
{
return false;
}
//set window caption
SDL_WM_SetCaption("Tic-Tac-Toe", NULL);
//if evetything worked
return true;
}
//load files
bool load_files()
{
//sprite sheet
sprites = load_image("Sprites.png");
if (sprites == NULL)
{
return false;
}
font = TTF_OpenFont("font.ttf", 45);
if (font == NULL)
{
return false;
}
return true;
}
//quit
void clean_up()
{
//delete game state
delete currentState;
//free image
SDL_FreeSurface(sprites);
//quit ttf
TTF_CloseFont(font);
TTF_Quit();
//quit SDL
SDL_Quit();
}
void set_clip_regions()
{
//init clip array
//O
sprite_clip[0].x = 300;
sprite_clip[0].y = 0;
sprite_clip[0].w = 80;
sprite_clip[0].h = 82;
//X
sprite_clip[1].x = 300;
sprite_clip[1].y = 176;
sprite_clip[1].w = 80;
sprite_clip[1].h = 82;
//grid
sprite_clip[2].x = 0;
sprite_clip[2].y = 0;
sprite_clip[2].w = 300;
sprite_clip[2].h = 300;
//highlight
sprite_clip[3].x = 300;
sprite_clip[3].y = 82;
sprite_clip[3].w = 94;
sprite_clip[3].h = 94;
//left to right line
sprite_clip[4].x = 398;
sprite_clip[4].y = 188;
sprite_clip[4].w = 234;
sprite_clip[4].h = 12;
//diag up
sprite_clip[5].x = 393;
sprite_clip[5].y = 0;
sprite_clip[5].w = 188;
sprite_clip[5].h = 186;
//up down line
sprite_clip[6].x = 591;
sprite_clip[6].y = 0;
sprite_clip[6].w = 11;
sprite_clip[6].h = 208;
//Diag down line
sprite_clip[7].x = 0;
sprite_clip[7].y = 300;
sprite_clip[7].w = 188;
sprite_clip[7].h = 186;
//start button
sprite_clip[8].x = 202;
sprite_clip[8].y = 300;
sprite_clip[8].w = 94;
sprite_clip[8].h = 32;
//intro and choice background
sprite_clip[9].x = 300;
sprite_clip[9].y = 300;
sprite_clip[9].w = 300;
sprite_clip[9].h = 300;
//start hover
sprite_clip[10].x = 202;
sprite_clip[10].y = 332;
sprite_clip[10].w = 94;
sprite_clip[10].h = 32;
//X hover
sprite_clip[11].x = 202;
sprite_clip[11].y = 446;
sprite_clip[11].w = 80;
sprite_clip[11].h = 82;
//o hover
sprite_clip[12].x = 202;
sprite_clip[12].y = 364;
sprite_clip[12].w = 80;
sprite_clip[12].h = 82;
}
void set_grid_regions()
{
//set regions for images to be applied to
grid_region[0].x = 3;
grid_region[0].y = 3;
grid_region[1].x = 103;
grid_region[1].y = 3;
grid_region[2].x = 203;
grid_region[2].y = 3;
grid_region[3].x = 3;
grid_region[3].y = 103;
grid_region[4].x = 103;
grid_region[4].y = 103;
grid_region[5].x = 203;
grid_region[5].y = 103;
grid_region[6].x = 3;
grid_region[6].y = 203;
grid_region[7].x = 103;
grid_region[7].y = 203;
grid_region[8].x = 203;
grid_region[8].y = 203;
}
void init_grid()
{
//from left to right top to bottom
grid_array[0] = 0;
grid_array[1] = 0;
grid_array[2] = 0;
grid_array[3] = 0;
grid_array[4] = 0;
grid_array[5] = 0;
grid_array[6] = 0;
grid_array[7] = 0;
grid_array[8] = 0;
}
// STATE MACHINE FUNCTIONS //
void set_next_state(int newState)
{
if (nextState != EXIT)
{
nextState = newState;
}
}
void change_state()
{
if (nextState != S_NULL)
{
//change state
switch (nextState)
{
case CHOICE:
currentState = new choice();
break;
case PLAYER_ONE:
currentState = new playerOne();
break;
case PLAYER_TWO:
currentState = new playerTwo();
break;
case O_win:
currentState = new win(0);
break;
case X_win:
currentState = new win(1);
break;
case Tie:
currentState = new win(2);
break;
case EXIT:
currentState = new Exit();
break;
}
//change state
stateID = nextState;
//null nextState
nextState = S_NULL;
}
}
// CLASS DEFINITIONS //
intro::intro()
{
//button
button_hover = false;
//title
title_message = TTF_RenderText_Solid(font, "TIC TAC TOE", color);
//button bounds
button.x = 102;
button.y = 180;
button.w = 94;
button.h = 32;
}
intro::~intro()
{
SDL_FreeSurface(title_message);
}
void intro::events()
{
int x, y;
//mouse events
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
x = event.motion.x;
y = event.motion.y;
if ((x > button.x) && (x < button.x + button.w) && (y > button.y) && (y < button.y + button.h))
{
button_hover = true;
}
else
{
button_hover = false;
}
}
if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
x = event.motion.x;
y = event.motion.y;
if ((x > button.x) && (x < button.x + button.w) && (y > button.y) && (y < button.y + button.h))
{
set_next_state(CHOICE);
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void intro::logic()
{
}
void intro::render()
{
apply_surface(0, 0, sprites, screen, &sprite_clip[9]);
apply_surface((SCREEN_WIDTH - title_message->w) / 2, 100, title_message, screen);
if (button_hover == true)
{
apply_surface(102, 180, sprites, screen, &sprite_clip[10]);
}
else
{
apply_surface(102, 180, sprites, screen, &sprite_clip[8]);
}
}
choice::choice()
{
O_hover = false;
X_hover = false;
shape_O_button.x = 0;
shape_O_button.y = 130;
shape_O_button.w = 80;
shape_O_button.h = 82;
shape_X_button.x = 220;
shape_X_button.y = 130;
shape_X_button.w = 80;
shape_X_button.h = 82;
font = TTF_OpenFont("font.ttf", 34);
choice_text = TTF_RenderText_Solid(font, "CHOOSE YOUR SHAPE", color);
}
choice::~choice()
{
SDL_FreeSurface(choice_text);
O_hover = NULL;
X_hover = NULL;
}
void choice::events()
{
int x, y;
//mouse events
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
x = event.motion.x;
y = event.motion.y;
if ((x > shape_O_button.x) && (x < shape_O_button.x + shape_O_button.w) && (y > shape_O_button.y) && (y < shape_O_button.y + shape_O_button.h))
{
O_hover = true;
}
else
{
O_hover = false;
}
if ((x > shape_X_button.x) && (x < shape_X_button.x + shape_X_button.w) && (y > shape_X_button.y) && (y < shape_X_button.y + shape_X_button.h))
{
X_hover = true;
}
else
{
X_hover = false;
}
}
if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
x = event.motion.x;
y = event.motion.y;
if ((x > shape_O_button.x) && (x < shape_O_button.x + shape_O_button.w) && (y > shape_O_button.y) && (y < shape_O_button.y + shape_O_button.h))
{
shape = false;
init_grid();
set_next_state(PLAYER_ONE);
}
if ((x > shape_X_button.x) && (x < shape_X_button.x + shape_X_button.w) && (y > shape_X_button.y) && (y < shape_X_button.y + shape_X_button.h))
{
shape = true;
init_grid();
set_next_state(PLAYER_TWO);
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void choice::logic()
{
}
void choice::render()
{
apply_surface( 0, 0, sprites, screen, &sprite_clip[9]);
if (O_hover == false)
{
apply_surface(shape_O_button.x, shape_O_button.y, sprites, screen, &sprite_clip[0]);
}
else
{
apply_surface(shape_O_button.x, shape_O_button.y, sprites, screen, &sprite_clip[12]);
}
if (X_hover == false)
{
apply_surface(shape_X_button.x, shape_X_button.y, sprites, screen, &sprite_clip[1]);
}
else
{
apply_surface(shape_X_button.x, shape_X_button.y, sprites, screen, &sprite_clip[11]);
}
apply_surface((SCREEN_WIDTH - choice_text->w) / 2, 60, choice_text, screen);
}
//plyer O
playerOne::playerOne()
{
set_grid_regions();
}
playerOne::~playerOne()
{
}
void playerOne::events()
{
//mouse offsets
int x = 0, y = 0;
//if mouse moves
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
//get the mouse co-ords
x = event.motion.x;
y = event.motion.y;
for (int grid = 0; grid < number_elements; grid++)
{
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//set highlight region
highlight = grid;
}
}
}
//when the player clicks on a grid_region
if (event.type == SDL_MOUSEBUTTONDOWN)
{
//mouse co-ordinates
x = event.motion.x;
y = event.motion.y;
if (event.button.button == SDL_BUTTON_LEFT)
{
//iterate
for (int grid = 0; grid < number_elements; grid++)
{
//if in region box
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//check region
//if O turn
if ((grid_array[grid] == 0) && (shape == 0))
{
//fill region
grid_array[grid] = 1;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
//if X turn
else if ((grid_array[grid] == 0) && (shape == 1))
{
if ((grid_array[grid] == 0))
{
//fill region
grid_array[grid] = 2;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
}
}
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void playerOne::logic()
{
//check O win
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 1) && (grid_array[win + 1] == 1) && (grid_array[win + 2] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 1) && (grid_array[win + 3] == 1) && (grid_array[win + 6] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
if ((grid_array[0] == 1) && (grid_array[4] == 1) && (grid_array[8] == 1))
{
winner = 0;
set_next_state(O_win);
}
if ((grid_array[2] == 1) && (grid_array[4] == 1) && (grid_array[6] == 1))
{
winner = 0;
set_next_state(O_win);
}
//check X's
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 2) && (grid_array[win + 1] == 2) && (grid_array[win + 2] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 2) && (grid_array[win + 3] == 2) && (grid_array[win + 6] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
if ((grid_array[0] == 2) && (grid_array[4] == 2) && (grid_array[8] == 2))
{
winner = 1;
set_next_state(X_win);
}
if ((grid_array[2] == 2) && (grid_array[4] == 2) && (grid_array[6] == 2))
{
winner = 1;
set_next_state(X_win);
}
//check TIE
if ((grid_array[0] != 0) && (grid_array[1] != 0) && (grid_array[2] != 0) && (grid_array[3] != 0) && (grid_array[4] != 0) && (grid_array[5] != 0) && (grid_array[6] != 0) && (grid_array[7] != 0) && (grid_array[8] != 0) && (winner == NULL))
{
set_next_state(Tie);
}
}
void playerOne::render()
{
//logic
//rendering
//background
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
//grid
apply_surface(0, 0, sprites, screen, &sprite_clip[2]);
//highlight
if (highlight != -1)
{
apply_surface(grid_region[highlight].x, grid_region[highlight].y, sprites, screen, &sprite_clip[3]);
}
//APPLY PLAYER SHAPE
for (int grid = 0; grid < number_elements; grid++)
{
//O's
if ((grid_array[grid] == 1))
{
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[0]);
}
else if ((grid_array[grid] == 2))
{
//X's
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[1]);
}
}
}
playerTwo::playerTwo()
{
set_grid_regions();
}
playerTwo::~playerTwo()
{
}
void playerTwo::events()
{
//mouse offsets
int x = 0, y = 0;
//if mouse moves
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
//get the mouse co-ords
x = event.motion.x;
y = event.motion.y;
for (int grid = 0; grid < number_elements; grid++)
{
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//set highlight region
highlight = grid;
}
}
}
//when the player clicks on a grid_region
if (event.type == SDL_MOUSEBUTTONDOWN)
{
//mouse co-ordinates
x = event.motion.x;
y = event.motion.y;
if (event.button.button == SDL_BUTTON_LEFT)
{
//iterate
for (int grid = 0; grid < number_elements; grid++)
{
//if in region box
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//check region
//if O turn
if ((grid_array[grid] == 0) && (shape == 0))
{
//fill region
grid_array[grid] = 1;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
//if X turn
else if ((grid_array[grid] == 0) && (shape == 1))
{
if ((grid_array[grid] == 0))
{
//fill region
grid_array[grid] = 2;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
}
}
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void playerTwo::logic()
{
//check O win
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 1) && (grid_array[win + 1] == 1) && (grid_array[win + 2] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 1) && (grid_array[win + 3] == 1) && (grid_array[win + 6] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
if ((grid_array[0] == 1) && (grid_array[4] == 1) && (grid_array[8] == 1))
{
winner = 0;
set_next_state(O_win);
}
if ((grid_array[2] == 1) && (grid_array[4] == 1) && (grid_array[6] == 1))
{
winner = 0;
set_next_state(O_win);
}
//check X's
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 2) && (grid_array[win + 1] == 2) && (grid_array[win + 2] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 2) && (grid_array[win + 3] == 2) && (grid_array[win + 6] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
if ((grid_array[0] == 2) && (grid_array[4] == 2) && (grid_array[8] == 2))
{
winner = 1;
set_next_state(X_win);
}
if ((grid_array[2] == 2) && (grid_array[4] == 2) && (grid_array[6] == 2))
{
winner = 1;
set_next_state(X_win);
}
//check TIE
if ((grid_array[0] != 0) && (grid_array[1] != 0) && (grid_array[2] != 0) && (grid_array[3] != 0) && (grid_array[4] != 0) && (grid_array[5] != 0) && (grid_array[6] != 0) && (grid_array[7] != 0) && (grid_array[8] != 0) && (winner == NULL))
{
set_next_state(Tie);
}
}
void playerTwo::render()
{
//logic
//rendering
//background
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
//grid
apply_surface(0, 0, sprites, screen, &sprite_clip[2]);
//highlight
if (highlight != -1)
{
apply_surface(grid_region[highlight].x, grid_region[highlight].y, sprites, screen, &sprite_clip[3]);
}
//APPLY PLAYER SHAPE
for (int grid = 0; grid < number_elements; grid++)
{
//O's
if ((grid_array[grid] == 1))
{
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[0]);
}
else if ((grid_array[grid] == 2))
{
//X's
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[1]);
}
}
}
win::win(int winner)
{
shape_winner = winner;
font = TTF_OpenFont("font.ttf", 45);
X_win = TTF_RenderText_Solid(font, "X WINS", win_Color);
O_win = TTF_RenderText_Solid(font, "O wins", win_Color);
Tie = TTF_RenderText_Solid(font, "Tie", win_Color);
}
win::~win()
{
TTF_CloseFont(font);
SDL_FreeSurface(X_win);
SDL_FreeSurface(O_win);
}
void win::events()
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void win::logic()
{
if (shape_winner == 3)
{
SDL_Delay(2000);
set_next_state(CHOICE);
winner = NULL;
}
}
void win::render()
{
//background
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
//grid
apply_surface(0, 0, sprites, screen, &sprite_clip[2]);
//highlight
if (highlight != -1)
{
apply_surface(grid_region[highlight].x, grid_region[highlight].y, sprites, screen, &sprite_clip[3]);
}
//APPLY PLAYER SHAPE
for (int grid = 0; grid < number_elements; grid++)
{
//O's
if ((grid_array[grid] == 1))
{
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[0]);
}
else if ((grid_array[grid] == 2))
{
//X's
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[1]);
}
}
if (shape_winner == 1)
{
apply_surface((SCREEN_WIDTH - X_win->w) / 2, (SCREEN_HEIGHT - X_win->h) / 2, X_win, screen);
//enable delay and reset
shape_winner = 3;
}
if (shape_winner == 0)
{
apply_surface((SCREEN_WIDTH - O_win->w) / 2, (SCREEN_HEIGHT - O_win->h) / 2, O_win, screen);
//enable delay and reset
shape_winner = 3;
}
if (shape_winner == 2)
{
apply_surface((SCREEN_WIDTH - Tie->w) / 2, (SCREEN_HEIGHT - Tie->h) / 2, Tie, screen);
//enable delay and reset
shape_winner = 3;
}
}
Exit::Exit()
{
}
Exit::~Exit()
{
}
void Exit::events()
{
}
void Exit::logic()
{
}
void Exit::render()
{
}
//MAAAAAAAAAAAAAAAAAAIN//
int main(int argc, char* args[])
{
//init SDL
init();
//load files
load_files();
//set clips
set_clip_regions();
//set state
stateID = INTRO;
//set game object
currentState = new intro();
while (stateID != EXIT)
{
//handle state events
currentState->events();
// do state logic
currentState->logic();
//change state if needed
change_state();
//render state
currentState->render();
if (SDL_Flip(screen) == -1)
{
return 1;
}
}
clean_up();
return 0;
}
It's pretty strange. But I'm 99% sure that it's the "set_grid_regions()" that is effecting the rendering inside the choice::render() or choice::event() class fucntions. Can anyone help with this?
The error causing the clipping problem is an incorrect declaration for sprite_clip. You've declared it as sprite_clip[10], but you have 13 sprites. Change this to sprite_clip[13].
Other things I noticed:
You allocate all these state objects with new, but you never delete them. You need to delete them when you change states. Otherwise you will leak memory.
The font font.ttf seems to be a global resource but is haphazardly managed by a mixture of global and local methods. Load it once in load_files() and release it once in clean_up().
While your project may be complete, you might tinker around with it and work on improving the implementation now that you have something working. (If this was a homework, keep a copy of a working version to hand in. ;-) )
Consider packaging all of your global state (your fonts, sprites, clipping arrays, etc.) into a single class for the game. Your init_xxx and load_xxx functions move to its constructor. Your clean_up moves to its destructor.
Consider converting your dynamic state objects into statically allocated state objects. They could even be members of the same global state class I mentioned in the previous bullet. Now you've encapsulated the whole game in one class.
Consider merging playerOne and playerTwo into a single class. Distinguish them at construction time, just as you did with win(0), win(1), win(2).

Create space between characters blitted on screen - SDL

I have a bmp-file of numbers and characters. My program reads keypresses and blits the appropriate character/number from the bitmap onto the screen. The only problem is if i press 'A' - 'A' will show on screen, but if I press 'B', it will take 'A's place. So I will never have more than one character on screen.
Here's my code:
#include <SDL/SDL.h>
#include <iostream>
#include <string>
#include <vector>
#include <SDL_image/SDL_image.h>
using namespace std;
const Uint32 FRAMES_PER_SECOND = 60;
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int WIDTH = 21;
const int HEIGHT = 25;
SDL_Event sdlEvent;
char getAsciiKey(const SDL_Event &sdlEvent);
int main( int argc, char* args[] )
{
//The surfaces
SDL_Surface* image[2] = {NULL};
SDL_Surface* screen = NULL;
//Start SDL
SDL_Init( SDL_INIT_EVERYTHING );
//Set up screen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE | SDL_DOUBLEBUF );
char filename[256]; //create a large enough C-string
for(int index = 0; index < 2; index++)
{
sprintf(filename, "Text-types/Arial%d.bmp", index); //Arial0 and Arial1
//Load the image
image[index] = IMG_Load( filename );
if(image == NULL)
{
cout << "Error loading image: " << filename << endl;
exit(1);
}
}
Uint32 color = SDL_MapRGB(screen->format, 0xff,0xff,0xff); //White
SDL_FillRect(screen, &screen->clip_rect, color); //Backgroundcolor -> White
bool quit = false;
//Main program loop
while(quit == false)
{
//Process any events from the event queue - such as key presses or mouse movements
while(SDL_PollEvent(&sdlEvent))
{
if(sdlEvent.type == SDL_QUIT)
{
quit = true;
}
if (sdlEvent.type == SDL_KEYDOWN) //A key has just pressed
{
int x, y, temp;
SDL_Rect srcRect;
SDL_Rect dstRect;
//char letter = getAsciiKey(sdlEvent); //Getting keypress
temp = (static_cast<int>(getAsciiKey(sdlEvent)) - 12);
x = (temp % 20); //X-axis postion
y = (temp / 20); //Y-axis position
srcRect.x = (x - 1) * WIDTH;
srcRect.y = (y - 1) * HEIGHT;
//PIXELSIZE
srcRect.w = WIDTH;
srcRect.h = HEIGHT;
dstRect.x = 0;
dstRect.y = 0;
dstRect.w = WIDTH;
dstRect.h = HEIGHT;
SDL_BlitSurface(image[1] , &srcRect, screen, &dstRect ); //Putting image up on screen
//Update Screen
SDL_Flip( screen );
//Pause
SDL_Delay( 2000 );
}
}
}
//Free any loaded images
for(int index = 0; index < 2; index++)
{
SDL_FreeSurface( image[index] );
}
//Quit SDL
SDL_Quit();
return 0;
}
char getAsciiKey(const SDL_Event &sdlEvent)
{
char key = 0;
if(sdlEvent.key.keysym.sym >= SDLK_a && sdlEvent.key.keysym.sym <= SDLK_z)
{
if(sdlEvent.key.keysym.mod & KMOD_SHIFT)
{
key = 'A' + char(sdlEvent.key.keysym.sym - SDLK_a);
}
else
{
key = 'a' + char(sdlEvent.key.keysym.sym - SDLK_a);
}
}
else if(sdlEvent.key.keysym.sym >= SDLK_0 && sdlEvent.key.keysym.sym <= SDLK_9)
{
key = '0' + char(sdlEvent.key.keysym.sym - SDLK_0);
}
return key;
}
dstRect.x = 0;
dstRect.y = 0;
This is the position you're blitting to, and I don't see you changing it anywhere. Update it for each new character.
Also, this:
dstRect.w = WIDTH;
dstRect.h = HEIGHT;
is redundant, width and height of destination are ignored when blitting (at least the reference for SDL_BlitSurface says so).

SFML sprite std::list

I have some SFML 2.0 code, where I draw a robot which moves in a grid. Grid is drawn using OpenGL, the robot image is loaded using sf::Texture. I have some code that makes walls on user left mouse click (no collision detection). I made a function which erases them on right click.
Walls are stored in sf::Sprite, then put into std::list and drawn in a loop. When I call list.erase() program segfaults. Debugger shows some problem in sf::transformable = operator.
How to fix that.
Here is the code:
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <iostream>
#include <list>
using namespace std;
static const size_t WIN_HEIGHT=800, WIN_WIDTH=800;
void drawGrid();
void fixCoords(int & x, int & y);
static list<sf::Sprite> walls;
int main()
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(WIN_WIDTH, WIN_HEIGHT), "SFML window");
/*** Robot code ***/
sf::Image robotImg;
robotImg.loadFromFile("robot.png");
robotImg.createMaskFromColor(sf::Color(89, 167, 45));
sf::Texture robotTexture;
robotTexture.loadFromImage(robotImg);
sf::Sprite robotSpr(robotTexture);
sf::Sprite t;
robotSpr.setPosition(sf::Vector2f(400, 405));
/***** Wall code ****/
int x = 0, y = 0;
sf::Image wallimg;
wallimg.loadFromFile("wall.png");
wallimg.createMaskFromColor(sf::Color(255, 0, 255));
sf::Texture walltex;
walltex.loadFromImage(wallimg);
sf::Sprite wall;
wall.setTexture(walltex);
int movex = 0, movey = 0;
gluOrtho2D(0, WIN_WIDTH, 0, WIN_HEIGHT);
while (window.isOpen())
{
// Process events
sf::Event event;
while (window.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
{
window.close();
return 0;
}
if (event.type == sf::Event::MouseButtonPressed )
{
if(event.mouseButton.button == sf::Mouse::Left)
{
x = event.mouseButton.x;
y = event.mouseButton.y;
fixCoords(x, y);
wall.setPosition(sf::Vector2f(x, y));
walls.push_back(wall);
}
if(event.mouseButton.button == sf::Mouse::Right)
{
x = event.mouseButton.x;
y = event.mouseButton.y;
fixCoords(x, y);
for(list<sf::Sprite>::iterator it = walls.begin(); it != walls.end(); it++)
{
if((it->getPosition().x == x) && (it->getPosition().y == y)) // This line
walls.erase(it);
}
}
}
if(event.type == sf::Event::KeyPressed)
{
if((movex == 0) && (movey == 0))
{
if(event.key.code == sf::Keyboard::Up)
movey -= 37;
if(event.key.code == sf::Keyboard::Down)
movey += 37;
if(event.key.code == sf::Keyboard::Left)
movex -= 40;
if(event.key.code == sf::Keyboard::Right)
movex += 40;
}
}
}
window.pushGLStates();
window.clear(sf::Color(90, 167, 45));
// Insert SFML Draws here
if(movex > 0)
{
robotSpr.move(1, 0);
movex--;
}
if(movex < 0)
{
robotSpr.move(-1, 0);
movex++;
}
if(movey > 0)
{
robotSpr.move(0, 1);
movey--;
}
if(movey < 0)
{
robotSpr.move(0, -1);
movey++;
}
window.draw(robotSpr);
if((x != 0) && (y != 0))
{
for(list<sf::Sprite>::iterator it = walls.begin(); it != walls.end(); it++)
window.draw(*it);
}
window.popGLStates();
// OpenGL Here
drawGrid();
// Update the window
window.display();
}
}
void drawGrid()
{
glColor3ub(0, 0, 0);
glBegin(GL_LINES); // Horizontal lines
for(int i = 0; i < WIN_HEIGHT; i += WIN_HEIGHT / 20)
{
glVertex2i(0, i);
glVertex2i(WIN_WIDTH, i);
}
glEnd();
glColor3ub(0, 0, 0);
glBegin(GL_LINES); // Vertical lines
for(int i = 0; i < WIN_WIDTH; i += WIN_WIDTH / 20)
{
glVertex2i(i, 0);
glVertex2i(i, WIN_HEIGHT);
}
glEnd();
}
void fixCoords(int &x, int &y)
{
/**** Find the nearest x sqare ****/
for(int i = 1; i < WIN_WIDTH - 1; i += 40)
{
if((x >= i) && x <= (i + 40))
{
x = i - 1;
break;
}
}
for(int i = WIN_HEIGHT; i > 0; i -= 40)
{
if((y >= i) && y <= (i + 40))
{
y = i;
break;
}
}
}
This is an annoyance of the way the list<T> container works.
A list<T> container is implemented as a doubly linked list. So an iterator needs to access its current element to get to the next element. If you have just erased its current element, everything explodes.
You can make it work like this:
list<sf::Sprite>::iterator it=walls.begin(),next;
while(it!=walls.end()) {
next = it; next++;
if((it->getPosition().x == x) && (it->getPosition().y == y))
walls.erase(it);
it = next;
}
you could also use remove_if with an appropriate predicate class, but that would just be uglier and more convoluted.