Skip to content

Instantly share code, notes, and snippets.

@awsumpwner27
Last active April 15, 2016 21:29
Show Gist options
  • Save awsumpwner27/37a34fcc093b4a6d0c3ee4546f447427 to your computer and use it in GitHub Desktop.
Save awsumpwner27/37a34fcc093b4a6d0c3ee4546f447427 to your computer and use it in GitHub Desktop.
Resolve the collision between a tilemap and a box as long as a tile and the box are both 64x64 units. Unnecessarily dependant on SFML.
void resolve_object_tile_collision(sf::Vector2f& tl_object_position, sf::Vector2f& tl_object_velocity, std::uint8_t* tile_data, std::uint32_t tiles_width, std::uint32_t tiles_height) {
//Using a method of AABB collision detection that handles the response between the tile it most intersects first.
std::vector<std::pair<float, sf::Vector2i>> tile_intersections; //Pairs consisting of the intersection area of a tile with its relative position
//Populate tile_intersections
sf::Vector2i prime_tile_pos( //Tile the object's top left corner rests within
int(std::floor(tl_object_position.x / 64.f)),
int(std::floor(tl_object_position.y / 64.f))
);
for (int8_t y = 0; y <= 1; ++y) {
for (int8_t x = 0; x <= 1; ++x) {
//Check if we'd remain in bounds
if (
x + prime_tile_pos.x >= 0 && x + prime_tile_pos.x < tiles_width &&
y + prime_tile_pos.y >= 0 && y + prime_tile_pos.y < tiles_height
) {
//Check if the tile is solid
if (1 == tile_data[x + prime_tile_pos.x + tiles_width * (y + prime_tile_pos.y)]) {
//Define vertices
sf::Vector2f v_objectTL(tl_object_position);
sf::Vector2f v_objectBR(tl_object_position + sf::Vector2f(64.f, 64.f));
sf::Vector2f v_tileTL(64.f * (x + prime_tile_pos.x + 0), 64.f * (y + prime_tile_pos.y + 0));
sf::Vector2f v_tileBR(64.f * (x + prime_tile_pos.x + 1), 64.f * (y + prime_tile_pos.y + 1));
//Calculate interesection area between these rectangles
float SI =
std::max(0.f, std::min(v_objectBR.x, v_tileBR.x) - std::max(v_objectTL.x, v_tileTL.x)) *
std::max(0.f, std::min(v_objectBR.y, v_tileBR.y) - std::max(v_objectTL.y, v_tileTL.y));
//Finally add these results into the vector paired with its relative position.
tile_intersections.push_back(std::pair<float, sf::Vector2i>(SI, sf::Vector2i(x, y)));
}
}
}
}
//Get that preferred tile.
if (!tile_intersections.empty()) { //But the array isn't empty, right?
sf::Vector2i pref_tile = (*std::max_element(tile_intersections.begin(), tile_intersections.end(),
[](std::pair<float, sf::Vector2i> &a, std::pair<float, sf::Vector2i> &b) {
return a.first < b.first;
}
)).second;
//Top left points of compared objects
sf::Vector2f objectTL(tl_object_position);
sf::Vector2f tileTL(64.f * sf::Vector2f(pref_tile + prime_tile_pos));
sf::Vector2f diff(tileTL - objectTL);
if (std::abs(diff.x) > std::abs(diff.y)) {
if (diff.x > 0) {
objectTL.x = tileTL.x - 64.f;
tl_object_position = objectTL;
tl_object_velocity.x = -0.667f * std::abs(tl_object_velocity.x);
}else
if (diff.x < 0) {
objectTL.x = tileTL.x + 64.f;
tl_object_position = objectTL;
tl_object_velocity.x = 0.667f * std::abs(tl_object_velocity.x);
}
}else
if (std::abs(diff.x) < std::abs(diff.y)) {
if (diff.y > 0) {
objectTL.y = tileTL.y - 64.f;
tl_object_position = objectTL;
tl_object_velocity.y = -0.5f * std::abs(tl_object_velocity.y);
}
else
if (diff.y < 0) {
objectTL.y = tileTL.y + 64.f;
tl_object_position = objectTL;
tl_object_velocity.y = 0.5f * std::abs(tl_object_velocity.y);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment