Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - decoder

Pages: [1]
1
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
#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();
        }
}
 

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.

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.

                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.

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
 

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).

The code above uses independent frame rate
window.setFramerateLimit(60);
.....
sprite.move(offset.x * deltaTime.asMilliseconds(),
                  offset.y * deltaTime.asMilliseconds());
 

Reference: https://maksimdan.gitbooks.io/sfml-and-gamedevelopement/content/frame_rate.html

2
Graphics / Re: Move the view if the entity's out view.
« on: June 16, 2018, 04:48:19 am »
The horizontal movement is fine, but how could I do the same for vertical.

3
Graphics / Move the view if the entity's out view.
« on: June 11, 2018, 09:48:45 am »
How can I make the view follow the player entity when it's nearly out of the drone's (the view) view.
I have here my code for the drone's movement.

void World::update(const sf::Time& deltaTime)
{
        mSceneGraph.update(deltaTime);
        mDrone.setCenter(mPlayer->getPosition());
}
 

What I want to achieve is to make the drone follow the player, but not really following the player's new position as it moves real-time. Instead, the drone will SMOOTHLY MOVE if the player is NEARLY OUT OF VIEW (not hitting the view's boundary).

4
Graphics / Re: Sprite collision detection is not accurate
« on: June 05, 2018, 06:17:46 am »
I've played around and ended up with a nice solution, but I ain't feelin good about that coz I've always been thinking that I'd only done a hack just to get the desired behavior.

The code below says that the rect should clamp to the wall's bounds if any collision happened.

// Where...
// Rect A: Moving body
// Rect B: Static body
bool checkCollision(const sf::RectangleShape& rectA,
                            const sf::RectangleShape& rectB)
{
        return rectB.getGlobalBounds().intersects(rectA.getGlobalBounds());
}

......


                if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                        rect.move(0.f, -rectVel * deltaTime.asSeconds());
                        if (checkCollision(rect, wall))
                                rect.setPosition(rect.getPosition().x, wall.getPosition().y + wall.getSize().y);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                        rect.move(0.f, rectVel * deltaTime.asSeconds());
                        if (checkCollision(rect, wall))
                                rect.setPosition(rect.getPosition().x, wall.getPosition().y - rect.getSize().y);
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                        rect.move(-rectVel * deltaTime.asSeconds(), 0.f);
                        if (checkCollision(rect, wall))
                                rect.setPosition(wall.getPosition().x + wall.getSize().x, rect.getPosition().y);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                        rect.move(rectVel * deltaTime.asSeconds(), 0.f);
                        if (checkCollision(rect, wall))
                                rect.setPosition(wall.getPosition().x - rect.getSize().x, rect.getPosition().y);
                }

 

The multiple wall version
enum class Direction
{
        Up, Down, Left, Right
};

void clampBody(sf::RectangleShape& rectA,
                           const sf::RectangleShape& rectB,
                           Direction dir);

// Where...
// Rect A: Moving body
// Rect B: Static body
void checkCollision(sf::RectangleShape& rectA,
                                        const sf::RectangleShape& rectB,
                                        Direction dir)
{
        if (rectB.getGlobalBounds().intersects(rectA.getGlobalBounds()))
                clampBody(rectA, rectB, dir);
}

void checkCollision(sf::RectangleShape& rectA,
                                        const std::vector<sf::RectangleShape>& rects,
                                        Direction dir)
{
        for (const sf::RectangleShape& rect : rects)
                if (rect.getGlobalBounds().intersects(rectA.getGlobalBounds()))
                        clampBody(rectA, rect, dir);
}

// Also where...
// Rect A: Moving body
// Rect B: Static body
void clampBody(sf::RectangleShape& rectA,
                           const sf::RectangleShape& rectB,
                           Direction dir)
{
        switch (dir)
        {
                case Direction::Up:
                        // Snap to the bottom of rectB
                        rectA.setPosition(rectA.getPosition().x, rectB.getPosition().y + rectB.getSize().y);
                        break;

                case Direction::Down:
                        // Snap to the top of rectB
                        rectA.setPosition(rectA.getPosition().x, rectB.getPosition().y - rectA.getSize().y);
                        break;

                case Direction::Left:
                        // Snap to the right side of rectB
                        rectA.setPosition(rectB.getPosition().x + rectB.getSize().x, rectA.getPosition().y);
                        break;

                case Direction::Right:
                        // Snap to the left side if rectB
                        rectA.setPosition(rectB.getPosition().x - rectA.getSize().x, rectA.getPosition().y);
                        break;
        }
}

...............

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                        rect.move(0.f, -rectVel * deltaTime.asSeconds());
                        checkCollision(rect, walls, Direction::Up);
                }
               
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                        rect.move(0.f, rectVel * deltaTime.asSeconds());
                        checkCollision(rect, walls, Direction::Down);
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                        rect.move(-rectVel * deltaTime.asSeconds(), 0.f);
                        checkCollision(rect, walls, Direction::Left);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                        rect.move(rectVel * deltaTime.asSeconds(), 0.f);
                        checkCollision(rect, walls, Direction::Right);
                }
 

I think there might be a better solution than mine.

5
Graphics / Re: Sprite collision detection is not accurate
« on: June 05, 2018, 02:28:36 am »
There's no code that would put the boxes exactly next to each other. The code only guarantees that the distance will be between 0 and vx * deltaTime, but it can take any value in that range and will most likely never be 0. ;)

Can you suggest me some code because I'm only new to SFML.

6
Graphics / Rectangle collision detection is not accurate
« on: June 04, 2018, 04:10:30 pm »
The problem is the rect is not actually entirely hitting the wall. As you can see in the image, there's a little gap between them, and the gap's size is random.

int main()
{
        sf::RenderWindow window(sf::VideoMode(1920, 1080), "SFML Test");

        float rectVel = 200.f;
        sf::RectangleShape rect({ 50, 50 });
        sf::Vector2f rectOffset;
        rect.setFillColor(sf::Color::Red);
        rect.setPosition(static_cast<sf::Vector2f>(window.getSize()) / 2.f);

        sf::RectangleShape wall({ 20, 70 });
        wall.setFillColor(sf::Color::Blue);
        wall.setPosition(300.f, 200.f);

        sf::Clock timer;

        while (window.isOpen())
        {
                sf::Time deltaTime = timer.restart();

                sf::Event ev;
                while (window.pollEvent(ev))
                {
                        switch (ev.type)
                        {
                                case sf::Event::Closed:
                                        window.close();
                                        break;
                        }
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                        rect.move(0.f, -rectVel * deltaTime.asSeconds());
                        if (wall.getGlobalBounds().intersects(rect.getGlobalBounds()))
                                rect.move(0.f, rectVel * deltaTime.asSeconds());
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                        rect.move(0.f, rectVel * deltaTime.asSeconds());
                        if (wall.getGlobalBounds().intersects(rect.getGlobalBounds()))
                                rect.move(0.f, -rectVel * deltaTime.asSeconds());
                }

                if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                        rect.move(-rectVel * deltaTime.asSeconds(), 0.f);
                        if (wall.getGlobalBounds().intersects(rect.getGlobalBounds()))
                                rect.move(rectVel * deltaTime.asSeconds(), 0.f);
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                        rect.move(rectVel * deltaTime.asSeconds(), 0.f);
                        if (wall.getGlobalBounds().intersects(rect.getGlobalBounds()))
                                rect.move(-rectVel * deltaTime.asSeconds(), 0.f);
                }

                window.clear(sf::Color::White);
                window.draw(wall);
                window.draw(rect);

                window.display();
        }

        return 0;
}

7
Window / Re: Use setFrameLimit and setVerticalSyncEnabled together
« on: May 25, 2018, 11:14:04 am »
I want to add a setting to my game whether of not to turn on vertical sync, and I don't know if the frame limit set by the setFramLimit would be overriden if the vertical sync has turned on.

8
Window / Use setFrameLimit and setVerticalSyncEnabled together
« on: May 22, 2018, 06:01:06 am »
Can I use setFrameLimit and setVerticalSyncEnabled together after I'd created a window because I will be adding a vertical sync setting into my game, and I'm not pretty sure if setVerticalSyncEnabled will override the FPS that I've passed into the setFrameLimit.

Pages: [1]
anything