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

Author Topic: Incorrect object collision  (Read 1884 times)

0 Members and 2 Guests are viewing this topic.

EvgehaRYTP

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Incorrect object collision
« on: November 07, 2022, 04:21:27 pm »
Hello, I have a problem, bullet collision is not working correctly. The screenshot shows an example.
It's like the hitbox is lower than it should be.
How can it be corrected? Thanks
size bullet 8px, wall - 32.

bullet and wall collision code
void CheckMapBull(float Dx, float Dy) {
        for (int i = y / 32; i < (y + 8) / 32; i++)
            for (int j = x / 32; j < (x + 8) / 32; j++) {
                if (map[i][j] == '0') {
                    if (Dx > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dx < 0.0f) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                }
            }
    }
 


P.S. Sorry for my english, I'm using a translator.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Incorrect object collision
« Reply #1 on: November 07, 2022, 05:27:05 pm »
Hi :)

What are x and y?

What are you passing as Dx and Dy?

Are you checking a single point against each tile or the entire rectangle of the bullet?

Aside from the problem, your Dx/Dy checks could all be one. In fact, you're effectively checking to see if they "not exactly equal to 0". Again, I don't know what Dx and Dy actually represent and why being zero is important.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

EvgehaRYTP

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Incorrect object collision
« Reply #2 on: November 07, 2022, 06:10:01 pm »
Here is all the code that I sent above, it's in the class Bullet and Bullet2

Sorry for the bad code, I'm just starting to learn, I would like it to work as it should at first

#include <SFML/Graphics.hpp>
#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <string>

using namespace sf;

String map[20]
{
    "                              ",
    "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
    "E          000  000          E",
    "E            0000            E",
    "E   000     00  00     000   E",
    "E   000      0  0      000   E",
    "E   000      0000      000   E",
    "E   000                000   E",
    "E                            E",
    "E                            E",
    "E                            E",
    "E                            E",
    "E                            E",
    "E   000                000   E",
    "E   000                000   E",
    "E   000                000   E",
    "E   000                000   E",
    "E             0000           E",
    "E           000  000         E",
    "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
};


class Entity {
public:
    float x, y, dx, dy, speed;
    float w, h;
    int dir; bool life;
    std::string name;
    String FILE;
    Texture texture, texture2, texture3, texture4;
    Sprite sprite;

    Entity(Image& image, Image& image2, Image& image3, Image& image4, String Name, float X, float Y, float W, float H) {
        x = X; y = Y; w = W; h = H;
        name = Name;
        life = true;
        speed = 0;

        texture.loadFromImage(image);
        texture2.loadFromImage(image2);
        texture3.loadFromImage(image3);
        texture4.loadFromImage(image4);

        sprite.setTexture(texture);

        sprite.setOrigin(w / 2, h / 2);
    }

    FloatRect getRect() {
        return FloatRect(x, y, w, h);
    }

    virtual void update(float time) = 0;
};

class Player : public Entity {
public:
    enum {
        left, right, up, down, stay
    }state;
    bool isShoot;
    int hp = 10;
    Player(Image& image, Image& image2, Image& image3, Image& image4, String Name, float X, float Y, float W, float H) : Entity(image, image2, image3, image4, Name, X, Y, W, H) {
        isShoot = false;
        state = stay;
        if (name == "Player1") {
            sprite.setTexture(texture);
        }
    }

    void control() {
        if (Keyboard::isKeyPressed) {
            if (Keyboard::isKeyPressed(Keyboard::A)) {
                state = left; speed = 0.1;

                sprite.setTexture(texture2);
            }
            if (Keyboard::isKeyPressed(Keyboard::D)) {
                state = right; speed = 0.1;

                sprite.setTexture(texture3);
            }
            if (Keyboard::isKeyPressed(Keyboard::W)) {
                state = up; speed = 0.1;

                sprite.setTexture(texture4);
            }
            if (Keyboard::isKeyPressed(Keyboard::S)) {
                state = down; speed = 0.1;

                sprite.setTexture(texture);
            }
            if (Keyboard::isKeyPressed(Keyboard::Tab)) {
                isShoot = true;
            }
        }
    }

    void CheckMap(float Dx, float Dy) {
        for (int i = y / h; i < (y + h) / h; i++)
            for (int j = x / w; j < (x + w) / w; j++) {
                if (map[i][j] == '0' || (map[i][j] == 'E')) {
                    if (Dx > 0) {
                        x = j * w - w;
                    }
                    if (Dx < 0) {
                        x = j * w + w;
                    }
                    if (Dy > 0) {
                        y = i * h - h;
                    }
                    if (Dy < 0) {
                        y = i * h + h;
                    }
                }
            }
    }

    void update(float time) {
        control();

        switch (state) {
        case right: dx = speed; dy = 0;
            break;
        case left: dx = -speed; dy = 0;
            break;
        case up: dy = -speed; dx = 0;
            break;
        case down: dy = speed; dx = 0;
            break;
        case stay:
            break;
        }

        x += dx * time;
        y += dy * time;
        speed = 0;



        CheckMap(dx, 0);
        CheckMap(0, dy);

        // if (x <= 0) x = 1;
        // if (y <= 0) y = 1;

         //if (x >= 960) x = 928;
        // if (y >= 640) y = 618;

        sprite.setPosition(x + w / 2, y + h / 2);
    }
};

class Player2 : public Entity {
public:
    enum {
        left, right, up, down, stay
    }state;
    bool isShoot2;
    int hp = 10;
    Player2(Image& image, Image& image2, Image& image3, Image& image4, String Name, float X, float Y, float W, float H) : Entity(image, image2, image3, image4, Name, X, Y, W, H) {
        isShoot2 = false;
        state = stay;
        if (name == "Player2") {
            sprite.setTexture(texture);
        }
    }

    void control() {
        if (Keyboard::isKeyPressed) {
            if (Keyboard::isKeyPressed(Keyboard::Left)) {
                state = left; speed = 0.1;

                sprite.setTexture(texture2);
            }
            if (Keyboard::isKeyPressed(Keyboard::Right)) {
                state = right; speed = 0.1;

                sprite.setTexture(texture3);
            }
            if (Keyboard::isKeyPressed(Keyboard::Up)) {
                state = up; speed = 0.1;

                sprite.setTexture(texture4);
            }
            if (Keyboard::isKeyPressed(Keyboard::Down)) {
                state = down; speed = 0.1;

                sprite.setTexture(texture);
            }
            if (Keyboard::isKeyPressed(Keyboard::Space)) {
                isShoot2 = true;
            }
        }
    }

    void CheckMap(float Dx, float Dy) {
        for (int i = y / h; i < (y + h) / h; i++)
            for (int j = x / w; j < (x + w) / w; j++) {
                if (map[i][j] == '0' || map[i][j] == 'E') {
                    if (Dx > 0) {
                        x = j * w - w;
                    }
                    if (Dx < 0) {
                        x = j * w + w;
                    }
                    if (Dy > 0) {
                        y = i * h - h;
                    }
                    if (Dy < 0) {
                        y = i * h + h;
                    }
                }
            }
    }

    void update(float time) {
        control();

        switch (state) {
        case right: dx = speed; dy = 0;
            break;
        case left: dx = -speed; dy = 0;
            break;
        case up: dy = -speed; dx = 0;
            break;
        case down: dy = speed; dx = 0;
            break;
        case stay:
            break;
        }

        x += dx * time;
        y += dy * time;
        speed = 0;



        CheckMap(dx, 0);
        CheckMap(0, dy);

        if (x <= 0) x = 1;
        if (y <= 0) y = 1;

        //if (x >= 928) x = 928;
        //if (y >= 618) y = 618;

        sprite.setPosition(x + w / 2, y + h / 2);
    }
};

class Bullet : public Entity {
public:
    int direction;

    Bullet(Image& image, Image& image2, Image& image3, Image& image4, String Name, float X, float Y, int W, int H, int dir) : Entity(image, image2, image3, image4, Name, X, Y, W, H) {
        x = X; y = Y; w = h = 8;
        direction = dir;

        speed = 0.2;
        life = true;

        if (name == "Bullet") {
            sprite.setTexture(texture);
        }
    }

    void CheckMapBull(float Dx, float Dy) {
        for (int i = y / 32; i < (y + 8) / 32; i++)
            for (int j = x / 32; j < (x + 8) / 32; j++) {
                if (map[i][j] == '0') {
                    if (Dx > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dx < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                }
            }
    }

    void update(float time) {
        switch (direction) {
        case 0: dx = -speed; dy = 0;
            break;
        case 1: dx = speed; dy = 0;
            break;
        case 2: dy = -speed; dx = 0;
            break;
        case 3: dy = speed; dx = 0;
            break;
        }

        x += dx * time;
        y += dy * time;

        if (x <= 0) life = false;
        if (y <= 0) life = false;

        if (x >= 930) life = false;
        if (y >= 620) life = false;

        CheckMapBull(dx, 0); CheckMapBull(0, dy);

        sprite.setPosition(x + w + 8, y + h + 8);
    }
};

class Bullet2 : public Entity {
public:
    int direction;

    Bullet2(Image& image, Image& image2, Image& image3, Image& image4, String Name, float X, float Y, int W, int H, int dir) : Entity(image, image2, image3, image4, Name, X, Y, W, H) {
        x = X; y = Y; w = h = 8;
        direction = dir;

        speed = 0.2;
        life = true;

        if (name == "Bullet2") {
            sprite.setTexture(texture);
        }
    }

    void CheckMapBull(float Dx, float Dy) {
        for (int i = y / 32; i < (y + 8) / 32; i++)
            for (int j = x / 32; j < (x + 8) / 32; j++) {
                if (map[i][j] == '0') {
                    if (Dx > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dx < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                }
            }
    }

    void update(float time) {
        switch (direction) {
        case 0: dx = -speed; dy = 0;
            break;
        case 1: dx = speed; dy = 0;
            break;
        case 2: dy = -speed; dx = 0;
            break;
        case 3: dy = speed; dx = 0;
            break;
        }

        x += dx * time;
        y += dy * time;

        if (x <= 0) life = false;
        if (y <= 0) life = false;

        if (x >= 930) life = false;
        if (y >= 620) life = false;

        CheckMapBull(dx, 0); CheckMapBull(0, dy);

        sprite.setPosition(x + w + 8, y + h + 8);
    }
};

bool StartGame() {
    return true;
    RenderWindow window(sf::VideoMode(960, 640), "SFML works!");

    std::list<Entity*> entities;
    std::list<Entity*>::iterator it;

    std::list<Entity*> entities2;
    std::list<Entity*>::iterator it2;

    Font font;
    font.loadFromFile("res\\AuX_DotBitC_Xtra_Bold.ttf");

    Text text1("", font, 20); Text text2("", font, 20);
    //  text.setColor(Color::Blue);
    text1.setStyle(Text::Bold); text2.setStyle(Text::Bold);


    Texture kir;
    kir.loadFromFile("res\\kirpich.png");
    Sprite kirpich(kir);

    Image PulImage;
    PulImage.loadFromFile("res/pulya.png");

    Image hImage, hImage2, hImage3, hImage4, hImage5, hImage6, hImage7, hImage8;
    hImage.loadFromFile("res\\tank_blue.png");
    hImage2.loadFromFile("res\\tank_blueLEFT.png");
    hImage3.loadFromFile("res\\tank_blueRIGHT.png");
    hImage4.loadFromFile("res\\tank_blueUP.png");

    hImage5.loadFromFile("res\\tank_green.png");
    hImage6.loadFromFile("res\\tank_greenLEFT.png");
    hImage7.loadFromFile("res\\tank_greenRIGHT.png");
    hImage8.loadFromFile("res\\tank_greenUP.png");

    Player p1(hImage, hImage2, hImage3, hImage4, "Player1", 32, 64, 32, 32);

    Player2 p2(hImage5, hImage6, hImage7, hImage8, "Player2", 960 - 64, 640 - 64, 32, 32);

    Clock clock;
    double timer = 0, delay = 0.07;

    while (window.isOpen())
    {
        float time = (clock.getElapsedTime().asMicroseconds());
        clock.restart();
        time = time / 800;

        Event event;
        while (window.pollEvent(event))
        {
            if (event.type == Event::Closed)
                window.close();

            if (p1.isShoot == true) {
                p1.isShoot = false;
                entities.push_back(new Bullet(PulImage, PulImage, PulImage, PulImage, "Bullet", p1.x, p1.y, 8, 8, p1.state));
            }
            if (p2.isShoot2 == true) {
                p2.isShoot2 = false;
                entities2.push_back(new Bullet2(PulImage, PulImage, PulImage, PulImage, "Bullet2", p2.x, p2.y, 8, 8, p2.state));
            }
        }
        if (Keyboard::isKeyPressed(Keyboard::R) || p1.hp == 0 || p2.hp == 0) {
            return true;
        }
        window.clear(Color::Black);





        for (int i = 0.; i < 20; i++)
            for (int j = 0; j < 30; j++) {
                if (map[i][j] == '0') {
                    kirpich.setPosition(j * 32, i * 32);
                    window.draw(kirpich);
                }
                if (map[i][j] == 'E') {
                    kirpich.setPosition(j * 32, i * 32);
                    window.draw(kirpich);
                }
       


        for (it = entities.begin(); it != entities.end();)
        {
            Entity* b = *it;
            if (b->life == false) {
                it = entities.erase(it);
                delete b;
            }
            else it++;
        }

        for (it2 = entities2.begin(); it2 != entities2.end();)
        {
            Entity* b2 = *it2;
            if (b2->life == false) {
                it2 = entities2.erase(it2);
                delete b2;
            }
            else it2++;
        }

        for (it = entities.begin(); it != entities.end();) {
            Entity* b = *it;
            b->update(time);
            if ((*it)->getRect().intersects(p2.getRect())) {
                it = entities.erase(it);
                delete b;
                //std::cout << "YES" << '\n';
                p2.hp--;
                std::cout << "PlayerGreen HP: " << p2.hp << '\n';
            }
            else it++;

        }



        for (it2 = entities2.begin(); it2 != entities2.end();) {
            Entity* b2 = *it2;
            b2->update(time);
            if ((*it2)->getRect().intersects(p1.getRect())) {
                it2 = entities2.erase(it2);
                delete b2;
                //std::cout << "YES2" << '\n';
                p1.hp--;
                std::cout << "PlayerBlue HP: " << p1.hp << '\n';
            }
            else it2++;
        }

        for (it = entities.begin(); it != entities.end(); it++) {
            (*it)->update(time);
        }

        for (it2 = entities2.begin(); it2 != entities2.end(); it2++) {
            (*it2)->update(time);
        }

        p1.update(time);
        p2.update(time);

        for (it = entities.begin(); it != entities.end(); it++) {
            window.draw((*it)->sprite);
        }

        for (it2 = entities2.begin(); it2 != entities2.end(); it2++) {
            window.draw((*it2)->sprite);
        }

        window.draw(p1.sprite);
        window.draw(p2.sprite);

        std::ostringstream p1hp, p2hp;
        p1hp << p1.hp; p2hp << p2.hp;

        text1.setString("Blue HP: " + p1hp.str());
        text1.setPosition(0, 0);
        window.draw(text1);

        text2.setString("Green HP: " + p2hp.str());
        text2.setPosition(778, 0);
        window.draw(text2);

        window.display();
    }
}

void gameRunning() {
    if (StartGame()) {
        for (int i = 0; i < 20; i++)
            for (int j = 0; j < 30; j++) {
                map[2][11] = '0'; map[2][12] = '0'; map[2][13] = '0'; map[2][16] = '0'; map[2][17] = '0'; map[2][18] = '0';
                map[3][13] = '0'; map[3][14] = '0'; map[3][15] = '0'; map[3][16] = '0';

                map[4][12] = '0'; map[4][13] = '0'; map[4][16] = '0'; map[4][17] = '0'; map[5][16] = '0'; map[6][16] = '0';
                map[5][13] = '0'; map[6][13] = '0'; map[7][13] = '0'; map[7][14] = '0'; map[7][15] = '0'; map[7][16] = '0';

                map[4][4] = '0'; map[4][5] = '0'; map[4][6] = '0'; map[5][4] = '0'; map[5][5] = '0'; map[5][6] = '0'; map[6][4] = '0'; map[6][5] = '0'; map[6][6] = '0'; map[7][4] = '0'; map[7][5] = '0'; map[7][6] = '0';
                map[4][23] = '0'; map[4][24] = '0'; map[4][25] = '0'; map[5][23] = '0'; map[5][24] = '0'; map[5][25] = '0'; map[6][23] = '0'; map[6][24] = '0'; map[6][25] = '0'; map[7][23] = '0'; map[7][24] = '0'; map[7][25] = '0';

                map[13][4] = '0'; map[13][5] = '0'; map[13][6] = '0'; map[14][4] = '0'; map[14][5] = '0'; map[14][6] = '0'; map[15][4] = '0'; map[15][5] = '0'; map[15][6] = '0'; map[16][4] = '0'; map[16][5] = '0'; map[16][6] = '0';
                map[13][23] = '0'; map[13][24] = '0'; map[13][25] = '0'; map[14][23] = '0'; map[14][24] = '0'; map[14][25] = '0'; map[15][23] = '0'; map[15][24] = '0'; map[15][25] = '0'; map[16][23] = '0'; map[16][24] = '0'; map[16][25] = '0';
            }
       
        gameRunning();
    }
}

int main()
{
    gameRunning();
    return 0;
}
 

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Incorrect object collision
« Reply #3 on: November 07, 2022, 09:08:51 pm »
That's a lot of code and very few people will go through your entire code to find an error for you.

I must admit that it doesn't really easily answer my questions above unfortunately.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

EvgehaRYTP

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Incorrect object collision
« Reply #4 on: November 07, 2022, 09:49:07 pm »
Okay, I have a Bullet class.

class Bullet : public Entity {
public:
    int direction;

    Bullet(Image& image, Image& image2, Image& image3, Image& image4, String Name, float X, float Y, int W, int H, int dir) : Entity(image, image2, image3, image4, Name, X, Y, W, H) {
        x = X; y = Y; w = h = 8;
        direction = dir;

        speed = 0.2;
        life = true;

        if (name == "Bullet") {
            sprite.setTexture(texture);
        }
    }

    void CheckMapBull(float Dx, float Dy) {
        for (int i = y / 32; i < (y + 8) / 32; i++)
            for (int j = x / 32; j < (x + 8) / 32; j++) {
                if (map[i][j] == '0') {
                    if (Dx > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dx < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy > 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                    if (Dy < 0) {
                        map[i][j] = ' ';
                        life = false;
                    }
                }
            }
    }

    void update(float time) {
        switch (direction) {
        case 0: dx = -speed; dy = 0;
            break;
        case 1: dx = speed; dy = 0;
            break;
        case 2: dy = -speed; dx = 0;
            break;
        case 3: dy = speed; dx = 0;
            break;
        }

        x += dx * time;
        y += dy * time;  

        CheckMapBull(dx, 0); CheckMapBull(0, dy);

        sprite.setPosition(x + w + 8, y + h + 8);
    }
};
 
In function "CheckMapBull" I check for collision with an object (wall). Where is float Dx and  float Dy its a direction

The wall I display through the class sf::String in int main()

for (int i = 0; i < 20; i++)
            for (int j = 0; j < 30; j++) {
                if (map[i][j] == '0') {
                    kirpich.setPosition(j * 32, i * 32);
                    window.draw(kirpich);
                }
            }
 

And my problem is that the bullet (or the wall) doesn't have the right hit box.

In the screenshot, this shows how the bullet in the game itself flies through the walls, although it should destroy it.
If you shoot at the center of the wall it works fine.

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
Re: Incorrect object collision
« Reply #5 on: November 08, 2022, 01:42:39 am »
At a quick guess (without testing the code) it looks like the collision test is assuming the bullet has an origin of the top left corner, but the sprite has an origin of the centre, and the sprite is set to the position + double the width and height.

Try changing the loops to:
        for (int i = (y - 4) / 32; i < (y + 3) / 32; i++)
            for (int j = (x - 4) / 32; j < (x + 3) / 32; j++) {
and change the sprite positioning to:
sprite.setPosition(x, y);

EvgehaRYTP

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: Incorrect object collision
« Reply #6 on: November 08, 2022, 02:16:20 pm »
Unfortunately it didn't help.
sprite.setPosition(x+w+8, y+h+8);
This is so that the position of the bullet is in the middle on the tank

sprite.setPosition(x, y);
If you do this, the bullet will spawn in the upper right corner.

for (int i = (y - 4) / 32; i < (y + 3) / 32; i++)
            for (int j = (x - 4) / 32; j < (x + 3) / 32; j++) {
The result has not changed(

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Incorrect object collision
« Reply #7 on: November 08, 2022, 03:37:30 pm »
I can't tell for sure but it still looks to me like you're comparing a point of the bullet with an area (the tile) (or even just a point, not sure).
Remember, the bullet is a rectangle, the tile is a rectangle and you need to check if they are intersecting.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*