1
Graphics / Re: How to make the sprite move when pushed by another sprite
« on: June 16, 2018, 03:24:03 pm »
First of all, the coordinate system that most graphics libraries like SFML, SDL, etc. had been using is the Cartesian coordinates, where the origin (0, 0) sits at the top left corner of the rendering window. For example, if you were to draw an object and didn't specify its specific location, then its default location will be at the top left corner (unless you've specified its origin), and not at the center of the screen as you would expect. Refer to the attachment.
So here's the code overview
Here's the explanation:
Reference: https://en.sfml-dev.org/forums/index.php?topic=14350.0
Typically, there's a big difference
The code above uses independent frame rate
Reference: https://maksimdan.gitbooks.io/sfml-and-gamedevelopement/content/frame_rate.html
So here's the code overview
#include <SFML/Graphics.hpp>
enum class Direction
{
Up, Down, Left, Right, Static
};
bool checkCollision(const sf::FloatRect& rectA,
const sf::FloatRect& rectB)
{
return rectB.intersects(rectA);
}
void shiftSprite(sf::Sprite& sprite,
const sf::Vector2f& speed,
Direction dir,
const sf::Time& deltaTime)
{
sf::Vector2f offset;
switch (dir)
{
case Direction::Left:
offset.x = -speed.x;
break;
case Direction::Right:
offset.x = speed.x;
break;
case Direction::Up:
offset.y = -speed.y;
break;
case Direction::Down:
offset.y = speed.y;
break;
}
sprite.move(offset.x * deltaTime.asMilliseconds(),
offset.y * deltaTime.asMilliseconds());
}
void main()
{
sf::RenderWindow window;
window.create(sf::VideoMode(800, 600), "test", sf::Style::Default);
window.setFramerateLimit(60);
sf::Texture texture;
texture.loadFromFile("protagonist.png");
sf::Sprite sprite(texture);
sf::Sprite sprite2(texture);
sprite.setPosition(sf::Vector2f(0, 250));
sprite.setOrigin(sprite.getLocalBounds().width / 2,
sprite.getLocalBounds().height / 2);
sprite2.setOrigin(-200, -200);
sf::Vector2f speed(0.4f, 0.4f);
sf::Clock timer;
while (window.isOpen())
{
sf::Event event;
sf::Time deltaTime = timer.restart();
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
sf::Vector2f offset;
Direction dir = Direction::Static;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
offset.x = -speed.x;
dir = Direction::Left;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
offset.x = speed.x;
dir = Direction::Right;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
offset.y = -speed.y;
dir = Direction::Up;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
offset.y = speed.y;
dir = Direction::Down;
}
sprite.move(offset.x * deltaTime.asMilliseconds(),
offset.y * deltaTime.asMilliseconds());
if (checkCollision(sprite.getGlobalBounds(), sprite2.getGlobalBounds()))
shiftSprite(sprite2, speed, dir, deltaTime);
window.clear(sf::Color(255, 255, 255));
window.draw(sprite);
window.draw(sprite2);
window.display();
}
}
enum class Direction
{
Up, Down, Left, Right, Static
};
bool checkCollision(const sf::FloatRect& rectA,
const sf::FloatRect& rectB)
{
return rectB.intersects(rectA);
}
void shiftSprite(sf::Sprite& sprite,
const sf::Vector2f& speed,
Direction dir,
const sf::Time& deltaTime)
{
sf::Vector2f offset;
switch (dir)
{
case Direction::Left:
offset.x = -speed.x;
break;
case Direction::Right:
offset.x = speed.x;
break;
case Direction::Up:
offset.y = -speed.y;
break;
case Direction::Down:
offset.y = speed.y;
break;
}
sprite.move(offset.x * deltaTime.asMilliseconds(),
offset.y * deltaTime.asMilliseconds());
}
void main()
{
sf::RenderWindow window;
window.create(sf::VideoMode(800, 600), "test", sf::Style::Default);
window.setFramerateLimit(60);
sf::Texture texture;
texture.loadFromFile("protagonist.png");
sf::Sprite sprite(texture);
sf::Sprite sprite2(texture);
sprite.setPosition(sf::Vector2f(0, 250));
sprite.setOrigin(sprite.getLocalBounds().width / 2,
sprite.getLocalBounds().height / 2);
sprite2.setOrigin(-200, -200);
sf::Vector2f speed(0.4f, 0.4f);
sf::Clock timer;
while (window.isOpen())
{
sf::Event event;
sf::Time deltaTime = timer.restart();
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
sf::Vector2f offset;
Direction dir = Direction::Static;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
offset.x = -speed.x;
dir = Direction::Left;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
offset.x = speed.x;
dir = Direction::Right;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
offset.y = -speed.y;
dir = Direction::Up;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
offset.y = speed.y;
dir = Direction::Down;
}
sprite.move(offset.x * deltaTime.asMilliseconds(),
offset.y * deltaTime.asMilliseconds());
if (checkCollision(sprite.getGlobalBounds(), sprite2.getGlobalBounds()))
shiftSprite(sprite2, speed, dir, deltaTime);
window.clear(sf::Color(255, 255, 255));
window.draw(sprite);
window.draw(sprite2);
window.display();
}
}
Here's the explanation:
enum class Direction
{
Up, Down, Left, Right, Static
};
Basically, this specifies the sprites' directions. The "Static" just says that the object is at rest.{
Up, Down, Left, Right, Static
};
bool checkCollision(const sf::FloatRect& rectA, const sf::FloatRect& rectB);
This function checks if any collision between the two rectangles happens, where rectA is the collider, and rectB is the bounding box.void shiftSprite(sf::Sprite& sprite,
const sf::Vector2f& velocity,
Direction dir,
const sf::Time& deltaTime)
This function just basically moves the sprite. It takes the sprite object; the velocity (because it has a corresponding direction - the dir parameter); and the frame time or the delta time. The delta time makes your sprite to move smoothly real time.const sf::Vector2f& velocity,
Direction dir,
const sf::Time& deltaTime)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
offset.x = -speed.x;
dir = Direction::Left;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
offset.x = speed.x;
dir = Direction::Right;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
offset.y = -speed.y;
dir = Direction::Up;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
offset.y = speed.y;
dir = Direction::Down;
}
You can't do this piece of code inside the poll event loop because sf::Keyboard::isKeyPressed checks if any key is being pressed not had been pressed.{
offset.x = -speed.x;
dir = Direction::Left;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
offset.x = speed.x;
dir = Direction::Right;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
offset.y = -speed.y;
dir = Direction::Up;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
offset.y = speed.y;
dir = Direction::Down;
}
Reference: https://en.sfml-dev.org/forums/index.php?topic=14350.0
Typically, there's a big difference
if (sf::Keyboard::isKeyPressed(sf::Keyboard::isKeyPressed(KEY)))
// Checks if the key is being pressed
while (window.pollEvent(event))
if (event.type == sf::Event::KeyReleased &&
event.key.code == sf::Keyboard::KEY)
// Checks if the key has been pressed
// Checks if the key is being pressed
while (window.pollEvent(event))
if (event.type == sf::Event::KeyReleased &&
event.key.code == sf::Keyboard::KEY)
// Checks if the key has been pressed
sprite.move(offset.x * deltaTime.asMilliseconds(), offset.y * deltaTime.asMilliseconds());
if (checkCollision(sprite.getGlobalBounds(), sprite2.getGlobalBounds()))
shiftSprite(sprite2, speed, dir, deltaTime);
The code should not be interchanged as the checkCollision function checks the updated position of the sprite (collider).if (checkCollision(sprite.getGlobalBounds(), sprite2.getGlobalBounds()))
shiftSprite(sprite2, speed, dir, deltaTime);
The code above uses independent frame rate
window.setFramerateLimit(60);
.....
sprite.move(offset.x * deltaTime.asMilliseconds(),
offset.y * deltaTime.asMilliseconds());
.....
sprite.move(offset.x * deltaTime.asMilliseconds(),
offset.y * deltaTime.asMilliseconds());
Reference: https://maksimdan.gitbooks.io/sfml-and-gamedevelopement/content/frame_rate.html