Hello,
Over the past couple of days, I've been struggling with getting collision detection to work for my game, a 2D sidescrolling platformer, made with SFML 2. This is example code using my most recent method of collision detection, although it has some flaws:
// main.h
#ifndef MAIN_H
#define MAIN_H
#include <SFML/Graphics.hpp>
#include <iostream>
extern sf::RenderWindow mainWin;
extern sf::Sprite player;
extern sf::Sprite platform[3];
extern sf::Texture tPlayer, tPlatform1, tPlatform2;
extern sf::Clock frameClock;
extern sf::Vector2f velocity;
extern bool falling;
enum DIRECTION { NORTH, EAST, SOUTH, WEST, NONE };
void getInput();
void update();
DIRECTION collisionDetection(sf::FloatRect source, sf::FloatRect collide);
#endif // MAIN_H
// main.cpp
#include "main.h"
sf::RenderWindow mainWin(sf::VideoMode(800, 600, 32), "SFML CD Test");
sf::Sprite player;
sf::Sprite platform[3];
sf::Texture tPlayer, tPlatform1, tPlatform2;
sf::Clock frameClock;
sf::Vector2f velocity;
bool falling;
int main()
{
falling = true;
tPlayer.loadFromFile("box2.png");
tPlatform1.loadFromFile("box.png");
tPlatform2.loadFromFile("box3.png");
player.setTexture(tPlayer);
player.setColor(sf::Color::Blue);
for(int i = 0; i < 2; i++)
{
platform[i].setTexture(tPlatform1);
platform[i].setColor(sf::Color::Red);
}
platform[2].setTexture(tPlatform2);
platform[2].setColor(sf::Color::Yellow);
platform[0].setPosition(400, 400);
platform[1].setPosition(200, 300);
platform[2].setPosition(600, 375);
while(mainWin.isOpen())
{
sf::Event event;
while(mainWin.pollEvent(event))
{
if(event.type == sf::Event::Closed)
mainWin.close();
}
mainWin.clear();
getInput();
update();
mainWin.draw(player);
for(int i = 0; i < 3; i++)
mainWin.draw(platform[i]);
mainWin.display();
frameClock.restart();
}
}
void getInput()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
velocity.x = -500;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
velocity.x = 500;
if(!sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
velocity.x = 0;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && !falling)
{
velocity.y = -5000;
player.move(0, -5);
}
}
void update()
{
bool left, right, up, down;
left = right = up = down = false;
DIRECTION cdDir;
for(int i = 0; i < 3; i++)
{
cdDir = collisionDetection(player.getGlobalBounds(), platform[i].getGlobalBounds());
if(cdDir == NORTH)
up = true;
else if(cdDir == SOUTH)
down = true;
else if(cdDir == EAST)
right = true;
else if(cdDir == WEST)
left = true;
}
if(!down)
{
if(velocity.y < 200)
velocity.y += 25;
falling = true;
}
else
{
velocity.y = 0;
falling = false;
}
if(right)
player.move(-2, 0);
if(left)
player.move(2, 0);
float elapsedTime = frameClock.getElapsedTime().asSeconds();
player.move(velocity.x * elapsedTime, velocity.y * elapsedTime);
}
DIRECTION collisionDetection(sf::FloatRect source, sf::FloatRect collide)
{
if(!source.intersects(collide))
return NONE;
// return the side of source which collide hit
if(source.top < collide.top && collide.top < source.top + source.height &&
source.top + source.height < collide.top + collide.height)
{
return SOUTH;
}
else if(collide.top < source.top && source.top < collide.top + collide.height &&
collide.top + collide.height < source.top + source.height)
{
return NORTH;
}
if(source.left < collide.left && collide.left < source.left + source.width &&
source.left + source.width < collide.left + collide.width)
{
return EAST;
}
else if(collide.left < source.left && source.left < collide.left + collide.width &&
collide.left + collide.width < source.left + collide.width)
{
return WEST;
}
return NONE;
}
The issue with my method is that when there are 2 collisions (for example, LEFT and TOP), it can only return one. Thus, when the player sprite collides with the yellow platform (platform[2]), it usually doesn't detect the left or right collision, and you can "go inside" platform[2].
Excuse my greenness, but it appears to me that there must be some "simple" solution, or many platformers would run slow because of all the calculations collision detection must make each frame.
Thus, my question is, how do most platformers handle collision detection? Is there some "secret" to collision detection that I haven't grasped?
Thanks in advance.