SFML Game Slows Down When Shooting Bullets - c++

I am making an asteroids game in C++ using SFML. I seem to have a problem though with shooting bullets. Although the class seems to work each time a bullet is shot the game significantly slows down. This is the code for the spaceship and the bullets. I just can't seem to find what's wrong with it! Thank you for your time.
This is the Code of the Ship:
#include "Spaceship.h"
Spaceship::Spaceship(void){}
Spaceship::~Spaceship(void){}
void Spaceship::LoadResources()
{
if(!shipAnimImg.LoadFromFile("Resources/Images/SpaceshipAnimation.png"))
std::cout <<"Could not locate the ship animation image" <<std::endl;
if(!shipIdleImg.LoadFromFile("Resources/Images/SpaceshipIdle.png"))
std::cout <<"Could not locate the ship idle image" <<std::endl;
if(!bulletImg.LoadFromFile("Resources/Images/Bullet.png"))
std::cout <<"Could not locate the bullet image" <<std::endl;
shipSpr.SetImage(shipIdleImg);
shipSpr.SetScale(0.5,0.5);
shipSpr.SetCenter(shipIdleImg.GetWidth() / 2,shipIdleImg.GetHeight() / 2);
x = DEFAULT_SCREENWIDTH / 2;
y = DEFAULT_SCREENHEIGHT / 2;
shipSpr.SetPosition(x,y);
shipSpr.SetRotation(90);
std::cout<<shipSpr.GetCenter().x<<std::endl;
std::cout<<shipSpr.GetCenter().y<<std::endl;
vx = 0.2;
vy = 0.2;
isBulletOnScreen = false;
isPressed = false;
}
void Spaceship::UnloadResources(){}
void Spaceship::Update(sf::RenderWindow &Window,sf::Event event)
{
if (Window.GetInput().IsKeyDown(sf::Key::A))
{
shipSpr.Rotate(0.08);
}
if (Window.GetInput().IsKeyDown(sf::Key::D))
{
shipSpr.Rotate(-0.08);
}
if (Window.GetInput().IsKeyDown(sf::Key::W))
{
x += (cos(shipSpr.GetRotation() * (3.14159265/180.0)) *0.2);
y -= (sin(shipSpr.GetRotation() * (3.14159265/180.0)) *0.2);
shipSpr.SetPosition(x,y);
}
if (Window.GetInput().IsKeyDown(sf::Key::Space) && !isPressed)
{
isBulletOnScreen = true;
isPressed = true;
bullets.push_back(new Bullet(shipSpr.GetPosition().x,shipSpr.GetPosition().y,0.3,shipSpr.GetRotation(),bulletImg));
}
if (event.Type == sf::Event::KeyReleased)
{
isPressed = false;
}
if(bullets.size() != 0)
{
for (int i=0; i<bullets.size(); i++)
{
bullets[i]->Update(Window,event);
if ((bullets[i]->GetX() > DEFAULT_SCREENWIDTH + 40) || (bullets[i]->GetX() < 0 - 40) ||
(bullets[i]->GetY() > DEFAULT_SCREENWIDTH + 40) || (bullets[i]->GetY() < 0 - 40))
{
bullets.erase(bullets.begin() +i);
}
}
std::cout<<bullets.size()<<std::endl;
}
std::cout<<bullets.size()<<std::endl;
}
void Spaceship::Draw(sf::RenderWindow &Window)
{
if(isBulletOnScreen)
for (int i=0; i<bullets.size(); i++)
{
Bullet *cur = bullets[i];
bullets[i]->Draw(Window);
std::cout<<bullets.size()<<std::endl;
}
Window.Draw(shipSpr);
}
And this is for the Bullet:
#include "Bullet.h"
Bullet::Bullet(void){}
Bullet::Bullet(float x,float y,float v,float r,sf::Image image)
{
LoadResources(x,y,v,r,image);
}
Bullet::~Bullet(void){}
void Bullet::LoadResources(float x,float y,float v,float r , sf::Image image)
{
this->x = x;
this->y = y;
this->v = v;
bulletImg = image;
bulletSpr.SetImage(bulletImg);
bulletSpr.SetScale(0.5,0.5);
bulletSpr.SetCenter(bulletImg.GetWidth() / 2,bulletImg.GetHeight() / 2);
bulletSpr.SetPosition(x,y);
bulletSpr.SetRotation(r);
}
void Bullet::UnloadResources(){}
void Bullet::Update(sf::RenderWindow &Window,sf::Event event)
{
x += (cos(bulletSpr.GetRotation() * (3.14159265/180.0)) *v);
y -= (sin(bulletSpr.GetRotation() * (3.14159265/180.0)) *v);
bulletSpr.SetPosition(x,y);
}
void Bullet::SetX(float x)
{
this->x = x;
}
void Bullet::SetY(float y)
{
this->y = y;
}
void Bullet::SetRotation(float r)
{
rotation = r;
}
float Bullet::GetX()
{
return x;
}
float Bullet::GetY()
{
return y;
}
void Bullet::Draw(sf::RenderWindow &Window)
{
Window.Draw(bulletSpr);
}
EDIT: Changed the code so that it loads the image inside the Spaceship Class and passes it to the Bullet's Resources after it is created. The problem still remains the same though. The game becomes more and more slower each time a bullet is shot and it remains slow until it is erased.

1.
You are loading the Bullet PNG image from disk every time you create a new object (often, if you like shooting). The loading from disk is probably going to be very slow. Try to reuse the same image several times instead!
You could probably pull the LoadFromFile function out of LoadResources and put it somewhere where it would last for the duration of the game. Then just have LoadResources refer to that place whenever a new bullet needs to be created. The same goes for any other images or resources that can be reused in your game.
2.
I also saw that you have std::cout in your code. Try removing all of those that are in the rendering loop, as printing is slow.
for (int i=0; i<bullets.size(); i++)
{
Bullet *cur = bullets[i];
bullets[i]->Draw(Window);
std::cout<<bullets.size()<<std::endl; // This is going to be slow
}
3.
You might also want to look at the bullets vector. When adding bullets to it,push_back changes the size of the vector, and that takes some allocation and deallocation of memory each time. A better approach would be to make room for a maximum number of bullets to start with (using the resize function for example) so that the vector doesn't change size whenever a bullet is created.
if (Window.GetInput().IsKeyDown(sf::Key::Space) && !isPressed)
{
isBulletOnScreen = true;
isPressed = true;
bullets.push_back(new Bullet(...); // avoid this
}

Everytime you call a new Bullet
Bullet::Bullet(float x,float y,float v,float r)
{
LoadResources(x,y,v,r);
}
You also call LoadResources(x,y,v,r) which calls
bulletImg.LoadFromFile("Resources/Images/Bullet.png")
and that call read a file from a disk, which is a very slow operation, in order of magnitudes slower than anything else, so your program stops for the duration of the load.

Related

Class objects member variables won't change when function is called

My problem is that I can not change the class members variable value, I tried everything that has come to my mind
So here is the following code that is involved:
if(player.getCollisionObject().isColliding(platform1))
{
if(player.getCollisionObject().up)
std::cout << "Colliding from top\n";
if(player.getCollisionObject().down)
std::cout << "Colliding from bottom\n";
if(player.getCollisionObject().left)
std::cout << "Colliding from left\n";
if(player.getCollisionObject().right)
std::cout << "Colliding from right\n";
}
bool Collision::isColliding(const Entity &other)
{
resetCollisionDirection();
sf::Vector2f otherCenterPosition = other.getCenterPosition();
sf::Vector2f otherSize = other.getSize();
float deltaX = m_CenterPosition.x - otherCenterPosition.x; // abs(deltaX) - (thisX + otherX)
float deltaY = m_CenterPosition.y - otherCenterPosition.y;
float resultX = abs(deltaX) - (m_Size.x / 2 + otherSize.x / 2);
float resultY = abs(deltaY) - (m_Size.y / 2 + otherSize.y / 2);
if(resultX < 0 && resultY < 0)
{
if(m_CenterPosition.x < otherCenterPosition.x)
left = true;
if(m_CenterPosition.x > otherCenterPosition.x)
right = true;
if(m_CenterPosition.y < otherCenterPosition.y)
up = true;
if(m_CenterPosition.y > otherCenterPosition.y)
down = true;
return true;
}
return false;
}
class Collision
{
public:
Collision(const Entity &entity);
void reset(const Entity &entity);
bool isColliding(const Entity &other);
bool up, down, left, right;
private:
void resetCollisionDirection();
private:
sf::Vector2f m_CenterPosition, m_Size;
};
So the problem is that I have a class member of Collision in my player class and with that I am accesing the Collision object from my player and checking if it is colliding with another object and if so it will return true and should also set the internal flag from which direction it is colliding from, but after it returns from the "isColliding()" function the flags from the Collision object hasn't been set
I do not really understand what may be the problem here, I tried debugging it and tried to follow along step by step. My observations were that it did in fact set the flags during the function call but as soon as it returned the information was lost
Any help would be appreciated!
EDIT: Here is the getCollisionObject() function:
Collision Player::getCollisionObject()
{
return m_CollisionBody;
}
EDIT: Found the problem the function above returned a copy (I am an idiot sorry) changed it to
Collision& Player::getCollisionObject()
{
return m_CollisionBody;
}
There's your problem. getCollisionObject() returns by value. Change it to
Collision &Player::getCollisionObject()

Moving player on board

I'm writing board game using SFML and I want my player's figures to move around this board, but I want this to be smooth animated move, from field X to field Y. Unfortunatelly, it isnt happening, my player's figures just changes location, it jumps from lets say field 4 into field 8, while I want to move from 4 to 5, then to 6, then to 7 and finnaly to 8. Hopefully its clear enough. Now let's see some code.
Firstly Field class.
class Field {
int m_position_id;
int m_position_x;
int m_position_y;
std::string m_name;
public:
Field() {}
Field(int, int, int);
virtual ~Field() = default;
int getPosID() { return m_position_id; }
int getPosX() { return m_position_x; }
int getPosY() { return m_position_y; }
};
Then we got Board which is basicly just an array of Fields
constexpr int BOARD_SIZE = 40;
class Board {
std::array<Field, BOARD_SIZE> m_board;
public:
Board();
Field& getBoard(int index) { return m_board[index]; }
};
Player class
class Player {
int m_position_id = 0; //starting position
float m_position_x = 600;
float m_position_y = 600;
sf::CircleShape m_shape;
public:
Player(std::string, sf::Color, float);
sf::CircleShape& getShape() { return m_shape; }
int getPositionID() { return m_position_id; }
float getPositionX() { return m_position_x; }
float getPositionY() { return m_position_y; }
void setPositionID(int p_position_id) { m_position_id = p_position_id; }
void setPositionX(int p_position_x) { m_position_x = p_position_x; }
void setPositionY(int p_position_y) { m_position_y = p_position_y; }
};
And finnaly, method that isnt working as I expect it oo
void GameEngine::movePlayer(Player &p_player, int p_distance) {
int l_current_pos_id = p_player.getPositionID();
p_player.setPositionID(p_player.getPositionID() + p_distance);
p_player.setPositionX(m_game_board.getBoard(p_player.getPositionID()).getPosX());
p_player.setPositionY(m_game_board.getBoard(p_player.getPositionID()).getPosY());
if (p_player.getPositionID() > 39) {
p_player.setPositionID(p_player.getPositionID() - 40);
p_player.setPositionX(m_game_board.getBoard(p_player.getPositionID()).getPosX());
p_player.setPositionY(m_game_board.getBoard(p_player.getPositionID()).getPosY());
}
//going out of array range here probably
for (int i = l_current_pos_id; i < p_player.getPositionID(); i++) {
int x = m_game_board.getBoard(i + 1).getPosX() - m_game_board.getBoard(i).getPosX();
int y = m_game_board.getBoard(i + 1).getPosY() - m_game_board.getBoard(i).getPosY();
p_player.getShape().move(x, y);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
And finnaly, class that handles the view
bool m_draw = false;
while (window.isOpen()) {
if (m_evnt.type == sf::Event::KeyReleased && m_evnt.key.code == sf::Keyboard::R) {
//Roll dice
m_game_engine.rollDice(m_game_status); //this just updates some text, result of rollDice is passed as p_distance to movePlayer
m_draw = true;
}
}
window.clear();
for (int i = 0; i < m_game_engine.getNumberOfPlayers(); i++) {
window.draw(m_game_engine.getPlayer(i).getShape());
}
if (m_draw) {
for (int i = 0; i < m_game_engine.getNumberOfPlayers(); i++) {
window.draw(m_game_engine.getPlayer(i).getShape());
}
window.display();
}
Ah and from GameEngine class
class GameEngine {
std::vector<Player> m_players;
Player& getPlayer(int index) { return m_players[index]; }
};
So as you can see, it stores in local variable current player position, then assigns new one, then by Field position ID it gets X and Y coordinate of this position. Next step is checking if this position is inside array (have to do the same for moving my figure around board, because it crashes after first circuit around the board. Still, thats not the point here. For loop at the end, should move from field i to (i+1), then it should wait for 0,5 sec, move again to next field, etc. Althought, after I run my program, it sleeps at beggining and then not moves, but changes position of my shape and its over, no animation at all.
You have a loop and you have waits. That's not how a game works. You can read up on the basics here.
Your game loop has to run. That's the place where the drawing takes place. If you move your token and don't draw it until it arrived, it will look like a teleport. You need to draw between your mini-moves.
Your token needs a target position and a current position and a speed. And every loop you need to add the appropriate numbers to the current position, until it finally arrives at the target position. But you cannot do that in a closed loop, this needs to happen inside your game loop, as a part of it. You probably also want a variable that indicates that a token is indeed moving, so nothing else can happen while it's not complete.

Rotating sprites relative to it's container has bug while moving

I've been working on making my game engine, and I've been having A LOT of trouble dealing with rotating a sprite relative to a container. (it's used to overlay multiple sprites and be able to easily change their location relative to the center of the object. I need to be able to rotate the object and keep their relative location proper).
I've got it pretty much working. I can rotate the sprite, and all the sprites relative locations stay the same. I can even do this while moving the sprite (it will move AND rotate at the same time). Unless the sprite starts moving again while the sprite is turning. When this happens, the sprite continues to keep it's orientation relative to the container, but will jump back to it's original X/Y location relative to the container.
I stripped down my code to provide a stand alone example program, and the bug persists. To test it, you'll need SFML 2.1, and the following source code
main.cpp
#include<SFML\Graphics.hpp>
#include<vector>
#include"sprite_holder.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 640), "Things don't work so gewd :<");
std::vector<sprite_holder> sprite_holders;
sprite_holders.push_back(sprite_holder(50,50));
sprite_holders.push_back(sprite_holder(150,100));
sprite_holders.push_back(sprite_holder(250,50));
sprite_holders.push_back(sprite_holder(350,50));
sprite_holders.push_back(sprite_holder(450,100));
sprite_holders.push_back(sprite_holder(550,50));
float move1 = -100;
float move2 = -100;
float move3 = -100;
float move4 = -100;
sf::Clock timer;
sprite_holders[3].adjust_child_pos(1,0,20,0);
sprite_holders[4].adjust_child_pos(-1,0,20,0);
sprite_holders[5].adjust_child_pos(-1,0,20,0);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color(255,0,255));
for(unsigned int i = 0; i < sprite_holders.size(); i++) {
sprite_holders[i].update(timer.getElapsedTime().asMilliseconds());
for(unsigned int j = 0; j < sprite_holders[i].sprites.size(); j++) {
window.draw(sprite_holders[i].sprites[j].first);
}
}
// This block of code will make the left-most sprite_holder move up and down constantly
if(sprite_holders[0].transform_complete(POSITION)) {
move1 *= -1;
sprite_holders[0].adjust_pos(0,move1,1200);
}
// This block of code will make the sprite_holder second from the left spin constantly
if(sprite_holders[1].transform_complete(ANGLE)) sprite_holders[1].adjust_angle(360,800);
// This block of code will make the sprite_holder third from the left move up and down AND spin constantly
if(sprite_holders[2].transform_complete(ANGLE)) sprite_holders[2].adjust_angle(360,800);
if(sprite_holders[2].transform_complete(POSITION)) {
move2 *= -1;
sprite_holders[2].adjust_pos(0,move2,1200);
}
// This block of code will make the sprite_holder third from the right move up and down constantly
if(sprite_holders[3].transform_complete(POSITION)) {
move3 *= -1;
sprite_holders[3].adjust_pos(0,move3,1200);
}
// This block of code will make the sprite_holder second from the right spin constantly
if(sprite_holders[4].transform_complete(ANGLE)) sprite_holders[4].adjust_angle(360,800);
// This block of code will make the right-most sprite_holder move up and down AND spin constantly
if(sprite_holders[5].transform_complete(ANGLE)) sprite_holders[5].adjust_angle(360,800);
if(sprite_holders[5].transform_complete(POSITION)) {
move4 *= -1;
sprite_holders[5].adjust_pos(0,move4,1200);
}
window.display();
}
return 0;
}
sprite_holder.cpp
#include "sprite_holder.h"
sprite_holder::sprite_holder(float x, float y)
{
xPos = x;
yPos = y;
cAngle = 0;
lastUpdateTime = -1;
// These are here so I could remove some functions to make tracking the error down much simpler.
// Ignore everything from here till the end of the constructor. It's just loading the sprites and texures
// into memory, initializing the offsets to 0, and setting the initial positions
sf::Sprite sprite1;
sf::Texture texture1;
texture1.loadFromFile("heart_back.png");
textures.push_back(texture1);
sprite1.setTexture(textures.back());
sprite1.setPosition(xPos,yPos);
sf::Vector2u spriteSize = textures.back().getSize();
sprite1.setOrigin(spriteSize.x/2, spriteSize.y/2);
offset offset1;
offset1.xOffset = 0;
offset1.yOffset = 0;
offset1.angleOffset = 0;
offset1.tiltOffset = 0;
sf::Sprite sprite2;
sf::Texture texture2;
texture2.loadFromFile("heart.png");
textures.push_back(texture2);
sprite2.setTexture(textures.back());
sprite2.setPosition(xPos,yPos);
spriteSize = textures.back().getSize();
sprite2.setOrigin(spriteSize.x/2, spriteSize.y/2);
offset offset2;
offset2.xOffset = 0;
offset2.yOffset = 0;
offset2.angleOffset = 0;
offset2.tiltOffset = 0;
sprites.push_back(std::make_pair(sprite1,offset1));
sprites.push_back(std::make_pair(sprite2,offset2));
}
// This is called every frame the window is redrawn.
// (note, the reason I calculate everything based on the timeElapsed since last draw is because
// I don't want the application's speed to be bound to it's framerate)
void sprite_holder::update(int timeElapsed)
{
// Because SFML hates textures for some reason, I'd normally have classes containing the sf::Texture, and keep pointer instances of
// said classes. But since that'd complicate the code a little, I'm just re-loading the image every time I need to draw it. That
// keeps the sprites from being white boxes.
for(unsigned int i = 0; i < sprites.size(); i++) sprites[i].first.setTexture(textures[i]);
int transformToRemove = -1;
for(unsigned int i = 0; i<transforms.size(); i++) {
if(transforms[i].first.startTime == -1) transforms[i].first.startTime = timeElapsed; // This makes anything transforms created before the first update use the proper start time
float percentComplete = (float)(timeElapsed - transforms[i].first.startTime) / transforms[i].first.duration; // this calculates what percentage of the transform's time duration has passed
if(transforms[i].first.type == POSITION) {
if( calculate_transform_pos(percentComplete,i) == true ) transformToRemove = i; // This will calculate the x and y value for the current completion percentage of the transform and remove it if it's 100% complete
render_children_pos(); // This sets all the sf::Sprites to their proper location reletive to the sprite_holder
} else {
// This will calculate the angle value for the current completion percentage of the transform and remove it if it's 100% complete
if( calculate_transform_angle(percentComplete,i) == true ) transformToRemove = i;
render_children_angle(); // This sets all the sf::Sprites to their proper location reletive to the sprite_holder
}
}
lastUpdateTime = timeElapsed;
if(transformToRemove != -1) transforms.erase(transforms.begin()+transformToRemove);
}
// This is a function that will let you know if a given transformation has finished.
// It's used so you can do something as soon as a transformation is complete.
// (an example would be to make a sprite rotate forever by telling it to spin by 360 degrees,
// whenever it's finished spinning by 360 degrees)
bool sprite_holder::transform_complete(transform_type type, int spriteIndex)
{
if(lookup_transform(type,spriteIndex) == -1) return true;
return false;
}
// This will move the sprite_holder's center point by
// the x and y values provided. The argument "duration"
// provides a time in miliseconds the movement will take.
// (note, children will keep their reletive position to the sprite_holder)
void sprite_holder::adjust_pos(float x, float y, int duration)
{
int transformIndex = lookup_transform(POSITION);
if(transformIndex == -1) {
transformIndex = transforms.size();
transform newTransform;
newTransform.type = POSITION;
transforms.push_back(std::make_pair(newTransform,-1));
}
transforms[transformIndex].first.startingA = xPos;
transforms[transformIndex].first.startingB = yPos;
transforms[transformIndex].first.targetA = x + xPos;
transforms[transformIndex].first.targetB = y + yPos;
transforms[transformIndex].first.duration = duration;
transforms[transformIndex].first.startTime = lastUpdateTime;
}
// This will rotate the sprite_holder by the angle
// value provided. The argument "duration" provides
// a time in miliseconds the rotation will take.
// (note, children will keep their reletive position and angle to the sprite_holder)
void sprite_holder::adjust_angle(float angle, int duration)
{
int transformIndex = lookup_transform(ANGLE);
if(transformIndex == -1) {
transformIndex = transforms.size();
transform newTransform;
newTransform.type = ANGLE;
transforms.push_back(std::make_pair(newTransform,-1));
}
transforms[transformIndex].first.startingA = cAngle;
transforms[transformIndex].first.targetA = angle + cAngle;
transforms[transformIndex].first.duration = duration;
transforms[transformIndex].first.startTime = lastUpdateTime;
}
// This will move the sf::Sprite specified by spriteIndex
// by the x and y values provided. This movement will last
// as long as the provided duration argument.
void sprite_holder::adjust_child_pos(int spriteIndex, float x, float y, int duration)
{
if (spriteIndex == -1) spriteIndex = sprites.size()-1;
int transformIndex = lookup_transform(ANGLE,spriteIndex);
if(transformIndex == -1) {
transformIndex = transforms.size();
transform newTransform;
newTransform.type = POSITION;
transforms.push_back(std::make_pair(newTransform,spriteIndex));
}
transforms[transformIndex].first.startingA = sprites[spriteIndex].second.xOffset;
transforms[transformIndex].first.startingB = sprites[spriteIndex].second.yOffset;
transforms[transformIndex].first.targetA = x + sprites[spriteIndex].second.xOffset;
transforms[transformIndex].first.targetB = y + sprites[spriteIndex].second.yOffset;
transforms[transformIndex].first.duration = duration;
transforms[transformIndex].first.startTime = lastUpdateTime;
}
// This will rotate the sf::Sprite specified by spriteIndex
// by the angle value provided. This movement will last
// as long as the provided duration argument.
void sprite_holder::adjust_child_angle(int spriteIndex, float angle, int duration)
{
if (spriteIndex == -1) spriteIndex = sprites.size()-1;
int transformIndex = lookup_transform(ANGLE,spriteIndex);
if(transformIndex == -1) {
transformIndex = transforms.size();
transform newTransform;
newTransform.type = ANGLE;
transforms.push_back(std::make_pair(newTransform,spriteIndex));
}
transforms[transformIndex].first.startingA = sprites[spriteIndex].second.tiltOffset;
transforms[transformIndex].first.targetA = angle + sprites[spriteIndex].second.tiltOffset;
transforms[transformIndex].first.duration = duration;
transforms[transformIndex].first.startTime = lastUpdateTime;
}
// This function is called every time a transform updates either an sf::Sprite or the sprite_holder's position
// note: the reason angleOffset is set here is because the reletive angle to the sprite_holder only changes when it's
// reletive position does. It doesn't matter how much you rotate the sprite_holder, the reletive angle of the sf::Sprite is the same
void sprite_holder::render_children_pos()
{
for(unsigned int i = 0; i < sprites.size(); i++) {
sprites[i].first.setPosition(xPos+sprites[i].second.xOffset, yPos+sprites[i].second.yOffset);
sf::Vector2f spritePos = sprites[i].first.getPosition();
sprites[i].second.angleOffset = atan2(spritePos.y - yPos, spritePos.x - xPos);
}
}
void sprite_holder::render_children_angle()
{
for(unsigned int i = 0; i < sprites.size(); i++) {
sf::Vector2f spritePos = sprites[i].first.getPosition();
float radius = sqrt(pow((xPos - spritePos.x), 2) + pow((yPos - spritePos.y), 2)); // xPos and yPos are the container's x and y position
float angle = sprites[i].second.angleOffset + (cAngle /180*3.14); // cAngle is the container's angle
float newX = xPos + radius * cos(angle);
float newY = yPos + radius * sin(angle);
sprites[i].first.setPosition(newX, newY); // this sets the sprite's x and y coordinates
sprites[i].first.setRotation(cAngle + sprites[i].second.tiltOffset); // this sets the spries rotation around it's local axis. it only affects the sprite's orientation, not position
}
}
// This function returns the index of the transform.
// If you give it a spriteIndex value, it'll look for transforms
// bound to an sf::Sprite contained within the sprite_holder.
// Otherwise, it'll look for transforms bound to the sprite_holder.
int sprite_holder::lookup_transform(transform_type type, int spriteIndex)
{
int result = -1;
for(unsigned int i = 0; i < transforms.size(); i++) {
if(transforms[i].first.type == type) {
if(transforms[i].second == spriteIndex) result = i;
break;
}
}
return result;
}
// This returns the value a given percent between the start and end value
// It's so I can calculate what is 33.2687% between 36.2 and 55, or some other such
// nonesense that occurs when moving things around
float sprite_holder::percentage_along_distance(float startValue,float endValue, float percentComplete)
{
return ((1-percentComplete) * startValue) + (percentComplete * endValue);
}
// This function will set either an sf::Sprite or a sprite_holder (the transform provided by transformIndex tells it which to set)
// to the proper location a given percentage through the transformation.
// For example, if the start point of the transform is 0,0, the end point is 0,10, and we tell it we're 50% done with the transform
// it'll set the proper entity to 0,5
bool sprite_holder::calculate_transform_pos(float percentComplete, int transformIndex) // returns true when the transform is finished
{
float x;
float y;
if(percentComplete < 1) {
x = percentage_along_distance(transforms[transformIndex].first.startingA, transforms[transformIndex].first.targetA, percentComplete);
y = percentage_along_distance(transforms[transformIndex].first.startingB, transforms[transformIndex].first.targetB, percentComplete);
} else {
x = transforms[transformIndex].first.targetA;
y = transforms[transformIndex].first.targetB;
}
if(transforms[transformIndex].second == -1) {
xPos = x;
yPos = y;
} else {
int spriteIndex = transforms[transformIndex].second;
sprites[spriteIndex].second.xOffset = x;
sprites[spriteIndex].second.yOffset = y;
}
if(percentComplete >= 1) return true;
return false;
}
// This does the same as calculate_transform_pos, but with angles. I'm planning on merging the two functions, but haven't yet come up with a good way to go about it.
bool sprite_holder::calculate_transform_angle(float percentComplete, int transformIndex) // returns true when the transform is finished
{
float angle;
if(percentComplete < 1) {
angle = percentage_along_distance(transforms[transformIndex].first.startingA, transforms[transformIndex].first.targetA, percentComplete);
} else {
angle = transforms[transformIndex].first.targetA;
}
if(transforms[transformIndex].second == -1) {
cAngle = angle;
} else {
int spriteIndex = transforms[transformIndex].second;
sprites[spriteIndex].second.tiltOffset = angle;
}
if(percentComplete >= 1) return true;
return false;
}
offset.h
#ifndef _LBMOON_OFFSET_H
#define _LBMOON_OFFSET_H
struct offset
{
float xOffset;
float yOffset;
float angleOffset;
float tiltOffset;
};
#endif
sprite_holder.h
#ifndef _LBMOON_SPRITE_H
#define _LBMOON_SPRITE_H
#include<SFML\Graphics.hpp>
#include<vector>
#include<string>
#include<utility>
#include <math.h>
#include "transform.h"
#include "offset.h"
class sprite_holder
{
public:
// General Interface Functions
sprite_holder(float x, float y);
void update(int timeElapsed);
bool transform_complete(transform_type type, int spriteIndex=-1);
// Shell functions (transform the whole sprite)
void adjust_pos(float x, float y, int duration);
void adjust_angle(float angle, int duration);
// Child functions (transform a specific drawable)
// note: when passing drawIndex, -1 means the top drawable
void adjust_child_pos(int spriteIndex, float x, float y, int duration);
void adjust_child_angle(int spriteIndex, float angle, int duration);
std::vector<std::pair<sf::Sprite,offset>> sprites;
std::vector<sf::Texture> textures;
protected:
int lookup_transform(transform_type type, int spriteIndex = -1);
void render_children_pos();
void render_children_angle();
float percentage_along_distance(float startValue,float endValue, float percentComplete);
float xPos;
float yPos;
float cAngle;
int lastUpdateTime;
std::vector<std::pair<transform,int>> transforms;
private:
bool calculate_transform_pos (float percentComplete, int transformIndex); // returns true when the transform is finished
bool calculate_transform_angle(float percentComplete, int transformIndex); // returns true when the transform is finished
};
#endif
transform.h
#ifndef _LBMOON_TRANSFORM_H
#define _LBMOON_TRANSFORM_H
enum transform_type{UNKNOWN=-1,POSITION=0,SCALE,ANGLE};
struct transform
{
transform_type type;
int startTime;
int duration;
float startingA;
float startingB;
float targetA;
float targetB;
};
#endif
You'll also want to put the following images with the program:
http://legacyblade.com/images/heart.png
http://legacyblade.com/images/heart_back.png
I've been working on getting this class working for a couple weeks now, and after testing all day to find the source of this particularly baffling error, I've come up dry. So thanks for reading this! Any help you could provide would be amazing.

platform game using sfml 1.6 in c++ collision using AABB's

I am using tile mapping and have my map class in place to draw the map by using an array of sprites. i have it to set the position of the sprite and then create a bounding box array around it and then draw the sprite.
i then have a collision class which gets the player bounding box and compares it with each bounding box for the sprite. i have an array called platformboundingBox. this stores each bounding box of each sprite in the array. however when i compare the values it seems that the platform bounding box has no values in any of the locations yet the i have checked that the values of each sprite go into the bounding box array.
here is my map class. see the drawmap and collision functions to take a look. if anyone can help i would really appreciate it.
#include "Map.h"
#include "Block.h"
#include <sstream>
using namespace std;
Map::Map()
{
//map ctor;
}
Map::~Map()
{
// map dtor
}
void Map::Initialise(const char *filename)
{
if(!BlockImage.LoadFromFile("Images/block.png"))
cout<<endl<<"failed to load block image"<<endl;
if(!GemImage.LoadFromFile("Images/Gem.png"))
cout<<endl<<"failed to load Gem Image"<<endl;
if(!leftBlockImage.LoadFromFile("Images/blockLeft.png"))
cout<<endl<<"failed to load left block Image"<<endl;
if(!rightBlockImage.LoadFromFile("Images/blockRight.png"))
cout<<endl<<"failed to load right block Image"<<endl;
std::ifstream openfile(filename);
std::vector <int> tempvector;
std::string line;
while(std::getline(openfile, line))
{
for(int i =0; i < line.length(); i++)
{
if(line[i] != ' ') // if the value is not a space
{
char value = line[i];
tempvector.push_back(value - '0');
}
}
mapVector.push_back(tempvector); // push back the value of the temp vector into the map vector
tempvector.clear(); // clear the temp vector readt for the next value
}
}
void Map::DrawMap(sf::RenderWindow &Window)
{
Player playermap;
for(i = 0; i < mapVector.size(); i++)
{
for(j = 0; j < mapVector[i].size(); j++)
{
if(mapVector[i][j] == 1)
{
sprite[j].SetImage(BlockImage);
sprite[j].SetPosition(j * BLOCKSIZE, i * BLOCKSIZE);
platformBoundingBox[j].Bottom = sprite[j].GetPosition().y;
platformBoundingBox[j].Left = sprite[j].GetPosition().x - 5;
platformBoundingBox[j].Right = sprite[j].GetPosition().x;
Window.Draw(sprite[j]);
}
else if(mapVector[i][j] == 2)
{
sprite[j].SetImage(GemImage);
sprite[j].SetPosition(j * BLOCKSIZE, i * BLOCKSIZE);
platformBoundingBox[j].Top = sprite[j].GetPosition().y - 5;
platformBoundingBox[j].Bottom = sprite[j].GetPosition().y;
platformBoundingBox[j].Left = sprite[j].GetPosition().x - 5;
platformBoundingBox[j].Right = sprite[j].GetPosition().x;
Window.Draw(sprite[j]);
}
else if(mapVector[i][j] == 3)
{
sprite[j].SetImage(leftBlockImage);
sprite[j].SetPosition(j * BLOCKSIZE, i * BLOCKSIZE);
platformBoundingBox[j].Top = sprite[i].GetPosition().y - 5;
platformBoundingBox[j].Bottom = sprite[i].GetPosition().y;
platformBoundingBox[j].Left = sprite[i].GetPosition().x - 5;
platformBoundingBox[j].Right = sprite[i].GetPosition().x;
Window.Draw(sprite[j]);
}
else if(mapVector[i][j] == 4)
{
sprite[j].SetImage(rightBlockImage);
sprite[j].SetPosition(j * BLOCKSIZE, i * BLOCKSIZE);
platformBoundingBox[j].Top = sprite[i].GetPosition().y - 5;
platformBoundingBox[j].Bottom = sprite[i].GetPosition().y;
platformBoundingBox[j].Left = sprite[i].GetPosition().x - 5;
platformBoundingBox[j].Right = sprite[i].GetPosition().x;
Window.Draw(sprite[j]);
}
}
}
}
void Map::collisions(float x, float y)
{
Player playermap;
this->x = x;
this->y = y;
playerboundingbox.Top = y - 5;
playerboundingbox.Bottom = y ;
playerboundingbox.Left = x - 5;
playerboundingbox.Right = x;
for(i = 0; i < 100; i++)
{
if(playerboundingbox.Intersects(platformBoundingBox[i]))
cout << " praise the lord";
}
}
Please switch to SFML 2 because 1.6 have a lot of bugs.
Let's say you create a class named handler where you will put:
handler::handler()
// window initialization
Map Map; // here initialize the Map class
/* why don't use Map::Map( ctor) for initialization? */
// player initialization
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
sf::Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
//draw player
Map.DrawMap(); // also need to improve the drawing for less lag
window.display();
update(Map &Map, Player &Player);
// every time to use & because without the compiler will create another object
}
}
update(Map &Map, Player &Player)
{
// verify if exists some interacts
if (intersects(Map &Map, Player &Player))
{
//verify from where and put to the correct position
/* e.g: if we have a collide with a down tile map will say something like this:
Player.setPosition(Player.getPosition().x, (Player.getGlobalBounds().top+Player.getGlobalBounds().height)-(Map.getGlobalBounds().top-(Player.getGlobalBounds().top+Player.getGlobalBounds().height)); */
}
}
intersects(Map &Map, Player &Player)
{
sf::FloatRect fPlayer = Player.getGlobalBounds();
for (int i=0; i<Map.NrOfYourTiles; ++i)
{
sf::FloatRect fMap = YourTile.getGlobalBounds();
if (fPlayer.intersects(fMap))
return 1;
}
return 0;
}
Hope this will help you( the code is in SFML 2.0). You can find a lot more help on forums of the creator sfml-dev.org.

How do I made shooting multiple bullets function correctly using a for loop?

I'm working on a prototype for a shmup game in C++ using SDL...Right now I'm just trying to get the basics working without using classes. Now, I have it so it shoots multiple bullets, but it behaves strangely which I believe is because of the way the counter is reset...The bullets will appear and disappear, and some will keep blinking in the original spot they were shot at, and there will sometimes be a delay before any can be shot again even if the limit isn't on the screen...And sometimes the player character will suddenly jump way to the right and only be able to move up and down. How do I fix this so it smoothly shoots? I've included all relevent code...
[edit] Please note that I intend on cleaning it up and moving it all to a class once I get this figured out...This is just a simple prototype so I can have the basics of the game programmed in.
[edit2] ePos is the enemy position, and pPos is the player position.
//global
SDL_Surface *bullet[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
bool shot[10];
int shotCount = 0;
SDL_Rect bPos[10];
//event handler
case SDLK_z: printf("SHOT!"); shot[shotCount] = true; ++shotCount; break;
//main function
for(int i = 0; i <= 9; i++)
{
shot[i] = false;
bullet[i] = IMG_Load("bullet.png");
}
//game loop
for(int i = 0; i <= shotCount; i++)
{
if(shot[i] == false)
{
bPos[i].x = pPos.x;
bPos[i].y = pPos.y;
}
if(shot[i] == true)
{
bPos[i].y -= 8;
SDL_BlitSurface(bullet[i], NULL, screen, &bPos[i]);
if( (bPos[i].y + 16 == ePos.y + 16) || (bPos[i].x + 16 == ePos.x + 16) )
{
shot[i] = false;
}
else if(bPos[i].y == 0)
{
shot[i] = false;
}
}
}
if(shotCount >= 9) { shotCount = 0; }
Here is something like I was suggesting in the comment. It was just written off the top of my head but it gives you a general idea of what I'm talking about..
class GameObject
{
public:
int x;
int y;
int width;
int height;
int direction;
int speed;
GameObject()
{
x = 0;
y = 0;
width = 0;
height = 0;
direction = 0;
speed = 0;
}
void update()
{
// Change the location of the object.
}
bool collidesWidth(GameObject *o)
{
// Test if the bullet collides with Enemy.
// If it does, make it invisible and return true
}
}
GameObject bullet[10];
GameObject enemy[5];
while(true)
{
for(int x=0; x<=10;x++)
{
bullet[x].update();
for(int y=0;y<=5;y++)
{
if(bullet[x].collidesWith(&enemy[y])
{
// Make explosion, etc, etc.
}
}
}
}