mirror of
https://github.com/HowestDAE/dae16-VerhulstBram.git
synced 2025-12-16 12:21:48 +01:00
Collision reworked into a Collision Namespace
Added basic player (Needs work)
This commit is contained in:
120
Engine/Collision.cpp
Normal file
120
Engine/Collision.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "Collision.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
namespace Collision
|
||||
{
|
||||
bool PointVsRect(const Point2f p, const Collision::CollisionRect& r) {
|
||||
return ( p.x >= r.pos.x && p.y >= r.pos.y && p.x < r.pos.x + r.size.x && p.y < r.pos.y + r.size.y );
|
||||
}
|
||||
|
||||
bool RectVsRect(const Collision::CollisionRect& r1, const Collision::CollisionRect r2) {
|
||||
return ( r1.pos.x < r2.pos.x + r2.size.x && r1.pos.x + r1.size.x > r2.pos.x && r1.pos.y < r2.pos.y + r2.size.y && r1.pos.y + r1.size.y > r2.pos.y );
|
||||
}
|
||||
|
||||
bool RayVsRect(const Point2f& rayOrigin, const Point2f& rayDirection, const Collision::CollisionRect target, Point2f& contactPoint, Point2f& contactNormal,
|
||||
float& t_HitNear) {
|
||||
contactNormal = Point2f { 0, 0 };
|
||||
contactPoint = Point2f { 0, 0 };
|
||||
|
||||
const Point2f inverseDirection = 1.0f / rayDirection;
|
||||
|
||||
// Calculate intersections with rectangle bounding axes
|
||||
Point2f t_Near = Point2f{ target.pos.x - rayOrigin.x, target.pos.y - rayOrigin.y } * inverseDirection;
|
||||
Point2f t_Far = Point2f{ target.pos.x + target.size.x - rayOrigin.x, target.pos.y + target.size.y - rayOrigin.y } * inverseDirection;
|
||||
|
||||
if (std::isnan(t_Far.y) || std::isnan(t_Far.x))
|
||||
return false;
|
||||
if (std::isnan(t_Near.y) || std::isnan(t_Near.x))
|
||||
return false;
|
||||
|
||||
// Sort distances
|
||||
if (t_Near.x > t_Far.x)
|
||||
std::swap(t_Near.x, t_Far.x);
|
||||
if (t_Near.y > t_Far.y)
|
||||
std::swap(t_Near.y, t_Far.y);
|
||||
|
||||
// Early rejection
|
||||
if (t_Near.x > t_Far.y || t_Near.y > t_Far.x)
|
||||
return false;
|
||||
|
||||
// Closest 'time' will be the first contact
|
||||
t_HitNear = std::max(t_Near.x, t_Near.y);
|
||||
|
||||
const float t_HitFar = std::min(t_Far.x, t_Far.y);
|
||||
|
||||
// Reject if ray direction is pointing away from object
|
||||
if (t_HitFar < 0)
|
||||
return false;
|
||||
|
||||
// Contact point of collision from parametric line equation
|
||||
contactPoint = rayOrigin + t_HitNear * rayDirection;
|
||||
|
||||
if (t_Near.x > t_Near.y) {
|
||||
if (inverseDirection.x < 0) {
|
||||
contactNormal = Point2f { 1, 0 };
|
||||
}
|
||||
else {
|
||||
contactNormal = Point2f { -1, 0 };
|
||||
}
|
||||
}
|
||||
else if (t_Near.x < t_Near.y) {
|
||||
if (inverseDirection.y < 0) {
|
||||
contactNormal = Point2f { 0, 1 };
|
||||
}
|
||||
else {
|
||||
contactNormal = Point2f { 0, -1 };
|
||||
}
|
||||
}
|
||||
// If t_Near == t_Far, collision is diagonal so pointless
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicRectVsRect(const Collision::CollisionRect& dynamicRectangle, float ElapsedTime, const Collision::CollisionRect& staticRectangle,
|
||||
Point2f& contactPoint, Point2f& contactNormal, float& contactTime) {
|
||||
// Check if dynamic rectangle is actually moving - we assume rectangles are NOT in collision to start
|
||||
if (dynamicRectangle.vel.x == 0 && dynamicRectangle.vel.y == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Expand target rectangle by source dimensions
|
||||
Collision::CollisionRect expandedTarget;
|
||||
expandedTarget.pos = Point2f{staticRectangle.pos.x - (dynamicRectangle.size / 2).x, staticRectangle.pos.y - (dynamicRectangle.size / 2).y};
|
||||
expandedTarget.size = staticRectangle.size + dynamicRectangle.size;
|
||||
|
||||
Point2f RayOrigin = dynamicRectangle.pos + dynamicRectangle.size / 2;
|
||||
|
||||
if (RayVsRect(RayOrigin, dynamicRectangle.vel * ElapsedTime, expandedTarget, contactPoint, contactNormal, contactTime)) {
|
||||
return ( contactTime >= 0.0f && contactTime < 1.0f );
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResolveDynamicRectVsRect(Collision::CollisionRect& dynamicRectangle, float ElapsedTime, Collision::CollisionRect* staticRectangle) {
|
||||
Point2f contactPoint, contactNormal;
|
||||
float contact_time = 0.0f;
|
||||
if (DynamicRectVsRect(dynamicRectangle, ElapsedTime, *staticRectangle, contactPoint, contactNormal, contact_time)) {
|
||||
if (contactNormal.y > 0) {
|
||||
dynamicRectangle.contact[0] = staticRectangle;
|
||||
}
|
||||
if (contactNormal.x < 0) {
|
||||
dynamicRectangle.contact[1] = staticRectangle;
|
||||
}
|
||||
if (contactNormal.y < 0) {
|
||||
dynamicRectangle.contact[2] = staticRectangle;
|
||||
}
|
||||
if (contactNormal.x > 0) {
|
||||
dynamicRectangle.contact[3] = staticRectangle;
|
||||
}
|
||||
|
||||
//dynamicRectangle.vel = dynamicRectangle.vel + contactNormal * Point2f(std::abs(dynamicRectangle.vel.x), std::abs(dynamicRectangle.vel.y)) * ( 1 - contact_time );
|
||||
dynamicRectangle.vel = dynamicRectangle.vel + contactNormal * -utils::DotProduct(dynamicRectangle.vel, contactNormal) * ( 1 - contact_time );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user