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 - arzaan789

Pages: [1]
1
I'm learning SFML and making a basic 2D medieval game. As you can see in the image, the enemy collides with me when I am facing the right direction and hence it attacks me, but when I face the left direction it does not collide and hence walks straight. How do I fix this? I need it to collide even if I am facing the left direction. I have even outputted on the console if there is a collision, but it only outputs a collision if the player faces right as a collision is only happening in that case for some reason.

main.cpp
#include<iostream>

#include<SFML\Graphics.hpp>

#include "Collision.hpp"
#include "Enemy.h"
#include "Player.h"

using namespace std;
int main() {

    sf::RenderWindow window(sf::VideoMode(1280, 720), "My title", sf::Style::Titlebar | sf::Style::Close);


    sf::Texture backgroundTexture;
    sf::RectangleShape Background;
    backgroundTexture.loadFromFile("2_game_background.png");
    backgroundTexture.setSmooth(true);

    Background.setSize(sf::Vector2f(1280.0f, 720.0f));
    Background.setOrigin(sf::Vector2f(0.0f, 0.0f));
    Background.setPosition(0, 0);
    Background.setTexture(&backgroundTexture);




    sf::Texture playerTexture;
    Collision::CreateTextureAndBitmask(playerTexture, "knight.png");
    playerTexture.setSmooth(true);

    Player player(&playerTexture, sf::Vector2u(10, 3),0.06f,170.0f);

    sf::Texture reaper2Texture;
    Collision::CreateTextureAndBitmask(reaper2Texture, "reaper2.png");
    reaper2Texture.setSmooth(true);

    Enemy enemy(&reaper2Texture, sf::Vector2u(11, 3), 0.06f, 100.0f);


    float deltaTime = 0.0f;
    sf::Clock clock;




    while (window.isOpen()) {

        deltaTime = clock.restart().asSeconds();

        sf::Event evnt;

        while (window.pollEvent(evnt)) {

            switch (evnt.type) {

            case sf::Event::Closed:
                window.close();
                break;
            }
        }




        if (Collision::PixelPerfectTest(player.body, enemy.body)) {

            enemy.UpdateAttack(deltaTime);
            player.UpdateMove(deltaTime, true, enemy.faceRight);
            cout << "collision" << endl;


        }
        else {
            enemy.UpdateMove(deltaTime);

            player.UpdateMove(deltaTime, false, enemy.faceRight);
            cout << "no collision" << endl;

        }







        window.clear();




        window.draw(Background);
        player.Draw(window);
        enemy.Draw(window);
        window.display();

    }





}

 

Animation.h
#pragma once
#include<SFML/Graphics.hpp>
class Animation
{
public:
    Animation(sf::Texture* texture,sf::Vector2u imageCount,float switchTime);

    sf::IntRect uvRect;
    void Update(int row, float deltaTime, bool faceRight);

    float switchTime;
private:
    sf::Vector2u imageCount;
    sf::Vector2u currentImage;

    float totalTime;


};
 

Collision.hpp(from official SFML website)
#ifndef COLLISION_H
#define COLLISION_H

namespace Collision {
    //////
    /// Test for a collision between two sprites by comparing the alpha values of overlapping pixels
    /// Supports scaling and rotation
    /// AlphaLimit: The threshold at which a pixel becomes "solid". If AlphaLimit is 127, a pixel with
    /// alpha value 128 will cause a collision and a pixel with alpha value 126 will not.
    ///
    /// This functions creates bitmasks of the textures of the two sprites by
    /// downloading the textures from the graphics card to memory -> SLOW!
    /// You can avoid this by using the "CreateTextureAndBitmask" function
    //////
    bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit = 0);

    //////
    /// Replaces Texture::loadFromFile
    /// Load an imagefile into the given texture and create a bitmask for it
    /// This is much faster than creating the bitmask for a texture on the first run of "PixelPerfectTest"
    ///
    /// The function returns false if the file could not be opened for some reason
    //////
    bool CreateTextureAndBitmask(sf::Texture& LoadInto, const std::string& Filename);

    //////
    /// Test for collision using circle collision dection
    /// Radius is averaged from the dimensions of the sprite so
    /// roughly circular objects will be much more accurate
    //////
    bool CircleTest(const sf::Sprite& Object1, const sf::Sprite& Object2);

    //////
    /// Test for bounding box collision using the Separating Axis Theorem
    /// Supports scaling and rotation
    //////
    bool BoundingBoxTest(const sf::Sprite& Object1, const sf::Sprite& Object2);
}

#endif  /* COLLISION_H */
 
Enemy.h

#pragma once
#include<SFML/Graphics.hpp>
#include "Animation.h"


class Enemy
{
public:
    Enemy(sf::Texture* texture, sf::Vector2u imageCount, float switchTime, float speed);
    void UpdateMove(float deltaTime);
    void UpdateAttack(float deltaTime);
    void Draw(sf::RenderWindow& window);
    bool faceRight;
    sf::Sprite body;
private:


    Animation animation;
    unsigned int row;
    float speed;


};
 
Player.h
#pragma once
#include<SFML/Graphics.hpp>
#include "Animation.h"

class Player
{
public:
    Player(sf::Texture* texture, sf::Vector2u imageCount, float switchTime,float speed);
    void UpdateMove(float deltaTime,bool collide,bool enemyFaceRight);
    void Draw(sf::RenderWindow& window);
    sf::Sprite body;

private:


    Animation animation;
    unsigned int row;
    float speed;
    bool faceRight;

};
 

Animation.cpp
#include "Animation.h"
Animation::Animation(sf::Texture* texture, sf::Vector2u imageCount, float switchTime) {
    this->imageCount = imageCount;
    this->switchTime = switchTime;
    totalTime = 0.0f;
    currentImage.x = 0;

    uvRect.width = texture->getSize().x / (float)imageCount.x;
    uvRect.height = texture->getSize().y / (float)imageCount.y;


}


void Animation::Update(int row, float deltaTime,bool faceRight) {

    currentImage.y = row;
    totalTime += deltaTime;

    if (totalTime >= switchTime) {
        totalTime -= switchTime;
        currentImage.x++;

        if (currentImage.x >= imageCount.x) {
            currentImage.x = 0;
        }

    }


    uvRect.top = currentImage.y * uvRect.height;

    if (faceRight) {
        uvRect.left = currentImage.x * abs(uvRect.width);
        uvRect.width = abs(uvRect.width);
    }
    else {
        uvRect.left = (currentImage.x + 1) * abs(uvRect.width);
        uvRect.width = -abs(uvRect.width);
    }
}
 
Collision.cpp(also from official SFML website)
#include <SFML/Graphics.hpp>
#include <map>
#include "Collision.hpp"

namespace Collision
{
    class BitmaskManager
    {
    public:
        ~BitmaskManager() {
            std::map<const sf::Texture*, sf::Uint8*>::const_iterator end = Bitmasks.end();
            for (std::map<const sf::Texture*, sf::Uint8*>::const_iterator iter = Bitmasks.begin(); iter != end; iter++)
                delete[] iter->second;
        }

        sf::Uint8 GetPixel(const sf::Uint8* mask, const sf::Texture* tex, unsigned int x, unsigned int y) {
            if (x > tex->getSize().x || y > tex->getSize().y)
                return 0;

            return mask[x + y * tex->getSize().x];
        }

        sf::Uint8* GetMask(const sf::Texture* tex) {
            sf::Uint8* mask;
            std::map<const sf::Texture*, sf::Uint8*>::iterator pair = Bitmasks.find(tex);
            if (pair == Bitmasks.end())
            {
                sf::Image img = tex->copyToImage();
                mask = CreateMask(tex, img);
            }
            else
                mask = pair->second;

            return mask;
        }

        sf::Uint8* CreateMask(const sf::Texture* tex, const sf::Image& img) {
            sf::Uint8* mask = new sf::Uint8[tex->getSize().y * tex->getSize().x];

            for (unsigned int y = 0; y < tex->getSize().y; y++)
            {
                for (unsigned int x = 0; x < tex->getSize().x; x++)
                    mask[x + y * tex->getSize().x] = img.getPixel(x, y).a;
            }

            Bitmasks.insert(std::pair<const sf::Texture*, sf::Uint8*>(tex, mask));

            return mask;
        }
    private:
        std::map<const sf::Texture*, sf::Uint8*> Bitmasks;
    };

    BitmaskManager Bitmasks;

    bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
        sf::FloatRect Intersection;
        if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
            sf::IntRect O1SubRect = Object1.getTextureRect();
            sf::IntRect O2SubRect = Object2.getTextureRect();

            sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
            sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());

            // Loop through our pixels
            for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
                for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {

                    sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
                    sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);

                    // Make sure pixels fall within the sprite's subrect
                    if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
                        o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
                        o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {

                        if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit&&
                            Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
                            return true;

                    }
                }
            }
        }
        return false;
    }

    bool CreateTextureAndBitmask(sf::Texture& LoadInto, const std::string& Filename)
    {
        sf::Image img;
        if (!img.loadFromFile(Filename))
            return false;
        if (!LoadInto.loadFromImage(img))
            return false;

        Bitmasks.CreateMask(&LoadInto, img);
        return true;
    }

    sf::Vector2f GetSpriteCenter(const sf::Sprite& Object)
    {
        sf::FloatRect AABB = Object.getGlobalBounds();
        return sf::Vector2f(AABB.left + AABB.width / 2.f, AABB.top + AABB.height / 2.f);
    }

    sf::Vector2f GetSpriteSize(const sf::Sprite& Object)
    {
        sf::IntRect OriginalSize = Object.getTextureRect();
        sf::Vector2f Scale = Object.getScale();
        return sf::Vector2f(OriginalSize.width * Scale.x, OriginalSize.height * Scale.y);
    }

    bool CircleTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {
        sf::Vector2f Obj1Size = GetSpriteSize(Object1);
        sf::Vector2f Obj2Size = GetSpriteSize(Object2);
        float Radius1 = (Obj1Size.x + Obj1Size.y) / 4;
        float Radius2 = (Obj2Size.x + Obj2Size.y) / 4;

        sf::Vector2f Distance = GetSpriteCenter(Object1) - GetSpriteCenter(Object2);

        return (Distance.x * Distance.x + Distance.y * Distance.y <= (Radius1 + Radius2) * (Radius1 + Radius2));
    }

    class OrientedBoundingBox // Used in the BoundingBoxTest
    {
    public:
        OrientedBoundingBox(const sf::Sprite& Object) // Calculate the four points of the OBB from a transformed (scaled, rotated...) sprite
        {
            sf::Transform trans = Object.getTransform();
            sf::IntRect local = Object.getTextureRect();
            Points[0] = trans.transformPoint(0.f, 0.f);
            Points[1] = trans.transformPoint(local.width, 0.f);
            Points[2] = trans.transformPoint(local.width, local.height);
            Points[3] = trans.transformPoint(0.f, local.height);
        }

        sf::Vector2f Points[4];

        void ProjectOntoAxis(const sf::Vector2f& Axis, float& Min, float& Max) // Project all four points of the OBB onto the given axis and return the dotproducts of the two outermost points
        {
            Min = (Points[0].x * Axis.x + Points[0].y * Axis.y);
            Max = Min;
            for (int j = 1; j < 4; j++)
            {
                float Projection = (Points[j].x * Axis.x + Points[j].y * Axis.y);

                if (Projection < Min)
                    Min = Projection;
                if (Projection > Max)
                    Max = Projection;
            }
        }
    };

    bool BoundingBoxTest(const sf::Sprite& Object1, const sf::Sprite& Object2) {
        OrientedBoundingBox OBB1(Object1);
        OrientedBoundingBox OBB2(Object2);

        // Create the four distinct axes that are perpendicular to the edges of the two rectangles
        sf::Vector2f Axes[4] = {
            sf::Vector2f(OBB1.Points[1].x - OBB1.Points[0].x,
                          OBB1.Points[1].y - OBB1.Points[0].y),
            sf::Vector2f(OBB1.Points[1].x - OBB1.Points[2].x,
                          OBB1.Points[1].y - OBB1.Points[2].y),
            sf::Vector2f(OBB2.Points[0].x - OBB2.Points[3].x,
                          OBB2.Points[0].y - OBB2.Points[3].y),
            sf::Vector2f(OBB2.Points[0].x - OBB2.Points[1].x,
                          OBB2.Points[0].y - OBB2.Points[1].y)
        };

        for (int i = 0; i < 4; i++) // For each axis...
        {
            float MinOBB1, MaxOBB1, MinOBB2, MaxOBB2;

            // ... project the points of both OBBs onto the axis ...
            OBB1.ProjectOntoAxis(Axes[i], MinOBB1, MaxOBB1);
            OBB2.ProjectOntoAxis(Axes[i], MinOBB2, MaxOBB2);

            // ... and check whether the outermost projected points of both OBBs overlap.
            // If this is not the case, the Separating Axis Theorem states that there can be no collision between the rectangles
            if (!((MinOBB2 <= MaxOBB1) && (MaxOBB2 >= MinOBB1)))
                return false;
        }
        return true;
    }
}
 
Enemy.cpp

#include "Enemy.h"
#include<SFML/Graphics.hpp>
#include<iostream>
using namespace std;

Enemy::Enemy(sf::Texture* texture, sf::Vector2u imageCount, float switchTime, float speed) :
    animation(texture, imageCount, switchTime) {

    this->speed = speed;
    row = 0;
    faceRight = true;

    body.setScale(sf::Vector2f(0.18f, 0.235f));
    body.setPosition(-20.0f, 479.0f);
    body.setTexture(*texture);





}

void Enemy::UpdateMove(float deltaTime) {

    sf::Vector2f movement(0.0f, 0.0f);

    //if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
    //  movement.x -= speed * deltaTime;
    //}
    //if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
    movement.x += speed * deltaTime;

    row = 2;
    if (movement.x > 0.0f) {
        faceRight = true;
    }
    else {
        faceRight = false;
    }


    animation.Update(row, deltaTime, faceRight);
    body.setTextureRect(animation.uvRect);

    body.move(movement);





}

void Enemy::UpdateAttack(float deltaTime)
{
    sf::Vector2f movement(0.0f, 0.0f);

    //if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
    //  movement.x -= speed * deltaTime;
    //}
    //if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
    //movement.x += speed * deltaTime;

    row = 1;
    //if (movement.x > 0.0f) {
    //  faceRight = true;
    //}
    //else {
    //  faceRight = false;
    //}


    animation.Update(row, deltaTime, faceRight);
    body.setTextureRect(animation.uvRect);

    //body.move(movement);
}

void Enemy::Draw(sf::RenderWindow& window) {

    window.draw(body);
}
 
Player.cpp
#include "Player.h"
#include<SFML/Graphics.hpp>
#include<iostream>
using namespace std;

Player::Player(sf::Texture* texture, sf::Vector2u imageCount, float switchTime, float speed) :
    animation(texture,imageCount,switchTime){

    this->speed = speed;
    row = 0;
    faceRight = true;

    body.setScale(sf::Vector2f(0.25f, 0.25f));
    body.setPosition(550.0f, 490.0f);
    body.setTexture(*texture);





}

void Player::UpdateMove(float deltaTime,bool collide, bool enemyFaceRight) {

    sf::Vector2f movement(0.0f, 0.0f);

    if (collide) {
        if (enemyFaceRight) {
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
                movement.x += speed * deltaTime;
            }
        }
        else {
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
                movement.x -= speed * deltaTime;
            }
        }

    }
    else {

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
            movement.x -= speed * deltaTime;
        }
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
            movement.x += speed * deltaTime;
        }

    }



    if (movement.x == 0) {
        row = 1;

    }
    else {
        row = 2;
        if (movement.x > 0.0f) {
            faceRight = true;
        }
        else {
            faceRight = false;
        }
    }
    if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) {
        row = 0;
    }
    animation.Update(row, deltaTime, faceRight);
    body.setTextureRect(animation.uvRect);
    if (!(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left))) {
        body.move(movement);
    }




}



void Player::Draw(sf::RenderWindow& window) {

    window.draw(body);
}
 

Pages: [1]