I am trying to animate a sprite in sfml. At the moment I am able to move the sprite and change it's image when moving in a different direction, but I want to animate it while it is moving. I am thinking that there might be a way to accomplish this with sf::Clock or there might be a better way. All sprites are on the same sprite sheet so I just need to find a way to change the X and Y coordinates of the textureRect based on a time while moving in a direction. If I am missing something or you have any questions, I will answer to the best of my ability.
main.cpp
#include <iostream>
#include <SFML/Graphics.hpp>
#include "Character.hpp"
int main() {
sf::RenderWindow window(sf::VideoMode(5000, 5000), "Awesome Game" );
Character Boi("SpritesBoi.png", 0, 0, 5, 100);
sf::Sprite BoiSprite = Boi.getSprite();
Boi.SheetX = 0;
Boi.SheetY = 48;
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();
}
}
Boi.Move();
BoiSprite.setTextureRect(sf::IntRect(Boi.SheetX, Boi.SheetY, 110, 150));
BoiSprite.setPosition(Boi.x_pos, Boi.y_pos);
window.clear(sf::Color(255, 255, 255));
window.draw(BoiSprite);
window.display();
}
}
Character.hpp
#ifndef Character_hpp
#define Character_hpp
#include <stdio.h>
#include <SFML/Graphics.hpp>
#endif /* Character_hpp */
class Character{
public:
int health;
int speed;
int x_pos;
int y_pos;
int SheetX;
int SheetY;
sf::Texture texture;
sf::Sprite sprite;
Character(std::string image, int xlocation, int ylocation, int s, int h){
health = h;
speed = s;
x_pos = xlocation;
y_pos = ylocation;
texture.loadFromFile(image);
}
sf::Sprite getSprite() {
sprite.setTexture(texture);
sprite.setPosition(x_pos, y_pos);
sprite.setTextureRect(sf::IntRect(SheetX, SheetY, 110, 150));
return sprite;
}
void Move();
};
Character.cpp
#include "Character.hpp"
#include <iostream>
void Character::Move(){
//Up
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
SheetX = 0;
SheetY = 192;
y_pos = y_pos - 1;
Up = true;
}
//Down
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
SheetX = 0;
SheetY = 48;
y_pos = y_pos + 1;
Down = false;
}
//Left
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
SheetX = 0;
SheetY = 480;
x_pos = x_pos - 1;
Left = true;
}
//Right
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
SheetX = 0;
SheetY = 339;
x_pos = x_pos + 1;
Right = true;
}
//Up Right
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) and sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
SheetX = 334;
SheetY = 490;
}
//Up Left
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) and sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
SheetX = 333;
SheetY = 340;
}
//Down Right
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) and sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
SheetX = 334;
SheetY = 48;
}
//Down Left
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) and sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
SheetX = 334;
SheetY = 191;
}
}
You need to keep track of the frames in the animation (list of sf::IntRects). And have some sort of delay inbetween. On update, simply move through the frames and apply the rectangle.
struct Frame {
sf::IntRect rect;
double duration; // in seconds
};
class Animation {
std::vector<Frame> frames;
double totalLength;
double totalProgress;
sf::Sprite *target;
public:
Animation(sf::Sprite& target) {
this->target = ⌖
totalProgress = 0.0;
}
void addFrame(Frame&& frame) {
frames.push_back(std::move(frame));
totalLength += frame.duration;
}
void update(double elapsed) {
totalProgress += elapsed;
double progress = totalProgress;
for(auto frame : frames) {
progress -= (*frame).duration;
if (progress <= 0.0 || &(*frame) == &frames.back())
{
target->setTextureRect((*frame).rect);
break; // we found our frame
}
}
};
You can use like so:
sf::Sprite myCharacter;
// Load the image...
Animation animation(myCharacter);
animation.addFrame({sf::IntRect(x,y,w,h), 0.1});
// do this for as many frames as you need
// In your main loop:
animation.update(elapsed);
window.draw(myCharacter);
Related
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:
So I am creating a simple Pong game using c++ and the SFML graphics library in Ubuntu 19.04, but when I run my program it seems to work fine until around 5 seconds later, I get a warning saying my program isn't responding and the choice to wait or force quit the application. When I click wait the warning goes away for another 5 seconds but comes back up. How do I stop this from happening or is there something in my code causing this to happen?
Edit, I need this to be real time input otherwise the game uses the key repeat delay.
Edit, Discovered pollEvent did not need to be the condition for a while loop. So i put it in the main loop, This fixed it!
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
// init global variables
int screenX = 1920, screenY = 1080; // Screen size
int paddleWidth = 30, paddleHeight = 200; // Paddle size
int orbWidth = 26, orbHeight = 26; // Orb size
float objectLocations [6] = // This is an array
{
/*paddleL_X_G*/ 0, /*paddleL_Y_G*/ 0,
/*paddleR_X_G*/ 0, /*paddleR_Y_G*/ 0,
/*orbL_X_G*/ 0, /*orbL_Y_G*/ 0
};
float speed = 1;
// init window
sf::RenderWindow window(sf::VideoMode(screenX, screenY), "SFML Tests!"); // Init window
sf::Event event;
// Defines all objects to be drawn on the screen
class defineObjects
{
public:
void leftPaddle(int paddleL_X, int paddleL_Y) // Define the leftPaddle
{
sf::RectangleShape paddleL(sf::Vector2f(paddleWidth,paddleHeight));
paddleL.setFillColor(sf::Color::White);
paddleL.setPosition(paddleL_X,paddleL_Y);
window.draw(paddleL);
}
void rightPaddle(int paddleR_X, int paddleR_Y) // Define the rightPaddle
{
sf::RectangleShape paddleR(sf::Vector2f(paddleWidth,paddleHeight));
paddleR.setFillColor(sf::Color::White);
paddleR.setPosition(paddleR_X,paddleR_Y);
window.draw(paddleR);
}
void orb(int orbX, int orbY)
{
int orbSize = 26;
sf::RectangleShape orbShape(sf::Vector2f(orbSize,orbSize));
orbShape.setFillColor(sf::Color::Red);
orbShape.setPosition(orbX,orbY);
window.draw(orbShape);
}
};
class eventHandler
{
public:
void input()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
objectLocations[3] -= speed;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
objectLocations[3] += speed;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
objectLocations[1] -= speed;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
objectLocations[1] += speed;
}
}
};
int main()
{
// Get classes
defineObjects O;
eventHandler E;
// inital object positions
objectLocations[0] = paddleWidth; // paddleL_X
objectLocations[1] = screenY / 2 - (paddleHeight / 2); // paddleL_Y
objectLocations[2] = screenX - (paddleWidth * 2); // paddleR_X
objectLocations[3] = screenY / 2 - (paddleHeight / 2); // paddleR_Y
objectLocations[4] = screenX / 2 + (orbWidth / 2); // orbX
objectLocations[5] = screenY / 2 - (orbHeight / 2); // orbY
// Logic
while(window.isOpen()) // Main loop
{
// Clear display
window.clear();
// Input
E.input();
// Update object locations
O.leftPaddle(objectLocations[0],objectLocations[1]);
O.rightPaddle(objectLocations[2],objectLocations[3]);
O.orb(objectLocations[4],objectLocations[5]);
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace std;
// init global variables
int screenX = 1920, screenY = 1080; // Screen size
int paddleWidth = 30, paddleHeight = 200; // Paddle size
int orbWidth = 26, orbHeight = 26; // Orb size
float objectLocations [6] = // This is an array
{
/*paddleL_X_G*/ 0, /*paddleL_Y_G*/ 0,
/*paddleR_X_G*/ 0, /*paddleR_Y_G*/ 0,
/*orbL_X_G*/ 0, /*orbL_Y_G*/ 0
};
float speed = 1;
// init window
sf::RenderWindow window(sf::VideoMode(screenX, screenY), "SFML Tests!"); // Init window
sf::Event event;
// Defines all objects to be drawn on the screen
class defineObjects
{
public:
void leftPaddle(int paddleL_X, int paddleL_Y) // Define the leftPaddle
{
sf::RectangleShape paddleL(sf::Vector2f(paddleWidth,paddleHeight));
paddleL.setFillColor(sf::Color::White);
paddleL.setPosition(paddleL_X,paddleL_Y);
window.draw(paddleL);
}
void rightPaddle(int paddleR_X, int paddleR_Y) // Define the rightPaddle
{
sf::RectangleShape paddleR(sf::Vector2f(paddleWidth,paddleHeight));
paddleR.setFillColor(sf::Color::White);
paddleR.setPosition(paddleR_X,paddleR_Y);
window.draw(paddleR);
}
void orb(int orbX, int orbY)
{
int orbSize = 26;
sf::RectangleShape orbShape(sf::Vector2f(orbSize,orbSize));
orbShape.setFillColor(sf::Color::Red);
orbShape.setPosition(orbX,orbY);
window.draw(orbShape);
}
};
class eventHandler
{
public:
void input()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
objectLocations[3] -= speed;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
objectLocations[3] += speed;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
objectLocations[1] -= speed;
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
objectLocations[1] += speed;
}
}
};
int main()
{
// Get classes
defineObjects O;
eventHandler E;
// inital object positions
objectLocations[0] = paddleWidth; // paddleL_X
objectLocations[1] = screenY / 2 - (paddleHeight / 2); // paddleL_Y
objectLocations[2] = screenX - (paddleWidth * 2); // paddleR_X
objectLocations[3] = screenY / 2 - (paddleHeight / 2); // paddleR_Y
objectLocations[4] = screenX / 2 + (orbWidth / 2); // orbX
objectLocations[5] = screenY / 2 - (orbHeight / 2); // orbY
// Logic
while(window.isOpen()) // Main loop
{
// Clear display
window.clear();
// Input
E.input();
// Update object locations
O.leftPaddle(objectLocations[0],objectLocations[1]);
O.rightPaddle(objectLocations[2],objectLocations[3]);
O.orb(objectLocations[4],objectLocations[5]);
// Show display
window.display();
}
return 0;
}
I'm a beginner and I try to use the SFML library but I have a problem with my code
#pragma region include
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
#include <cstdlib>
#pragma endregion include
sf::RenderWindow fenetre(sf::RenderWindow*);
sf::RectangleShape rectDraw(sf::RectangleShape*);
sf::CircleShape cercleDraw(sf::CircleShape*);
void CentreCercle(sf::CircleShape *cercle, int*, int*);
void fermetureFenetre();
void main()
{
#pragma region variables
sf::RenderWindow window;
fenetre(&window);
sf::RectangleShape rect;
rectDraw(&rect);;
sf::CircleShape cercle;
cercleDraw(&cercle);
int xCentreCercle;
int yCentreCercle;
CentreCercle(&cercle, &xCentreCercle, &yCentreCercle);
float speed = 1;
sf::Vector2i positionSouris;
#pragma endregion variables
while(window.isOpen())
{
#pragma region fenOpen
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
}
#pragma endregion fenOpen
#pragma region KeyboardRectangle
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
rect.move(0, -speed);
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
rect.move(0, speed);
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
rect.move(-speed, 0);
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
rect.move(speed, 0);
#pragma endregion KeyboardRectangle
#pragma region KeyboardCercle
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Z))
cercle.move(0, -speed);
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
cercle.move(0, speed);
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
cercle.move(-speed, 0);
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
cercle.move(speed, 0);
#pragma endregion KeyboardCercle
#pragma region MouseCercle
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
bool boucle = true;
sf::Vector2f position = cercle.getPosition();
xCentreCercle = cercle.getPosition().x + cercle.getRadius();
yCentreCercle = cercle.getPosition().y+ cercle.getRadius();
float rayon = cercle.getRadius();
positionSouris = sf::Mouse::getPosition(window);
int xSouris = positionSouris.x;
int ySouris = positionSouris.y;
float resultat = (xCentreCercle-xSouris)*(xCentreCercle-xSouris)+(yCentreCercle-ySouris)*(yCentreCercle-ySouris);
if(sqrt(resultat)<= rayon)
{
int diffX;
int diffY;
diffX = xSouris-cercle.getPosition().x;
diffY = ySouris-cercle.getPosition().y;
while(boucle == true)
{
positionSouris = sf::Mouse::getPosition(window);
xSouris = positionSouris.x;
ySouris = positionSouris.y;
cercle.setPosition(xSouris - diffX, ySouris - diffY);
window.draw(rect);
window.draw(cercle);
window.display();
window.clear();
if (sf::Mouse::isButtonPressed(sf::Mouse::Left) == false)
boucle = false;
}
}
}
if(sf::Mouse::isButtonPressed(sf::Mouse::Right) && sf::Keyboard::isKeyPressed(sf::Keyboard::C))
{
positionSouris = sf::Mouse::getPosition(window);
int xSouris = positionSouris.x;
int ySouris = positionSouris.y;
cercle.setPosition(xSouris, ySouris);
}
#pragma endregion MouseCercle
#pragma region Mouserectangle
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
bool boucle = true;
sf::Vector2f position = rect.getPosition();
sf::Vector2f taille = rect.getSize();
int xMax = position.x + taille.x;
int xMin = position.x;
int yMax = position.y + taille.y;
int yMin = position.y;
positionSouris = sf::Mouse::getPosition(window);
int xSouris = positionSouris.x;
int ySouris = positionSouris.y;
if(xSouris > xMin && xSouris < xMax && ySouris > yMin && ySouris < yMax)
{
int diffX;
int diffY;
diffX = xSouris-xMin;
diffY = ySouris-yMin;
while(boucle == true)
{
positionSouris = sf::Mouse::getPosition(window);
xSouris = positionSouris.x;
ySouris = positionSouris.y;
rect.setPosition(xSouris - diffX, ySouris - diffY);
window.draw(rect);
window.draw(cercle);
window.display();
window.clear();
if (sf::Mouse::isButtonPressed(sf::Mouse::Left) == false)
boucle = false;
}
}
}
if(sf::Mouse::isButtonPressed(sf::Mouse::Right)&& sf::Keyboard::isKeyPressed(sf::Keyboard::R))
{
positionSouris = sf::Mouse::getPosition(window);
int xSouris = positionSouris.x;
int ySouris = positionSouris.y;
rect.setPosition(xSouris, ySouris);
}
#pragma endregion MouseRectangle
window.draw(rect);
window.draw(cercle);
window.display();
window.clear();
}
}
void fenetre(sf::RenderWindow &window)
{
window.create(sf::VideoMode(800,600),"Tuto SFML");
window.setPosition(sf::Vector2i(50,50));
window.setFramerateLimit(60);
}
void fermetureFenetre(sf::RenderWindow &window)
{
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
}
}
void rectDraw(sf::RectangleShape &rect)
{
rect.setSize(sf::Vector2f(200, 100));
rect.setPosition(10, 10);
rect.setFillColor(sf::Color(250, 100, 150));
}
void cercleDraw(sf::CircleShape &cercle)
{
cercle.setFillColor(sf::Color(100,250,50));
cercle.setRadius(50);
cercle.setPosition(0, 0);
}
void CentreCercle(sf::CircleShape &cercle, int &xCentreCercle, int
&yCentreCercle)
{
xCentreCercle = cercle.getPosition().x + cercle.getRadius();
yCentreCercle = cercle.getPosition().y+ cercle.getRadius();
}
This program just serve to move rectangle or circle with keyboard or mouse.
When all the program is in the main function I don't have any probleme but I want use subroutine and class in the future when I will be training but I have the following error ! error C2248
After search I think the probleme come from function 'sf::RenderWindow' but again beginner I don't understand how get arround the problem.
Thanks to help! :)
The problem is as #Jepessen mentioned you basically have a return type of sf::RenderWindow on your declaration, and your parameter is of type Pointer sf::RenderWindow:
sf::RenderWindow fenetre(sf::RenderWindow*);
And then when you define the function, you are returning void, and your parameter is a Reference sf::RenderWindow:
void fenetre(sf::RenderWindow &window)
{
// Code
}
To Fix this, make the return type of the declaration of fenetre void, since you are not actually returning a value at all, and make your parameter Reference to sf::RenderWindow:
// Declaration, on top of your program
void fenetre(sf::RenderWindow&);
// Definition, at the bottom
void fenetre(sf::RenderWindow &window)
{
// Code
}
I'am new there. I've been learning classes and tried to make a very simple platform game. But I have problem now. I've wanted to set Class "Player" to collide with 2 objects of Class "Block" But Collision do not work for one of them.
Here is my code:
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#undef main
class Block
{
private:
SDL_Texture *BlockTexture;
public:
Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height);
~Block();
void Draw(SDL_Renderer *renderTarget);
SDL_Rect BlockPos;
};
Block::Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
BlockTexture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
BlockPos.x = xPos;
BlockPos.y = yPos;
BlockPos.w = Width;
BlockPos.h = Height;
}
Block::~Block()
{
SDL_DestroyTexture(BlockTexture);
}
void Block::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, BlockTexture, NULL, &BlockPos);
}
class Player
{
private:
SDL_Texture *Texture;
float moveSpeed;
float jumpSpeed;
int falling = 0;
SDL_Scancode keys [3];
public:
SDL_Rect PlayerPos;
Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height);
~Player();
void Update(float delta, const Uint8 *Keystate);
void Draw(SDL_Renderer *renderTarget);
bool Collision(Block &p);
};
Player::Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
Texture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
PlayerPos.x = PosX;
PlayerPos.y = PosY;
PlayerPos.w = Width;
PlayerPos.h = Height;
keys[0] = SDL_SCANCODE_UP;
keys[1] = SDL_SCANCODE_LEFT;
keys[2] = SDL_SCANCODE_RIGHT;
moveSpeed = 200.f;
jumpSpeed = 100.f;
}
Player::~Player()
{
SDL_DestroyTexture(Texture);
}
void Player::Update(float delta, const Uint8 *KeyState)
{
if(KeyState[keys[0]])
{
PlayerPos.y -= moveSpeed * delta;
}
if(KeyState[keys[1]])
{
PlayerPos.x -= (moveSpeed / 2) * delta;
}
if(KeyState[keys[2]])
{
PlayerPos.x += moveSpeed * delta;
}
if(falling == 0)
{
PlayerPos.y += jumpSpeed * delta;
}
}
void Player::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, Texture, NULL, &PlayerPos);
}
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *Renderer)
{
SDL_Texture *texture = NULL;
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
texture = SDL_CreateTextureFromSurface(Renderer, surface);
}
SDL_FreeSurface(surface);
return texture;
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("Platform", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
SDL_Renderer *renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
int imgFlags = IMG_INIT_PNG;
int currentTime = 0;
int previousTime = 0;
float delta = 0;
const Uint8 *Keystate;
Player Player(renderTarget, "BlockP.png", 100, 100, 50, 50);
Block Block1(renderTarget, "Block.png", 0, 500, 800, 100);
Block Block2(renderTarget, "Block.png", 100, 300, 300, 50);
bool isRunning = true;
SDL_Event ev;
while(isRunning)
{
Keystate = SDL_GetKeyboardState(NULL);
Player.Collision(Block1);
Player.Collision(Block2);
previousTime = currentTime;
currentTime = SDL_GetTicks();
delta = (currentTime - previousTime) / 1000.0f;
Player.Update(delta, Keystate);
while(SDL_PollEvent(&ev) != 0)
{
if(ev.type == SDL_QUIT)
isRunning = false;
}
SDL_RenderClear(renderTarget);
Player.Draw(renderTarget);
Block1.Draw(renderTarget);
Block2.Draw(renderTarget);
SDL_RenderPresent(renderTarget);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderTarget);
window = NULL;
renderTarget = NULL;
SDL_Quit();
return 0;
}
The problem with your code is that each call to Player.Collision overwrites the "falling" variable.
Player.Collision(Block1); //this call calculates a falling value
Player.Collision(Block2); //...then this call overwrites falling with a new value
So effectively your code is only testing if the player is colliding with Block2, so collisions with Block1 are ignored.
Currently your Collision function is:
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
Firstly, your "return false;" is not actually part of the else, as you don't have {}. In this particular case it makes no difference as the else is exited and then the return happens but your indentation would suggest you expect the "return false;" line to be executed as part of the else block so you should put:
else
{
falling = 1;
return false;
}
Next you want to say if you have already detected a collision (eg, with Block1) then don't set falling to 1, to do this add an if statement.
else
{
if(falling != 0) //if we haven't already detected a collision this frame
{
falling = 1;
}
return false;
}
You will however need to set falling back to 1 at the start of each frame, otherwise if a collision is detected on one frame then the player will never fall on subsequent frames, even if they are not colliding with a block.
As a side note, your Player.Update code modifies the player's y position if falling == 0, this seems counter intuitive as usually 0 is false and 1 is true, hence you seem to be saying if not falling then update y, where as it should be if falling update y. Personally I would use a bool rather than an int to hold the value of falling, and then say if(falling) update y, this would make your code clearer.
I want to do a little animation in my application. I have an asteroid and when he travel to the right the animation go to the right, when he go to the left animation go to the left,
the angle is between 0 and 360°.
I have add the tiles for you explain me how to cut it perfectly.
I have in the class an integer who have number bewteen 0 and 34 (asteroids on the image) I decrease -1 or add +1 to this variable at each animation.
The method that animates the asteroid:
void Asteroid::animation(){
int x = 1;
int y = 1;
int width = 5;
int height = 5;
// what should I add here?
if(this->angle >= 0 && this->angle < 180){
// cut image go to the right
setPixmap(this->skin.copy(x,y,width,height));
this->frame++;
if(frame > 34) this->frame = 1;
} else {
// cut image go to the left
setPixmap(this->skin.copy(x,y,width,height));
this->frame--;
if(frame < 1) this->frame = 34;
}
}
The contents of the skin pixmap:
Interface
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QPoint>
#include <QVector>
#include <QPixmap>
#include <QString>
#include <QTimer>
#include <QObject>
#include <time.h>
#include <QtCore/qmath.h>
#include "SettingsAsteroid.h"
class Asteroid : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
// Animation
QPixmap skin;
int frame; // 32 images
// Data
int speed;
int size;
int pv;
float angle;
public:
Asteroid(int size);
Asteroid(QPointF position, int size);
~Asteroid();
int getPosX();
int getPosY();
void setPosX(int newPos);
void setPosY(int newPos);
int getSpeed();
int getSize();
int getPV();
int getAngle();
// météorite détruite
void destroyed();
// toucher par un tir
void touched(int damage);
bool isDestroyed();
private slots:
// mouvement de la météorite
void move();
// animation de la météorite
void animation();
signals:
//void notKilled();
// transmet la taille du météorite détruit
void killed(int);
};
Implementation
#include "Asteroid.h"
Asteroid::Asteroid(int size)
{
this->skin = QPixmap(SettingsAsteroid::getRandomSkin());
this->speed = SettingsAsteroid::getRandomSpeed(4,8);
this->pv = SettingsAsteroid::getPV(size);
this->angle = SettingsAsteroid::getRandomAngle();
this->frame = 1;
// Position de départ random
QPointF position = QPointF(SettingsAsteroid::getRandomStartPosition());
this->setPos(position.x(), position.y());
this->size = size;
// mouvement de l'astéroide
QTimer* timer2 = new QTimer();
connect(timer2,SIGNAL(timeout()),this,SLOT(move()));
timer2->start(this->speed);
// animation de l'astéroide
QTimer* timer = new QTimer();
connect(timer,SIGNAL(timeout()),this,SLOT(animation()));
timer->start(100);
}
Asteroid::Asteroid(QPointF position, int size)
{
this->skin = QPixmap(SettingsAsteroid::getRandomSkin());
this->speed = SettingsAsteroid::getRandomSpeed(4,8);
this->pv = SettingsAsteroid::getPV(size);
this->angle = SettingsAsteroid::getRandomAngle();
this->frame = 1;
this->setPos(position.x(), position.y());
this->size = size;
QTimer* timer2 = new QTimer();
connect(timer2,SIGNAL(timeout()),this,SLOT(move()));
timer2->start(this->speed);
//Decoupe sprite et anmiation
QTimer* timer = new QTimer();
connect(timer,SIGNAL(timeout()),this,SLOT(animation()));
timer->start(150);
}
Asteroid::~Asteroid()
{
}
int Asteroid::getPosX(){
return this->pos().x();
}
int Asteroid::getPosY(){
return this->pos().y();
}
void Asteroid::setPosX(int newPos){
this->setPos(newPos, this->pos().y());
}
void Asteroid::setPosY(int newPos){
this->setPos(this->pos().x(), newPos);
}
int Asteroid::getSpeed(){
return this->speed;
}
int Asteroid::getSize(){
return this->size;
}
int Asteroid::getPV(){
return this->pv;
}
int Asteroid::getAngle(){
return this->angle;
}
bool Asteroid::isDestroyed(){
if(pv > 0) return false;
else return true;
}
void Asteroid::destroyed(){
// AVERTIR CLASSE PRINCIPALE QUE DETRUIT
}
void Asteroid::touched(int damage){
this->pv -= damage;
if(pv<=0) destroyed();
}
void Asteroid::move(){
double dx = getSpeed() * qCos(qDegreesToRadians(angle)) ;
double dy = getSpeed() * qSin(qDegreesToRadians(angle)) ;
setPos(QPointF(getPosX() + dx, getPosY() + dy)) ;
// place la météorite de l'autre coté de la scène
if (getPosX()<=0) setPosX(799);
else if (getPosY()<=0) setPosY(659);
else if (getPosX()>= 800) setPosX(1);
else if (getPosY()>= 600) setPosY(1);
}
void Asteroid::animation(){
// what add here?
int x = 1;
int y = 1;
int width = 5;
int height = 5;
if(this->angle >= 0 && this->angle < 180){
// cut image go to the right
setPixmap(this->skin.copy(x,y,width,height));
this->frame++;
if(frame > 34) this->frame = 1;
} else {
// cut image go to the left
setPixmap(this->skin.copy(x,y,width,height));
this->frame--;
if(frame < 1) this->frame = 34;
}
}
The angle is the direction of the Asteroid on the scene. There will be a spaceship who should destroyed the asteroid. I want make the animaton of the Asteroids who move on the scene
Assuming that the asteroid images in the skin are square, you can do as follows.
Your skin has only 32 items, not 34, BTW.
void Asteroid::animation() {
int step = skin.height();
int N = skin.width() / step; // Number of images in the skin.
Q_ASSERT(skin.width() % step == 0); // ensure proper format of the skin
if (angle >= 0 && angle < 180) {
frame ++;
if (frame > N) frame -= N;
} else {
frame --;
if (frame < 1) frame += N;
}
int x = (frame - 1) * step;
setPixmap(skin.copy(x, 0, step, step));
}