THREAD 1 :EXC_BAD_ACCESS error, this error appears at the handle function in the cpp file at the first line - c++

this is a code that creates a chicken invaders game, the game(or whatever part i can do of the game) worked fine when i was just initializing one chicken, but when i made it a 2d array of chickens it showed me this error.
RenderWindow window;
int main(int, char const**)
{
chicken chick[4][7];
Sprite back;
Clock clock;
window.create(VideoMode(1800, 1000), "Menu");
while (window.isOpen())
{
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::KeyPressed && event.key.code == Keyboard::Escape)
window.close();
if (event.type == Event::Closed)
window.close();
}
Texture texture;
if (!texture.loadFromFile(resourcePath() + "background.jpg"))
{
std::cout << "Error loading texture" << std::endl;
}
Time time;
time = clock.getElapsedTime();
if (time.asSeconds() >= 0.001)
{
chick[4][7].handle(window, clock);
clock.restart();
}
window.clear();
back.setTexture(texture);
back.setPosition(0, 0);
back.setTextureRect(IntRect(0, 0, 1800, 1000));
window.draw(back);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 7; j++)
chick[i][j].initialize(window);
window.display();
}
}
///////////////////
this is the app file for the chicken class
using namespace sf;
class chicken
{
private:
RectangleShape chick;
bool flag;
public:
chicken();
void initialize(RenderWindow &window);
void handle(RenderWindow & window, Clock clock);
~chicken();
};
#endif /* chicken_hpp */
/////////////////////////////////////////////////////////////
this is the cpp file for the chicken class
using namespace sf;
chicken::chicken()
{
chick.setPosition(500, 500);
chick.setSize(Vector2f(200, 200));
chick.setOrigin(100, 100);
flag = true;
}
void chicken::initialize(RenderWindow & window)
{
Texture texture2;
if (!texture2.loadFromFile(resourcePath() + "chicken3.jpg"))
{
std::cout << "Error loading texture" << std::endl;
}
chick.setTexture(&texture2);
window.draw(chick);
}
void chicken::handle(RenderWindow & window, Clock clock)
{
if (flag) //the error appears here
{
chick.move( 10 , 0 ) ;
}
else
{
chick.move(-10 , 0);
}
if (chick.getPosition().x >= window.getSize().x)
flag = false;
if(chick.getPosition().x < 0)
flag = true;
}
chicken::~chicken()
{
}

In the future please include the entire error message in your question, however the issue here is you are accessing an out of bounds index in your chicken array.
your array size is 4x7 this means your valid indices are 0 - 3 and 0 - 6.
Your handle function is being called on chick[4][7], which is out of bounds.
If you are trying to call that function on only the last chick in the array it would be
chick[3][6].handle(window, clock);
to call it on every chicken you need a double for loop like
for(int i = 0; i < 4; ++i)
{
for(int j = 0; j < 7; ++j)
{
chick[i][j].handle(window, clock);
}
}

Related

How to reset values after dying

I am making a google chrome dinosaur game using an SDL Template for graphics and I am almost finished but I have run into the issue of needing to be able to reset to the starting values of the game just like how you reset when you hit spacebar after dying in the google chrome dinosaur game. I have made an isGameOver function but I don't know how to reset the values to start a new game which is my main problem.
this is my GameScene class where the game over logic is located
GameScene.h
#pragma once
#include "Scene.h"
#include "GameObject.h"
#include "Player.h"
#include "Floor.h"
#include "Obstacle.h"
#include "FlyingObstacle.h"
#include <vector>
#include "util.h"
#include "text.h"
class GameScene : public Scene
{
public:
GameScene();
~GameScene();
void start();
void draw();
void update();
std::vector<Obstacle*> spawnedObstacle;
std::vector<FlyingObstacle*> spawnedBird;
private:
Player* player;
Floor* floor;
float spawnTime;
float currentSpawnTimer;
void floorCollision();
void obstacleCollision();
void birdCollision();
void obstacleSpawn();
void birdSpawn();
void despawnObstacle(Obstacle* obstacle);
void despawnBird(FlyingObstacle* bird);
int points;
int highscore;
bool isGameOver;
};
GameScene.cpp
#include "GameScene.h"
GameScene::GameScene()
{
// Register and add game objects on constructor
player = new Player();
this->addGameObject(player);
floor = new Floor();
this->addGameObject(floor);
points = 0;
highscore = 0;
}
GameScene::~GameScene()
{
delete player;
}
void GameScene::start()
{
Scene::start();
// Initialize any scene logic here
initFonts();
isGameOver = true;
currentSpawnTimer = 300;
spawnTime = rand() % 300; //spawn time of 5 seconds
for (int i = 0; i < 1; i++)
{
obstacleSpawn();
}
for (int i = 0; i < 3; i++)
{
birdSpawn();
}
}
void GameScene::draw()
{
Scene::draw();
drawText(110, 20, 255, 255, 255, TEXT_CENTER, "POINTS: %03d", points);
if (player->getIsAlive() == true)
{
drawText(900, 20, 255, 255, 255, TEXT_CENTER, "PRESS SPACE TO START MOVING");
}
if (player->getIsAlive() == false)
{
if (isGameOver == false)
drawText(SCREEN_WIDTH / 2, 200, 255, 255, 255, TEXT_CENTER, "YOU LOSE! PRESS SPACE TO SHOW POINTS");
if (isGameOver == true)
{
drawText(SCREEN_WIDTH / 2, 200, 255, 255, 255, TEXT_CENTER, "HIGHSCORE: %03d", highscore);
if (points > highscore)
{
drawText(SCREEN_WIDTH / 2, 200, 255, 255, 255, TEXT_CENTER, "NEW HIGHSCORE: %03d", points, highscore);
}
}
}
}
void GameScene::update()
{
if (isGameOver == true)
{
if (app.keyboard[SDL_SCANCODE_SPACE])
{
isGameOver = false;
}
}
if (isGameOver == false)
{
Scene::update();
floorCollision();
obstacleCollision();
birdCollision();
if (currentSpawnTimer > 0)
currentSpawnTimer--;
if (currentSpawnTimer <= 0)
{
for (int i = 0; i < 1; i++)
{
obstacleSpawn();
}
for (int i = 0; i < 3; i++)
{
birdSpawn();
}
currentSpawnTimer = spawnTime;
}
//This is where Gravity strength is located
if (player->getOnFloor() == false) {
player->setY(player->getY() + 7);
}
else {
player->getY() + 0;
}
}
}
void GameScene::floorCollision()
{
//Checks for collisions
for (int i = 0; i < objects.size(); i++)
{
//Cast to floor
Floor* floor = dynamic_cast<Floor*>(objects[i]);
//Check if the floor was casted
if (floor != NULL)
{
int collision = checkCollision(
player->getX(), player->getY(), player->getWidth(), player->getHeight(),
floor->getX(), floor->getY(), floor->getWidth(), floor->getHeight()
);
if (collision == 1)
{
player->setOnFloor(true);
if (player->getIsAlive() == true)
{
points++;
highscore++;
}
break;
}
}
}
}
void GameScene::obstacleCollision()
{
for (int i = 0; i < objects.size(); i++)
{
Obstacle* obstacle = dynamic_cast<Obstacle*>(objects[i]);
if (obstacle != NULL)
{
if (obstacle != NULL)
{
int collision = checkCollision(
player->getX(), player->getY(), player->getWidth(), player->getHeight(),
obstacle->getX(), obstacle->getY(), obstacle->getWidth(), obstacle->getHeight()
);
if (collision == 1)
{
player->doDeath();
isGameOver = true;
break;
}
}
}
}
}
void GameScene::birdCollision()
{
for (int i = 0; i < objects.size(); i++)
{
FlyingObstacle* bird = dynamic_cast<FlyingObstacle*>(objects[i]);
if (bird != NULL)
{
if (bird != NULL)
{
int collision = checkCollision(
player->getX(), player->getY(), player->getWidth(), player->getHeight(),
bird->getX(), bird->getY(), bird->getWidth(), bird->getHeight()
);
if (collision == 1)
{
player->doDeath();
isGameOver = true;
break;
}
}
}
}
}
void GameScene::obstacleSpawn()
{
Obstacle* obstacle = new Obstacle();
this->addGameObject(obstacle);
obstacle->setPosition(1200, 300 + (rand() % 300));
spawnedObstacle.push_back(obstacle);
}
void GameScene::birdSpawn()
{
FlyingObstacle* bird = new FlyingObstacle();
this->addGameObject(bird);
bird->setPos(1200, 300 + (rand() % 300));
spawnedBird.push_back(bird);
}
void GameScene::despawnObstacle(Obstacle* obstacle)
{
int index = -1;
for (int i = 0; i < spawnedObstacle.size(); i++)
{
//If pointer matches
if (obstacle == spawnedObstacle[i])
{
index = i;
break;
}
}
//If any match is found
if (index != -1)
{
spawnedObstacle.erase(spawnedObstacle.begin() + index);
delete obstacle;
}
}
void GameScene::despawnBird(FlyingObstacle* bird)
{
int index = -1;
for (int i = 0; i < spawnedBird.size(); i++)
{
//If pointer matches
if (bird == spawnedBird[i])
{
index = i;
break;
}
}
//If any match is found
if (index != -1)
{
spawnedBird.erase(spawnedBird.begin() + index);
delete bird;
}
}
I tried making an isGameOver bool inside my GameScene.h and I made it so that pressing spacebar would reset the game but in reality when the player dies the screen pauses every movement instead of resetting and if I press space again the game continues to move even though the player is dead.
Your entry point for the game(probably main function will probably have some form like this)
#include ...
#include ...
...
int main()
{
bool game_running = true;
while(game_running)
{
GameInstance* game = new Game(); //Allocation and initialization of all resources needed to play the game.
game.play(); // This function will finish when you lose the game.
delete game; // Deallocation.
if(!run_again())
{
game_running = false;
}
}
return 0;
}
After deallocation, you check if user wants to play again, you enter the next iteration of while loop, and new instance of Game is allocated, where all the resource handling takes place. The only problem is that allocating Game instance for every iteration might be a little costly, but you can ignore that if you don't worry about performance much.

C++ Sfml, How can I create a collision box for my Sprite

I have a question to sfml.
I am relative new to C++ and sfml.
I am trying to create a Space Invaders type of game.
I currently have some problems with collision,
between the enemy's bullets and the rocket,
I'm talking about line 145. This line:
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
Can you create something like a collision box?,
because I don't want to collide with the whole rocket sprite,
I only want to collide with parts of it, e.g not the transparent parts.
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
void print(std::string string)
{
std::cout << string << std::endl;
}
sf::CircleShape create_bullet(sf::Vector2f possition, sf::Int16 offset)
{
sf::CircleShape circel;
circel.setRadius(10);
circel.setPosition(possition.x + offset, possition.y);
return circel;
}
bool collide(sf::Sprite a, sf::CircleShape b)
{
return a.getGlobalBounds().intersects(b.getGlobalBounds());
}
int main()
{
int speed;
speed = 25;
sf::RenderWindow window(sf::VideoMode(1200, 800), "Space Invaders", sf::Style::Titlebar | sf::Style::Close);
sf::Texture rocket_texture;
if (!rocket_texture.loadFromFile("data/rocket.png"))
{
print("Problem with loding file data/rocket.png");
exit(-1);
}
sf::Texture enemy_texture;
if (!enemy_texture.loadFromFile("data/enemy.png"))
{
print("Problem with loding file data/enemy.png");
exit(-1);
}
sf::Sprite rocket;
sf::Sprite enemy;
std::chrono::milliseconds couldown = std::chrono::milliseconds(0);
std::chrono::milliseconds time;
std::chrono::milliseconds enemy_couldown = std::chrono::milliseconds(0);
bool enemy_fire = false;
float bulletspeed = 0.02;
// sf::CircleShape test = create_bullet();
int changex;
rocket.setTexture(rocket_texture);
rocket.setPosition(500, 650);
rocket.scale(0.5, 0.5);
std::vector<sf::Sprite> enemy_list;
std::vector<sf::CircleShape> player_bullets;
std::vector<sf::CircleShape> enemy_bullets;
enemy.setTexture(enemy_texture);
enemy.scale(0.2, 0.2);
for (int i =0; i<8; i++)
{
enemy.setPosition(i * 150, 400);
enemy_list.push_back(enemy);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
changex = 0;
switch (event.type)
{
// window closed
case sf::Event::Closed:
window.close();
break;
// key pressed
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::A)
{
if (rocket.getPosition().x >= 0 )
{
changex = changex - speed;
}
}
else if (event.key.code == sf::Keyboard::D)
{
if (rocket.getPosition().x <= 1100)
{
changex = changex + speed;
}
}
else if (event.key.code == sf::Keyboard::Space)
{
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (couldown < time - std::chrono::milliseconds(100)){
couldown = time;
player_bullets.push_back(create_bullet(rocket.getPosition(), 47));
}
}
break;
default:
break;
}
rocket.move(changex, 0);
}
window.clear();
window.draw(rocket);
//swindow.draw(test);
for (int i=0; i<player_bullets.size();i++)
{
player_bullets[i].move(0,-bulletspeed);
window.draw(player_bullets[i]);
if (player_bullets[i].getPosition().y < 0)
{
player_bullets.erase(player_bullets.begin()+i);
}
}
for (int i = 0; i < enemy_bullets.size(); i++)
{
enemy_bullets[i].move(0, bulletspeed);
window.draw(enemy_bullets[i]);
if (enemy_bullets[i].getPosition().y > 800)
{
enemy_bullets.erase(enemy_bullets.begin() + i);
}
if (collide(rocket, enemy_bullets[i]))
{
window.close();
}
}
time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
if (enemy_couldown < time - std::chrono::milliseconds(2000))
{
enemy_couldown = time;
enemy_fire = true;
}
// Draw all Enemys
for (int i = 0; i < enemy_list.size(); i++)
{
for (int j = 0; j < player_bullets.size(); j++)
{
if (collide(enemy_list[i], player_bullets[j]))
{
enemy_list.erase(enemy_list.begin() + i);
}
}
if (enemy_fire)
{
enemy_couldown = time;
// ADD: Move enemys
enemy_bullets.push_back(create_bullet(enemy_list[i].getPosition(), 13));
}
window.draw(enemy_list[i]);
}
enemy_fire = false;
window.display();
}
return 0;
}
If you have any idea how to do that,
I would like to hear it.
Thanks, in advance
You can make a class that derives from sf::Sprite that has a sf::FloatRect for a hitbox, you will need to make a function to set the hitbox.
class Sprite : public sf::Sprite {
sf::FloatRect hitbox;
}
You can move the hitbox to the sprites location with:
getTransform().transformRect(hitbox);
I have used this in the past for hitboxes with SFML.
Edit, Here is an full example program:
#include <SFML/Graphics.hpp>
/// custom sprite class with hitbox
class HitboxSprite : public sf::Sprite {
public:
/// sets the hitbox
void setHitbox(const sf::FloatRect& hitbox) {
m_hitbox = hitbox;
}
/// gets the hitbox (use this instead of getGlobalBounds())
sf::FloatRect getGlobalHitbox() const {
return getTransform().transformRect(m_hitbox);
}
private:
sf::FloatRect m_hitbox;
};
int main() {
sf::RenderWindow window(sf::VideoMode(256, 128), "Example");
// create two sprites, player and enemy
HitboxSprite player;
player.setPosition({ 64.f, 64.f });
HitboxSprite enemy;
enemy.setPosition({ 128.f, 64.f });
enemy.setColor(sf::Color::Red);
// create sprite texture and apply to sprites
sf::Texture square_texture;
square_texture.loadFromFile("32x32square.png");
player.setTexture(square_texture);
enemy.setTexture(square_texture);
// set custom hitboxes
// (this one starts (8, 8) pixels from the top left and has a size of (16, 16)
// (this means the hitbox will be 1/2 of the square in the middle)
player.setHitbox({ 8.f, 8.f, 16.f, 16.f });
enemy.setHitbox({ 8.f, 8.f, 16.f, 16.f });
sf::Clock clock;
while (window.isOpen()) {
// process events
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
const float dt = clock.restart().asSeconds();
constexpr float player_speed = 128.f;
// move player with arrow keys
player.move({
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) - sf::Keyboard::isKeyPressed(sf::Keyboard::Left)),
player_speed * dt * (sf::Keyboard::isKeyPressed(sf::Keyboard::Down) - sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
});
// check for collision
const bool colliding = player.getGlobalHitbox().intersects(enemy.getGlobalHitbox());
// set background color based on collision
window.clear(colliding ? sf::Color::Green : sf::Color::Blue);
// draw sprites
window.draw(enemy);
window.draw(player);
// display
window.display();
}
return 0;
}
If you need any part explained let me know.
Here is the translucent png I made with the center part being the hitbox:

My array of sprites is not getting drawn on my renderwindow

So I am trying to make a chessgame, and of course I am starting out with just making the board. For this I am creating a two-dimensional array like 8x8. Each tile has their own object sprite called tileSprite and I am trying to define them as 1/8th of the width and height of the screen, which has a fixed size of 1024x768. The textures that are loaded in are just 1 pixel black or white. The program gives no definitive error, but the drawn tiles aren't getting displayed onto my window, and all I see is a red screen, which I get from clearing the screen (following the standard clear/draw/display cycle of SFML).
#include "SFML/Window.hpp"
#include "SFML/Graphics.hpp"
#include "SFML/Audio.hpp"
#include <iostream>
#include <vector>
#include <array>
bool playing = true;
class Textures {
public:
static void loadTextures();
sf::Texture static blackTile;
sf::Texture static whiteTile;
};
/*---Class--Definitions----*/
sf::Texture Textures::blackTile;
sf::Texture Textures::whiteTile;
/*-------------------------*/
void Textures::loadTextures() {
if (blackTile.loadFromFile("Images/blackTile.PNG")) {
return;
}
else if (whiteTile.loadFromFile("Images/whiteTile.PNG")) {
return;
}
}
class ChessBoard_Tiles {
public:
static void _initialize();
static void draw(sf::RenderWindow& window);
enum TileStatus { EMPTY, OCCUPIED, HIGHLIGHTED };
struct TileSlot {
sf::Sprite tileSprite;
TileStatus tileStatus;
};
private:
typedef std::array< std::array<TileSlot*, 8>, 8 > TileType;
static TileType tileBoard;
};
/*-Class Definition that has to be called-*/
ChessBoard_Tiles::TileType ChessBoard_Tiles::tileBoard = ChessBoard_Tiles::TileType();
void ChessBoard_Tiles::_initialize() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
tileBoard[i][j] = new TileSlot();
if ((i + j) % 2 == 0) {
tileBoard[i][j]->tileSprite.setTexture(Textures::whiteTile);
}
else {
tileBoard[i][j]->tileSprite.setTexture(Textures::blackTile);
}
tileBoard[i][j]->tileSprite.setPosition(128 * j, 96 * i);
tileBoard[i][j]->tileSprite.setScale(128, 96);
tileBoard[i][j]->tileStatus = EMPTY;
}
}
}
void ChessBoard_Tiles::draw(sf::RenderWindow& window) {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
window.draw(tileBoard[i][j]->tileSprite);
}
}
}
int main(int argc, char* argv[]) {
sf::RenderWindow renderWindow;
renderWindow.create(sf::VideoMode(1024, 768), "Chess");
Textures::loadTextures();
ChessBoard_Tiles::_initialize();
while (playing) {
sf::Event currentEvent;
renderWindow.pollEvent(currentEvent);
if (currentEvent.type == sf::Event::Closed) {
renderWindow.close();
playing = false;
}
if (currentEvent.type == sf::Event::KeyPressed) {
if (currentEvent.key.code == sf::Keyboard::Escape) {
renderWindow.close();
playing = false;
}
}
renderWindow.clear(sf::Color::Red);
std::cout << "Clear\n";
ChessBoard_Tiles::draw(renderWindow);
std::cout << "Draw\n";
renderWindow.display();
std::cout << "Display\n";
}
return 0;
}
If anyone knows what is wrong then that would be a big help for me.. Otherwise I'd probably have to entirely remake this program, which I think should work so far, but I haven't the slightest idea why it doesn't. Big thanks in advance =)
EDIT: Read a little about how the sprites seem to disappear if the textures are running out of scope.. If this is the case, could that just be pointed out and then I can work on that, because I have tried so many different things by now that I feel like I'm just going in circles?
The fault was from the loadTextures() function, where I had forgotten to include the file extension of the file to be loaded, and I screwed the logic about the loadFromFile() function up so the program only continued when it couldn't load the file..

X in namespace 'sf' does not name a type [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am working with SFML1.6 to produce a graphical app (a game). It was working fine when I only had one file beyond the Main file. Now I added a new file, Level, and I get these errors:
C:\Users\...\Window.hpp|6|error: 'RenderWindow' in namespace 'sf' does not name a type|
C:\Users\...\Window.hpp|7|error: 'Image' in namespace 'sf' does not name a type|
C:\Users\...\Window.hpp|8|error: 'Sprite' in namespace 'sf' does not name a type|
C:\Users\...\Window.hpp|9|error: 'Color' in namespace 'sf' does not name a type|
Since it was working fine, I suppose it is due to the new file:
Level.cpp
#include <SFML/Window.hpp>
#include <iostream>
#include "Window.hpp"
class Level
{
sf::Window* pResultScreen;
public:
Level( sf::Window& );
};
Level::Level( sf::Window &app)
{
pResultScreen = &app;
};
Level.hpp
#ifndef Level_hpp
#define Level_hpp
class Level
{
sf::Window* pResultScreen;
public:
Level( sf::Window& );
};
#endif
Does anyone see a problem with the above code?
EDIT:
Window.cpp
class Window
{
sf::RenderWindow appWindow;
sf::Image charImage;
sf::Sprite charSpriteSheet;
sf::Color deleteColor;
bool keyPressed;
int curFrame;
int stateChar;
int timerFrame;
int flipChar;
public:
Window();
int Loop();
void SheetCutter(int); // Prepares tiles
void Animate(int); // Loop through animations
void ColourCleaner(); // Remove the sprite's color.
};
Window::Window()
{
stateChar = 0;
curFrame = 0;
flipChar = 1;
deleteColor.a = 255;
deleteColor.r = 255;
deleteColor.g = 47;
deleteColor.b = 198;
appWindow.Create(sf::VideoMode( 800, 600, 32), "AI_Fighter");
appWindow.SetFramerateLimit(30);
if( !charImage.LoadFromFile("Bass.png") )
{
std::cout << "Problem opening file 'Bass.png'";
}
charImage.SetSmooth(false);
ColourCleaner();
charSpriteSheet.SetImage(charImage);
SheetCutter(curFrame); // This allows it to not show the entire tile set at the beginning.
};
int Window::Loop()
{
// Start game loop
while (appWindow.IsOpened())
{
sf::Event evt;
while (appWindow.GetEvent(evt))
{
// Window closed
if (evt.Type == sf::Event::Closed)
appWindow.Close();
// Escape key pressed
if ((evt.Type == sf::Event::KeyPressed) && (evt.Key.Code == sf::Key::Escape))
appWindow.Close();
if (evt.Type == sf::Event::KeyPressed)
keyPressed = true;
else
keyPressed = false;
}
// Get elapsed time
float ElapsedTime = appWindow.GetFrameTime();
// Move the sprite
if ( appWindow.GetInput().IsKeyDown(sf::Key::Left) || appWindow.GetInput().IsKeyDown(sf::Key::Right) || appWindow.GetInput().IsKeyDown(sf::Key::Up) || appWindow.GetInput().IsKeyDown(sf::Key::Down) )
{
if (appWindow.GetInput().IsKeyDown(sf::Key::Left))
{
charSpriteSheet.Move(-100 * ElapsedTime, 0);
stateChar = 1;
flipChar = 0;
Animate(6);
}
if (appWindow.GetInput().IsKeyDown(sf::Key::Right))
{
charSpriteSheet.Move( 100 * ElapsedTime, 0);
stateChar = 1;
flipChar = 1;
Animate(6);
}
if (appWindow.GetInput().IsKeyDown(sf::Key::Up))
{
charSpriteSheet.Move(0, -100 * ElapsedTime);
stateChar = 2;
Animate(6);
}
if (appWindow.GetInput().IsKeyDown(sf::Key::Down)) charSpriteSheet.Move(0, 100 * ElapsedTime);
}
else
{
stateChar = 0;
Animate(12);
}
// Clear the screen (fill it with black color)
appWindow.Clear(sf::Color( 0, 0, 0));
appWindow.Draw(charSpriteSheet);
// Display window contents on screen
appWindow.Display();
}
return 0;
};
void Window::SheetCutter(int offset)
{
charSpriteSheet.SetSubRect(sf::IntRect((offset * 26), 0, ((offset * 26) + 26), 35));
};
// This changes the curFrame, so that animations loop and stuff. Pretty easy, although unelegant.
void Window::Animate(int rate)
{
charSpriteSheet.FlipX(flipChar);
if((timerFrame%rate) == 0) // This is, rather obviously, a variable designed to allow to change the frames at the right rate.
{
if(stateChar == 0) // ? Not getting activated. Not getting called...
{
if(curFrame >= 2)
{
curFrame = 0;
}
else
{
curFrame++;
}
}
else if(stateChar == 1) // Walking.
{
if(curFrame >= 5 || curFrame <= 2 )
{
curFrame = 3;
}
else
{
curFrame++;
}
}
else curFrame = 6; // Jump.
SheetCutter(curFrame);
}
std::cout << stateChar;
timerFrame++;
};
// This removes the magenta background, changing the colour to tempClr. Color doesn't really matter as long as the fourth digit is set
// to 0, since it's the alpha value.
void Window::ColourCleaner()
{
sf::Color tempClr(0, 0, 0, 0);
for(int i = 0; i < 182; i++ )
{
for(int j = 0; j < 35; j++)
{
sf::Color CLR = charImage.GetPixel(i, j);
if(deleteColor == CLR)
{
charImage.SetPixel(i, j, tempClr);
}
}
}
};
Window.hpp
#ifndef Window_hpp
#define Window_hpp
class Window
{
sf::RenderWindow appWindow;
sf::Image charImage;
sf::Sprite charSpriteSheet;
sf::Color deleteColor;
int curFrame;
int stateChar;
int timerFrame;
public:
Window();
int Loop();
void SheetCutter();
void Animate(int rate);
void ColourCleaner();
};
#endif
You should put the #include <SFML/Window.hpp> into your header file, as you need its definitions there. (the source file should then include the header instead of duplicating its contents

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.