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#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
#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.hppbool 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#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#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#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):
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!