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:
Object(ObjectData data);
CollisionDir find_intersection(Object& entity);
// CollisionDir find_intersection(Object& entity);
float find_horizontal_difference_from_interesection(Object& entity);
float find_intersection(Object &entity);
sf::RectangleShape rect;
};
@@ -62,17 +63,17 @@ class Player : public Entity
void update_bounding_box();
int check_bounding_box(
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();
bool get_jumping();
void horizontal_no_out_of_bounds();
void vertical_no_out_of_bounds(Entity& base);
bool get_horizontal_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
bool get_vertical_top_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
bool get_vertical_bottom_collision(
std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
void vertical_no_out_of_bounds();
// bool get_horizontal_collision(
// std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
// bool get_vertical_top_collision(
// std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
// bool get_vertical_bottom_collision(
// std::array<std::array<std::unique_ptr<Object>, MAX_COLS>, MAX_ROWS>& tilemap);
private:
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.edge = -1.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;
return data;
}();
+203 -208
View File
@@ -3,11 +3,13 @@
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Rect.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Angle.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <cmath>
#include <iostream>
#include <memory>
#include <optional>
#include "data.hpp"
#include "globals.hpp"
@@ -20,6 +22,19 @@ namespace rv = ranges::views;
namespace rv = std::views;
#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)
{
rect.setSize(data.size);
@@ -53,140 +68,119 @@ Entity::get_velocity()
return _velocity;
}
CollisionDir
float
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;
}
std::optional<sf::FloatRect> intersection =
rect.getGlobalBounds().findIntersection(entity.rect.getGlobalBounds());
return intersection->size.x;
// return false;
}
float
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;
}
// 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;
// }
// }
const auto overlap = *inter;
// float
// 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
// }
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
}
/* Bounding Box
* Create on dash in front of player and check if the box collides with a wall,
* if so find the difference of the wall and the player and set the dash_distance
* to difference.
* */
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);
}
//
// void
// Player::initialize_bounding_box()
// {
// 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
// {
// bounding_box->rect.setSize({ length, rect.getSize().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;
// float max_dist = total_distance(player_data.max_dash_acceleration);
// float min_dist = max_dist;
//
// for (auto [i, j] : rv::cartesian_product(rv::iota(0, MAX_ROWS), rv::iota(0, MAX_COLS)))
// {
// if (tilemap[i][j] == nullptr) continue;
// float current_dist =
// bounding_box->find_horizontal_difference_from_interesection(*tilemap[i][j]);
//
// if (current_dist > 0 && current_dist < min_dist)
// {
// min_dist = current_dist;
// }
// }
// float final_dist = min_dist;
// if (direction == "left")
// {
// bounding_box->rect.setSize({ -final_dist, bounding_box->rect.getSize().y });
// }
// else
// {
// bounding_box->rect.setSize({ final_dist, bounding_box->rect.getSize().y });
// }
// max_dash_acceleration = distance_to_acceleration(final_dist);
// return final_dist;
// }
void
Player::initialize_bounding_box()
{
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)
Player::handle_movment(Timer& dash,
std::array<std::array<std::unique_ptr<Object>, 19>, 13>& tilemap)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))
{
@@ -198,15 +192,18 @@ Player::handle_movment(Timer& dash)
direction = "left";
rect.move({ -_velocity.x, 0 });
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && dash.get_time() <= 0)
{
// Dash order: spawn hitbox, check distance and set max_dash_acceleration
// Outside of this set max_dash_acceleration back to 15 { default }
max_dash_acceleration = player_data.max_dash_acceleration;
initialize_bounding_box();
_velocity.x = max_dash_acceleration;
dash.reset();
}
// if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && dash.get_time() <= 0)
// {
// // Dash order: spawn hitbox, check distance and set max_dash_acceleration
// // Outside of this set max_dash_acceleration back to 15 { default }
// max_dash_acceleration = player_data.max_dash_acceleration;
// initialize_bounding_box();
// update_bounding_box();
// 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)
{
m_jumping = true;
@@ -245,83 +242,81 @@ Player::horizontal_no_out_of_bounds()
}
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 -
base.rect.getOutlineThickness() - rect.getOutlineThickness();
if (rect.getPosition().y >= groundY)
if (rect.getPosition().y >= HEIGHT - 48)
{
rect.setPosition({ rect.getPosition().x, groundY });
rect.setPosition({ rect.getPosition().x, HEIGHT - 48 });
set_velocity_y(0);
m_jumping = false;
}
}
bool
Player::get_horizontal_collision(
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)))
{
if (tilemap[i][j] == nullptr) continue;
auto collision = tilemap[i][j]->find_intersection(*this);
if (collision == CollisionDir::None) continue;
if (collision == CollisionDir::Left)
{
rect.setPosition({ tilemap[i][j]->rect.getPosition().x - rect.getSize().x,
rect.getPosition().y });
return true;
}
if (collision == CollisionDir::Right)
{
rect.setPosition(
{ tilemap[i][j]->rect.getPosition().x + tilemap[i][j]->rect.getSize().x,
rect.getPosition().y });
return true;
}
}
return false;
}
bool
Player::get_vertical_top_collision(
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)))
{
if (tilemap[i][j] == nullptr) continue;
auto collision = find_intersection(*tilemap[i][j]);
if (collision == CollisionDir::None) continue;
if (collision == CollisionDir::Top)
{
rect.setPosition(
{ rect.getPosition().x, tilemap[i][j]->rect.getSize().y +
tilemap[i][j]->rect.getPosition().y });
set_velocity_y(0);
return true;
}
}
return false;
}
bool
Player::get_vertical_bottom_collision(
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)))
{
if (tilemap[i][j] == nullptr) continue;
auto collision = find_intersection(*tilemap[i][j]);
if (collision == CollisionDir::None) continue;
if (collision == CollisionDir::Bottom && get_velocity().y > 0)
{
rect.setPosition(
{ rect.getPosition().x,
tilemap[i][j]->rect.getPosition().y - rect.getSize().y });
m_jumping = false;
set_velocity_y(0);
return true;
}
}
return false;
}
// bool
// Player::get_horizontal_collision(
// 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)))
// {
// if (tilemap[i][j] == nullptr) continue;
// auto collision = tilemap[i][j]->find_intersection(*this);
// if (collision == CollisionDir::None) continue;
// if (collision == CollisionDir::Left)
// {
// rect.setPosition({ tilemap[i][j]->rect.getPosition().x - rect.getSize().x,
// rect.getPosition().y });
// return true;
// }
// if (collision == CollisionDir::Right)
// {
// rect.setPosition(
// { tilemap[i][j]->rect.getPosition().x + tilemap[i][j]->rect.getSize().x,
// rect.getPosition().y });
// return true;
// }
// }
// return false;
// }
//
// bool
// Player::get_vertical_top_collision(
// 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)))
// {
// if (tilemap[i][j] == nullptr) continue;
// auto collision = find_intersection(*tilemap[i][j]);
// if (collision == CollisionDir::None) continue;
// if (collision == CollisionDir::Top)
// {
// rect.setPosition(
// { rect.getPosition().x, tilemap[i][j]->rect.getSize().y +
// tilemap[i][j]->rect.getPosition().y });
// set_velocity_y(0);
// return true;
// }
// }
// return false;
// }
//
// bool
// Player::get_vertical_bottom_collision(
// 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)))
// {
// if (tilemap[i][j] == nullptr) continue;
// auto collision = find_intersection(*tilemap[i][j]);
// if (collision == CollisionDir::None) continue;
// if (collision == CollisionDir::Bottom && get_velocity().y > 0)
// {
// rect.setPosition(
// { rect.getPosition().x,
// tilemap[i][j]->rect.getPosition().y - rect.getSize().y });
// m_jumping = false;
// set_velocity_y(0);
// return true;
// }
// }
// return false;
// }
+25 -24
View File
@@ -32,10 +32,6 @@ std::string assets = "/home/andrew/personal/Projects/CPP/engine/assets/";
int
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;
Manager map_manager;
map_manager.load(level_data[BASE]);
@@ -93,34 +89,39 @@ main()
scheduler.timers.at(1).reset();
}
player.handle_movment(scheduler.timers.at(scheduler.pull("Dash")));
player.get_horizontal_collision(map_manager.tilemap);
player.handle_movment(scheduler.timers.at(scheduler.pull("Dash")), map_manager.tilemap);
// player.get_horizontal_collision(map_manager.tilemap);
player.handle_gravity();
std::cout << "Vel: " << player.get_velocity().x << ", " << player.get_velocity().y
<< "\n";
if (player.get_velocity().y > ((float)TILESIZE / 2 - GRAVITY))
{
player.set_velocity_y((TILESIZE / 2) - GRAVITY);
}
player.vertical_no_out_of_bounds();
// if (player.get_velocity().y > ((float)TILESIZE / 2 - GRAVITY))
// {
// player.set_velocity_y((TILESIZE / 2) - GRAVITY);
// }
if (!player.get_vertical_bottom_collision(map_manager.tilemap))
{
player.get_vertical_top_collision(map_manager.tilemap);
// if (!player.get_vertical_bottom_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);
window.draw(player.rect);
if (player.bounding_box != nullptr)
{
window.draw(player.bounding_box->rect);
}
window.draw(text);
// if (player.bounding_box != nullptr)
// {
// window.draw(player.bounding_box->rect);
// }
// window.draw(text);
window.display();
}