Last active
April 15, 2016 21:29
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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