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

Author Topic: How to correctly respond to collision detection?  (Read 1336 times)

0 Members and 1 Guest are viewing this topic.

Mark Weyland

  • Guest
How to correctly respond to collision detection?
« on: December 20, 2014, 07:43:15 pm »
Hello :)
I'm developing a simple grid-based platformer. The only thing stopping me from advancing is finding the correct response to a collision detection. At this point I just don't know what to do. I've successfully managed to handle out-of-level-bounds event, but that is all I have achieved. I would be very thankful if You would help me to implement the rest of collision handling code. Here's what I've got (deleted parts you don't need):

src.cpp
Code: [Select]
#include <fstream>
#include <SFML/Graphics.hpp>
#include "global.hpp"
#include "init.hpp"
#include "physics.hpp"
#include "hero.hpp"
#include "events.hpp"
int main(void)
{
    createWindow();
    loadLevel();
    loadGraphics();

    cube.init();
    sf::RectangleShape temporary(sf::Vector2f(BLOCK, BLOCK));

    while(window.isOpen())
    {
        cube.move();
        adjustCamera();
        if(!handleEvents()) window.close();
        window.clear();

        window.draw(bgSprite);
        /// TEMPORARY AWFUL WAY OF DRAWING BLOCKS!
        for (int i = 0; i < 32; ++i)
            for (int j = 0; j < 32; ++j)
                if (level[j] == '1')
                {
                    temporary.setFillColor(sf::Color(0,255,0));
                    temporary.setPosition(j*32, i*32);
                    window.draw(temporary);
                }
        window.draw(cube.rectangle);
        window.display();
    }
    return 0;
}
global.hpp
Code: [Select]
#ifndef GLOBAL
#define GLOBAL
/// CONSTANTS
const std::string TITLE  = "Square Mario";
const         int WIDTH  = 300;
const         int HEIGHT = 300;
const         int FPS    =  30;
const         int BLOCK  =  32; // This number defines the size of a tile - it may be a block, player, enemy, NPC, etc...

/// GLOBAL VARIABLES
sf::RenderWindow window;
sf::Event        event;
sf::View         view;
unsigned int     levelX;
unsigned int     levelY;
char           **level;
sf::Keyboard     kboard;
sf::Texture      bgTexture;
sf::Sprite       bgSprite;
sf::Vector2f     velocity;
sf::Vector2i     position; // Points to the center of HERO
#endif
init.hpp
Code: [Select]
bool loadLevel(void)
{
    /// IMPLEMENT HANDLING OF TOO SMALL/LARGE LEVEL RESOLUTION
    int width, height;
    std::ifstream data("data.txt");
    if (!data.is_open())
    {
        errorMessage(2, true);
        return false;
    }
    /// IMPLEMENT HANDLING OF INCORRECT INPUT and EARLY EOF
    data >> width >> height;
    level = new char*[height];
    for (int i = 0; i < height; ++i)
    {
        level[i] = new char[width];
        for (int j = 0; j < width; ++j)
        {
            data >> level[i][j];
        }
    }
    levelX = width  * BLOCK;
    levelY = height * BLOCK;
    position.x = BLOCK/2;
    position.y = BLOCK/2;
    return true;
}
physics.hpp
Code: [Select]
#ifndef PHYSICS
#define PHYSICS

#define GRAVITY 0.3
#define INERTIA 1.9
#define FRICTION 1.4
#define X_LIMIT 1
#define Y_LIMIT 1
#define JMP_FORCE -5
bool on_ground = false;

void inertia(void)
{
    if (on_ground)
    {
        if(kboard.isKeyPressed(sf::Keyboard::Left )) velocity.x -= INERTIA;
        if(kboard.isKeyPressed(sf::Keyboard::Right)) velocity.x += INERTIA;
    }
    return;
}
void friction(void)
{
    if (on_ground)
    {
        if (velocity.x >  FRICTION) velocity.x -= FRICTION; else
        if (velocity.x < -FRICTION) velocity.x += FRICTION; else
        velocity.x = 0;
    }
}
void gravity(void)
{
    if (!on_ground)
    {
        velocity.y += GRAVITY;
    }
}
void wallCollision()
{
    if (position.x + velocity.x < BLOCK/2)
    {
        velocity.x = 0;
        position.x = BLOCK/2;
    } else
    if (position.x + velocity.x > levelX-BLOCK/2)
    {
        velocity.x = 0;
        position.x = levelX - BLOCK/2;
    }
    if (position.y + velocity.y > levelY-BLOCK/2)
    {
        velocity.y = 0;
        position.y = levelY - BLOCK/2;
        on_ground = true;
    } else
    if (position.y + velocity.y <BLOCK/2)
    {
        velocity.y = 0;
        position.y = BLOCK/2;
    }
}
void jump()
{
    if (kboard.isKeyPressed(sf::Keyboard::Up) && on_ground)
    {
        on_ground = false;
        velocity.y = JMP_FORCE;
    }
    return;
}
#endif
hero.hpp
Code: [Select]
#ifndef HERO
class hero
{
    public:
        sf::RectangleShape rectangle;
        void init()
        {
            rectangle.setPosition(position.x-BLOCK/2, position.y-BLOCK/2);
            rectangle.setSize(sf::Vector2f(BLOCK, BLOCK));
            rectangle.setFillColor(sf::Color(255,0,0));
            return;
        }
        void move()
        {
            inertia();
            friction();
            gravity();
            jump();
            wallCollision();
            position.x += velocity.x;
            position.y += velocity.y;
            rectangle.setPosition(position.x-BLOCK/2, position.y-BLOCK/2);
            return;
        }
};

hero cube;
#define HERO
#endif
events.hpp
Code: [Select]
#ifndef EVENTS
#define EVENTS
bool handleEvents(void)
{
    while (window.pollEvent(event))
    {
        switch(event.type)
        {
            case sf::Event::Closed:
                return false;
                break;
            case sf::Event::KeyPressed:
                if (event.key.code == sf::Keyboard::Escape) return false;
                if (event.key.code == sf::Keyboard::P)
                {
                    while (true)
                    {
                        window.waitEvent(event);
                        if (event.key.code == sf::Keyboard::P) break; else
                        if (event.key.code == sf::Keyboard::Escape || event.type == sf::Event::Closed) return false;
                    }
                }
                break;
            default:
                break;
        }
    }
    return true;
}
#endif

Here's the final thing I've tried to handle the collision detection for blocks:
Collision function that doesn't work (square paralysed):
Code: [Select]
void blockCollision()
{

    on_ground = false;
    bool collisionX = false;
    bool collisionY = false;
    sf::IntRect rect1(sf::Vector2i(position.x-BLOCK/2, position.y-BLOCK/2), sf::Vector2i(BLOCK, BLOCK));
    rect1.left += velocity.y; rect1.top += velocity.y;
    for (int i = 0; i < 32; ++i)
    {
        for (int j = 0; j < 32; ++j)
        {
            if(level[i][j] == '1')
            {
                sf::IntRect rect2(sf::Vector2i(j*BLOCK,i*BLOCK), sf::Vector2i(BLOCK,BLOCK));
                if (rect1.intersects(rect2))
                {
                    rect1.left -= velocity.x;
                    if (rect1.intersects(rect2)) collisionY = true;
                    rect1.left += velocity.x;
                    rect1.top  -= velocity.y;
                    if (rect1.intersects(rect2)) collisionX = true;
                    rect1.top  += velocity.y;

                    if (collisionY)
                    {
                        on_ground = true;
                        if (velocity.y > 0) position.y = rect2.top-BLOCK/2; else
                        if (velocity.y < 0) position.y = rect2.top+BLOCK*1.5;
                    }
                    if (collisionX)
                    {
                        if (velocity.x > 0) position.x = rect2.left-BLOCK/2; else
                        if (velocity.x < 0) position.x = rect2.left+BLOCK*1.5;
                    }
                }
            }
        }
    }
    if (collisionX) velocity.x = 0;
    if (collisionY) velocity.y = 0;
}

Could anyone help me? Please, I've spent two days stuck on this! I can handle one axis correctly, but when there are two square is either paralysed, unable to move, teleporting somewhere, floating in air, shivering or losing vertical velocity because of side impact!

lafoniz

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: How to correctly respond to collision detection?
« Reply #1 on: December 20, 2014, 11:47:25 pm »
You better show minimal code and some kind of sketch so we can see what kind of collision detection exactly you wanted to get. Showing every line of code is very convenient, but nobody won't get through it, too much work I think :) So, get your minimal code, sketch and I'm almost certain that somebody will help you.