remaking entire collsion system

This commit is contained in:
Andrew Haynes Macbook
2026-01-25 15:37:54 -05:00
parent a3589fd93d
commit 3159efb257
4 changed files with 240 additions and 243 deletions
+10 -9
View File
@@ -27,8 +27,9 @@ class Object
{ {
public: public:
Object(ObjectData data); Object(ObjectData data);
CollisionDir find_intersection(Object& entity); // CollisionDir find_intersection(Object& entity);
float find_horizontal_difference_from_interesection(Object& entity); float find_horizontal_difference_from_interesection(Object& entity);
float find_intersection(Object &entity);
sf::RectangleShape rect; sf::RectangleShape rect;
}; };
@@ -62,17 +63,17 @@ class Player : public Entity
void update_bounding_box(); void update_bounding_box();
int check_bounding_box( int check_bounding_box(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap); std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
void handle_movment(Timer& dash); void handle_movment(Timer& dash, std::array<std::array<std::unique_ptr<Object>, 19>, 13> &tilemap);
void handle_gravity(); void handle_gravity();
bool get_jumping(); bool get_jumping();
void horizontal_no_out_of_bounds(); void horizontal_no_out_of_bounds();
void vertical_no_out_of_bounds(Entity& base); void vertical_no_out_of_bounds();
bool get_horizontal_collision( // bool get_horizontal_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap); // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
bool get_vertical_top_collision( // bool get_vertical_top_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap); // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
bool get_vertical_bottom_collision( // bool get_vertical_bottom_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap); // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
private: private:
sf::Vector2f _min_velocity { 0, 0 }; sf::Vector2f _min_velocity { 0, 0 };
+1 -1
View File
@@ -47,7 +47,7 @@ PlayerData player_data = []
data.size = { TILESIZE / 2.0f, TILESIZE / 2.0f }; data.size = { TILESIZE / 2.0f, TILESIZE / 2.0f };
data.edge = -1.0f; data.edge = -1.0f;
data.velocity = { 3.0f, 0.0f }; data.velocity = { 3.0f, 0.0f };
data.max_dash_acceleration = 15.0f; // 15 data.max_dash_acceleration = 30.0f; // 15
data.max_vertical_acceleration = 12.5f; data.max_vertical_acceleration = 12.5f;
return data; return data;
}(); }();
+203 -208
View File
@@ -3,11 +3,13 @@
#include <SFML/Graphics/Color.hpp> #include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Rect.hpp> #include <SFML/Graphics/Rect.hpp>
#include <SFML/Graphics/RectangleShape.hpp> #include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Angle.hpp>
#include <SFML/System/Vector2.hpp> #include <SFML/System/Vector2.hpp>
#include <SFML/Window/Keyboard.hpp> #include <SFML/Window/Keyboard.hpp>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <optional>
#include "data.hpp" #include "data.hpp"
#include "globals.hpp" #include "globals.hpp"
@@ -20,6 +22,19 @@ namespace rv = ranges::views;
namespace rv = std::views; namespace rv = std::views;
#endif #endif
float
total_distance(int k)
{
if (k > 0) return k + total_distance(k - 1);
else return 0;
}
float
distance_to_acceleration(int target)
{
return roundf(-1 + sqrtf(1 + 8 * target) / 2);
}
Object::Object(ObjectData data) Object::Object(ObjectData data)
{ {
rect.setSize(data.size); rect.setSize(data.size);
@@ -53,140 +68,119 @@ Entity::get_velocity()
return _velocity; return _velocity;
} }
CollisionDir float
Object::find_intersection(Object& entity) Object::find_intersection(Object& entity)
{ {
sf::FloatRect a = rect.getGlobalBounds(); std::optional<sf::FloatRect> intersection =
sf::FloatRect b = entity.rect.getGlobalBounds(); rect.getGlobalBounds().findIntersection(entity.rect.getGlobalBounds());
auto inter = a.findIntersection(b); return intersection->size.x;
if (!inter) // return false;
{
return CollisionDir::None;
} }
const auto overlap = *inter; // CollisionDir
// Object::find_intersection(Object& entity)
// {
// sf::FloatRect a = rect.getGlobalBounds();
// sf::FloatRect b = entity.rect.getGlobalBounds();
// auto inter = a.findIntersection(b);
// if (!inter)
// {
// return CollisionDir::None;
// }
//
// const auto overlap = *inter;
//
// float overlapW = overlap.size.x;
// float overlapH = overlap.size.y;
//
// if (overlapW < overlapH)
// {
// // Horizontal collision
// return (a.position.x < b.position.x)
// ? CollisionDir::Right // a hit b from the left side
// : CollisionDir::Left; // a hit b from the right side
// }
// else
// {
// return (a.position.y < b.position.y) ? CollisionDir::Bottom : CollisionDir::Top;
// }
// }
float overlapW = overlap.size.x; // float
float overlapH = overlap.size.y; // Object::find_horizontal_difference_from_interesection(Object& entity)
// {
// sf::FloatRect a = rect.getGlobalBounds();
// sf::FloatRect b = entity.rect.getGlobalBounds();
// auto inter = a.findIntersection(b);
// if (!inter)
// {
// return 0;
// }
//
// const auto overlap = *inter;
//
// return (a.position.x < b.position.x)
// ? b.position.x - a.position.x // a hit b from the left side
// : a.position.x - b.position.x; // a hit b from the right side
// }
if (overlapW < overlapH) //
{ // void
// Horizontal collision // Player::initialize_bounding_box()
return (a.position.x < b.position.x) // {
? CollisionDir::Right // a hit b from the left side // bounding_box = std::make_unique<Object>(object_data[1]);
: CollisionDir::Left; // a hit b from the right side // float length = total_distance(max_dash_acceleration);
} // if (direction == "left")
else // {
{ // bounding_box->rect.setSize({ -length, rect.getSize().y });
return (a.position.y < b.position.y) ? CollisionDir::Bottom : CollisionDir::Top; // }
} // else
} // {
// bounding_box->rect.setSize({ length, rect.getSize().y });
float // }
Object::find_horizontal_difference_from_interesection(Object& entity) // }
{ //
sf::FloatRect a = rect.getGlobalBounds(); // void
sf::FloatRect b = entity.rect.getGlobalBounds(); // Player::update_bounding_box()
auto inter = a.findIntersection(b); // {
if (!inter) // bounding_box->rect.setPosition({ rect.getPosition().x, rect.getPosition().y });
{ // }
return 0; //
} // int
// Player::check_bounding_box(
const auto overlap = *inter; // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap)
// {
return (a.position.x < b.position.x) // int distance = 0;
? b.position.x - a.position.x // a hit b from the left side // float max_dist = total_distance(player_data.max_dash_acceleration);
: a.position.x - b.position.x; // a hit b from the right side // float min_dist = max_dist;
} //
// for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS)))
/* Bounding Box // {
* Create on dash in front of player and check if the box collides with a wall, // if (tilemap[i][j] == nullptr) continue;
* if so find the difference of the wall and the player and set the dash_distance // float current_dist =
* to difference. // bounding_box->find_horizontal_difference_from_interesection(*tilemap[i][j]);
* */ //
// if (current_dist > 0 && current_dist < min_dist)
float // {
total_distance(int k) // min_dist = current_dist;
{ // }
if (k > 0) return k + total_distance(k - 1); // }
else return 0; // float final_dist = min_dist;
} // if (direction == "left")
// {
float // bounding_box->rect.setSize({ -final_dist, bounding_box->rect.getSize().y });
distance_to_acceleration(int target) // }
{ // else
return roundf(-1 + sqrtf(1 + 8 * target) / 2); // {
} // bounding_box->rect.setSize({ final_dist, bounding_box->rect.getSize().y });
// }
// max_dash_acceleration = distance_to_acceleration(final_dist);
// return final_dist;
// }
void void
Player::initialize_bounding_box() Player::handle_movment(Timer& dash,
{ std::array<std::array<std::unique_ptr<Object>, 19>, 13>& tilemap)
bounding_box = std::make_unique<Object>(object_data[1]);
float length = total_distance(max_dash_acceleration);
if (direction == "left")
{
bounding_box->rect.setSize({ -length, rect.getSize().y });
}
else if (direction == "right")
{
bounding_box->rect.setSize({ length, rect.getSize().y });
}
bounding_box->rect.setPosition({ rect.getPosition().x, rect.getPosition().y });
}
void
Player::update_bounding_box()
{
bounding_box->rect.setPosition({ rect.getPosition().x, rect.getPosition().y });
}
int
Player::check_bounding_box(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap)
{
int distance = 0;
/*
* The box checks the wall farthest into the hitbox and not the closest one to the player
*
* Best idea is to just check if there is a collision and set hitbox to that size and then
* see if that checks the one closest to the player
*
* Make a way to find the shortest distance on the collsion becuase the wall closest to the
* player will ahve a shorter difference_from_interesection than a one further from it will
*
* */
for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS)))
{
if (tilemap[i][j] == nullptr) continue;
if (bounding_box->find_horizontal_difference_from_interesection(*tilemap[i][j]) > 0)
{
std::cout << "Intersection: "
<< bounding_box->find_horizontal_difference_from_interesection(
*tilemap[i][j])
<< "\n";
bounding_box->rect.setSize(
{ bounding_box->find_horizontal_difference_from_interesection(
*tilemap[i][j]),
bounding_box->rect.getSize().y });
distance = bounding_box->rect.getSize().x;
max_dash_acceleration = distance_to_acceleration(distance);
}
else if (bounding_box->find_horizontal_difference_from_interesection(
*tilemap[i][j]) <= 0 &&
bounding_box->rect.getSize().x <= total_distance(15))
{
bounding_box->rect.setSize(
{ bounding_box->rect.getSize().x + 1, bounding_box->rect.getSize().y });
max_dash_acceleration =
distance_to_acceleration(bounding_box->rect.getSize().x);
}
}
return distance;
}
void
Player::handle_movment(Timer& dash)
{ {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D)) if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))
{ {
@@ -198,15 +192,18 @@ Player::handle_movment(Timer& dash)
direction = "left"; direction = "left";
rect.move({ -_velocity.x, 0 }); rect.move({ -_velocity.x, 0 });
} }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && dash.get_time() <= 0) // if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && dash.get_time() <= 0)
{ // {
// Dash order: spawn hitbox, check distance and set max_dash_acceleration // // Dash order: spawn hitbox, check distance and set max_dash_acceleration
// Outside of this set max_dash_acceleration back to 15 { default } // // Outside of this set max_dash_acceleration back to 15 { default }
max_dash_acceleration = player_data.max_dash_acceleration; // max_dash_acceleration = player_data.max_dash_acceleration;
initialize_bounding_box(); // initialize_bounding_box();
_velocity.x = max_dash_acceleration; // update_bounding_box();
dash.reset(); // std::cout << check_bounding_box(tilemap) << "\n";
} // _velocity.x = max_dash_acceleration;
// // _velocity.x = 15;
// dash.reset();
// }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Space) && !m_jumping && _velocity.x <= 3) if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Space) && !m_jumping && _velocity.x <= 3)
{ {
m_jumping = true; m_jumping = true;
@@ -245,83 +242,81 @@ Player::horizontal_no_out_of_bounds()
} }
void void
Player::vertical_no_out_of_bounds(Entity& base) Player::vertical_no_out_of_bounds()
{ {
float groundY = base.rect.getPosition().y - base.rect.getSize().y - rect.getSize().y - if (rect.getPosition().y >= HEIGHT - 48)
base.rect.getOutlineThickness() - rect.getOutlineThickness();
if (rect.getPosition().y >= groundY)
{ {
rect.setPosition({ rect.getPosition().x, groundY }); rect.setPosition({ rect.getPosition().x, HEIGHT - 48 });
set_velocity_y(0); set_velocity_y(0);
m_jumping = false; m_jumping = false;
} }
} }
bool // bool
Player::get_horizontal_collision( // Player::get_horizontal_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap) // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap)
{ // {
for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) // for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS)))
{ // {
if (tilemap[i][j] == nullptr) continue; // if (tilemap[i][j] == nullptr) continue;
auto collision = tilemap[i][j]->find_intersection(*this); // auto collision = tilemap[i][j]->find_intersection(*this);
if (collision == CollisionDir::None) continue; // if (collision == CollisionDir::None) continue;
if (collision == CollisionDir::Left) // if (collision == CollisionDir::Left)
{ // {
rect.setPosition({ tilemap[i][j]->rect.getPosition().x - rect.getSize().x, // rect.setPosition({ tilemap[i][j]->rect.getPosition().x - rect.getSize().x,
rect.getPosition().y }); // rect.getPosition().y });
return true; // return true;
} // }
if (collision == CollisionDir::Right) // if (collision == CollisionDir::Right)
{ // {
rect.setPosition( // rect.setPosition(
{ tilemap[i][j]->rect.getPosition().x + tilemap[i][j]->rect.getSize().x, // { tilemap[i][j]->rect.getPosition().x + tilemap[i][j]->rect.getSize().x,
rect.getPosition().y }); // rect.getPosition().y });
return true; // return true;
} // }
} // }
return false; // return false;
} // }
//
bool // bool
Player::get_vertical_top_collision( // Player::get_vertical_top_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap) // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap)
{ // {
for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) // for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS)))
{ // {
if (tilemap[i][j] == nullptr) continue; // if (tilemap[i][j] == nullptr) continue;
auto collision = find_intersection(*tilemap[i][j]); // auto collision = find_intersection(*tilemap[i][j]);
if (collision == CollisionDir::None) continue; // if (collision == CollisionDir::None) continue;
if (collision == CollisionDir::Top) // if (collision == CollisionDir::Top)
{ // {
rect.setPosition( // rect.setPosition(
{ rect.getPosition().x, tilemap[i][j]->rect.getSize().y + // { rect.getPosition().x, tilemap[i][j]->rect.getSize().y +
tilemap[i][j]->rect.getPosition().y }); // tilemap[i][j]->rect.getPosition().y });
set_velocity_y(0); // set_velocity_y(0);
return true; // return true;
} // }
} // }
return false; // return false;
} // }
//
bool // bool
Player::get_vertical_bottom_collision( // Player::get_vertical_bottom_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap) // std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap)
{ // {
for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) // for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS)))
{ // {
if (tilemap[i][j] == nullptr) continue; // if (tilemap[i][j] == nullptr) continue;
auto collision = find_intersection(*tilemap[i][j]); // auto collision = find_intersection(*tilemap[i][j]);
if (collision == CollisionDir::None) continue; // if (collision == CollisionDir::None) continue;
if (collision == CollisionDir::Bottom && get_velocity().y > 0) // if (collision == CollisionDir::Bottom && get_velocity().y > 0)
{ // {
rect.setPosition( // rect.setPosition(
{ rect.getPosition().x, // { rect.getPosition().x,
tilemap[i][j]->rect.getPosition().y - rect.getSize().y }); // tilemap[i][j]->rect.getPosition().y - rect.getSize().y });
m_jumping = false; // m_jumping = false;
set_velocity_y(0); // set_velocity_y(0);
return true; // return true;
} // }
} // }
return false; // return false;
} // }
+25 -24
View File
@@ -32,10 +32,6 @@ std::string assets = "/home/andrew/personal/Projects/CPP/engine/assets/";
int int
main() main()
{ {
// float dist = total_distance(12);
// std::cout << "Distance: " << dist << "\n";
// float acc = distance_to_acceleration(total_distance(12));
// std::cout << "Distance: " << acc << "\n";
Scheduler scheduler; Scheduler scheduler;
Manager map_manager; Manager map_manager;
map_manager.load(level_data[BASE]); map_manager.load(level_data[BASE]);
@@ -93,34 +89,39 @@ main()
scheduler.timers.at(1).reset(); scheduler.timers.at(1).reset();
} }
player.handle_movment(scheduler.timers.at(scheduler.pull("Dash"))); player.handle_movment(scheduler.timers.at(scheduler.pull("Dash")), map_manager.tilemap);
player.get_horizontal_collision(map_manager.tilemap); // player.get_horizontal_collision(map_manager.tilemap);
player.handle_gravity(); player.handle_gravity();
std::cout << "Vel: " << player.get_velocity().x << ", " << player.get_velocity().y player.vertical_no_out_of_bounds();
<< "\n"; // if (player.get_velocity().y > ((float)TILESIZE / 2 - GRAVITY))
if (player.get_velocity().y > ((float)TILESIZE / 2 - GRAVITY)) // {
{ // player.set_velocity_y((TILESIZE / 2) - GRAVITY);
player.set_velocity_y((TILESIZE / 2) - GRAVITY); // }
}
if (!player.get_vertical_bottom_collision(map_manager.tilemap)) // if (!player.get_vertical_bottom_collision(map_manager.tilemap))
{ // {
player.get_vertical_top_collision(map_manager.tilemap); // player.get_vertical_top_collision(map_manager.tilemap);
// }
// if (player.bounding_box != nullptr)
// {
// player.update_bounding_box();
// // player.check_bounding_box(map_manager.tilemap);
// }
for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS))) {
if(map_manager.tilemap[i][j]) {
std::cout << player.find_intersection(*map_manager.tilemap[i][j]);
window.close();
} }
if (player.bounding_box != nullptr)
{
player.update_bounding_box();
player.check_bounding_box(map_manager.tilemap);
} }
map_manager.draw(window); map_manager.draw(window);
window.draw(player.rect); window.draw(player.rect);
if (player.bounding_box != nullptr) // if (player.bounding_box != nullptr)
{ // {
window.draw(player.bounding_box->rect); // window.draw(player.bounding_box->rect);
} // }
window.draw(text); // window.draw(text);
window.display(); window.display();
} }