New collision detection

This commit is contained in:
zv0n 2021-03-13 15:05:16 +01:00
parent 258ce51cfe
commit d2cf54556e
12 changed files with 186 additions and 125 deletions

View File

@ -1,4 +1,5 @@
#include "sdlpp_circlecolider.hpp" #include "sdlpp_circlecolider.hpp"
#include "sdlpp_geometry.hpp"
namespace SDLPP { namespace SDLPP {
CircleColider::CircleColider( double x, double y, double rad ) CircleColider::CircleColider( double x, double y, double rad )
@ -9,39 +10,25 @@ CircleColider::CircleColider( const Vec2D< double > &center, double rad )
bool CircleColider::colidesWith( const SDLPP::CollisionPolygon &other ) const { bool CircleColider::colidesWith( const SDLPP::CollisionPolygon &other ) const {
if ( other.isCircle() ) { if ( other.isCircle() ) {
int otherRad = ( other.rightmost() - other.leftmost() ) / 2; /* check if distance of centers is lower than radiuses added together */
int otherRad =
dynamic_cast< const SDLPP::CircleColider & >( other ).getRadius();
int thisRad = getRadius(); int thisRad = getRadius();
int totalDist = otherRad + thisRad; int totalDist = otherRad + thisRad;
int xdiff = other.leftmost() + otherRad - ( leftmost() + thisRad ); int xdiff = other.getX() - getX();
int ydiff = other.topmost() + otherRad - ( topmost() + thisRad ); int ydiff = other.getY() - getY();
return ( xdiff * xdiff + ydiff * ydiff ) <= totalDist * totalDist; return ( xdiff * xdiff + ydiff * ydiff ) <= totalDist * totalDist;
} else if ( other.isInfinite() ) { } else if ( other.isInfinite() ) {
return infinityIntersection( other, *this ); return infinityIntersection( other, *this );
} }
int rad = rad_; /* other is not a circle */
int centerx = getX(); int rad = getRadius();
int centery = getY(); for ( auto &line : other.getLines() ) {
if ( other.topmost() <= centery && other.bottommost() >= centery ) { auto distance = pointLineDistance( position, line );
return other.leftmost() <= rightmost() && if ( distance * distance <= rad * rad )
other.rightmost() >= leftmost(); return true;
} else if ( other.leftmost() <= centerx && other.rightmost() >= centerx ) {
return other.topmost() <= bottommost() &&
other.bottommost() >= topmost();
} }
int pointx = 0, pointy = 0; return false;
if ( centerx > other.rightmost() ) {
pointx = other.rightmost();
} else {
pointx = other.leftmost();
}
if ( centery < other.topmost() ) {
pointy = other.topmost();
} else {
pointy = other.bottommost();
}
int distancesquared = ( pointx - centerx ) * ( pointx - centerx ) +
( pointy - centery ) * ( pointy - centery );
return distancesquared <= rad * rad;
} }
bool CircleColider::isCircle() const { bool CircleColider::isCircle() const {
@ -65,8 +52,8 @@ void CircleColider::updateCollision( int x, int y, int w, int h ) {
rad_ = original_rad * w; rad_ = original_rad * w;
} }
void CircleColider::render( Renderer &renderer, void CircleColider::render( Renderer &renderer, const SDL_Color &color,
const std::tuple< int, int, int, int > &color ) { const SDL_Color &outline_color ) {
std::vector< int > rect = { leftmost(), topmost(), rightmost(), std::vector< int > rect = { leftmost(), topmost(), rightmost(),
bottommost() }; bottommost() };
auto center_x = getX(); auto center_x = getX();
@ -76,14 +63,13 @@ void CircleColider::render( Renderer &renderer,
auto xdiff = center_x - i; auto xdiff = center_x - i;
auto xdist = xdiff * xdiff; auto xdist = xdiff * xdiff;
auto allowed_rad = sqrt( radsq - xdist ); auto allowed_rad = sqrt( radsq - xdist );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), SDL_SetRenderDrawColor( renderer.getRendererPtr(), color.r, color.g,
std::get< 0 >( color ), std::get< 1 >( color ), color.b, color.a );
std::get< 2 >( color ), 0x40 );
SDL_RenderDrawLine( renderer.getRendererPtr(), i, SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i, center_y + allowed_rad ); center_y - allowed_rad, i, center_y + allowed_rad );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), SDL_SetRenderDrawColor( renderer.getRendererPtr(), outline_color.r,
std::get< 0 >( color ), std::get< 1 >( color ), outline_color.g, outline_color.b,
std::get< 2 >( color ), 0x80 ); outline_color.a );
SDL_RenderDrawLine( renderer.getRendererPtr(), i, SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i, center_y - allowed_rad, i,
center_y - allowed_rad + 2 ); center_y - allowed_rad + 2 );
@ -91,39 +77,18 @@ void CircleColider::render( Renderer &renderer,
center_y + allowed_rad, i, center_y + allowed_rad, i,
center_y + allowed_rad - 2 ); center_y + allowed_rad - 2 );
} }
SDL_SetRenderDrawColor( renderer.getRendererPtr(), 0xFF, 0, 0, 0xFF );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
center_x + rad_, center_y );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y, center_x,
center_y + rad_ );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
center_x - rad_, center_y );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y, center_x,
center_y - rad_ );
} }
void CircleColider::render( Renderer &renderer, const SDL_Color &color ) {
auto input_color = color;
auto outline_color = color;
input_color.a = 0x40;
outline_color.a = 0x80;
render( renderer, input_color, outline_color );
}
void CircleColider::render( Renderer &renderer ) { void CircleColider::render( Renderer &renderer ) {
std::vector< int > rect = { leftmost(), topmost(), rightmost(), render( renderer, sdl_color, sdl_outline );
bottommost() };
auto center_x = getX();
auto center_y = getY();
auto radsq = rad_ * rad_;
for ( int i = rect[0]; i <= rect[2]; i++ ) {
auto xdiff = center_x - i;
auto xdist = xdiff * xdiff;
auto allowed_rad = sqrt( radsq - xdist );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_color.r,
sdl_color.g, sdl_color.b, sdl_color.a );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i, center_y + allowed_rad );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_outline.r,
sdl_outline.g, sdl_outline.b, sdl_outline.a );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i,
center_y - allowed_rad + 2 );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y + allowed_rad, i,
center_y + allowed_rad - 2 );
}
} }
int CircleColider::getRadius() const { int CircleColider::getRadius() const {
@ -133,4 +98,8 @@ int CircleColider::getRadius() const {
std::shared_ptr< CollisionPolygon > CircleColider::copySelf() { std::shared_ptr< CollisionPolygon > CircleColider::copySelf() {
return std::make_shared< CircleColider >( *this ); return std::make_shared< CircleColider >( *this );
} }
std::vector< Line< int > > CircleColider::getLines() const {
return {};
}
} // namespace SDLPP } // namespace SDLPP

View File

@ -21,11 +21,12 @@ public:
virtual int rightmost() const override; virtual int rightmost() const override;
virtual void updateCollision( int x, int y, int w, int h ) override; virtual void updateCollision( int x, int y, int w, int h ) override;
virtual void virtual void render( Renderer &renderer, const SDL_Color &color,
render( Renderer &renderer, const SDL_Color &outline_color ) override;
const std::tuple< int, int, int, int > &color ) override; virtual void render( Renderer &renderer, const SDL_Color &color ) override;
virtual void render( Renderer &renderer ) override; virtual void render( Renderer &renderer ) override;
virtual std::shared_ptr<CollisionPolygon> copySelf() override; virtual std::shared_ptr<CollisionPolygon> copySelf() override;
virtual std::vector<Line<int>> getLines() const override;
private: private:
int getRadius() const; int getRadius() const;

View File

@ -28,7 +28,7 @@ CircleRender::CircleRender( Vec2D< double > center, double rad,
CircleRender::CircleRender( Vec2D< double > center, double rad, CircleRender::CircleRender( Vec2D< double > center, double rad,
std::shared_ptr< Renderer > &r, std::shared_ptr< Renderer > &r,
std::shared_ptr< Texture > &t ) std::shared_ptr< Texture > &/*UNUSED*/ )
: CircleRender( center, rad, r ) { : CircleRender( center, rad, r ) {
throw "I don't support textures yet!!!"; throw "I don't support textures yet!!!";
} }

View File

@ -1,4 +1,5 @@
#include "sdlpp_collision.hpp" #include "sdlpp_collision.hpp"
#include "sdlpp_geometry.hpp"
namespace SDLPP { namespace SDLPP {
CollisionPolygon::CollisionPolygon( double x, double y ) CollisionPolygon::CollisionPolygon( double x, double y )
@ -53,8 +54,14 @@ bool infinityIntersection( const SDLPP::CollisionPolygon &infinite,
bool intersects( const SDLPP::CollisionPolygon &p1, bool intersects( const SDLPP::CollisionPolygon &p1,
const SDLPP::CollisionPolygon &p2 ) { const SDLPP::CollisionPolygon &p2 ) {
return !( if(p1.rightmost() < p2.leftmost() || p2.rightmost() < p1.leftmost() || p1.bottommost() < p2.topmost() || p2.bottommost() < p1.topmost())
p1.rightmost() < p2.leftmost() || p2.rightmost() < p1.leftmost() || return false;
p1.topmost() > p2.bottommost() || p2.topmost() > p1.bottommost() ); for(auto &line : p1.getLines()) {
for(auto &line2 : p2.getLines()) {
if(linesCross(line, line2))
return true;
}
}
return false;
} }
} // namespace SDLPP } // namespace SDLPP

View File

@ -4,7 +4,9 @@
#include "sdlpp_common.hpp" #include "sdlpp_common.hpp"
#include "sdlpp_renderer.hpp" #include "sdlpp_renderer.hpp"
#include "sdlpp_vector.hpp" #include "sdlpp_vector.hpp"
#include "sdlpp_line.hpp"
#include <memory> #include <memory>
#include <vector>
namespace SDLPP { namespace SDLPP {
class SDLPPSCOPE CollisionPolygon { class SDLPPSCOPE CollisionPolygon {
@ -21,14 +23,16 @@ public:
virtual int leftmost() const = 0; virtual int leftmost() const = 0;
virtual int rightmost() const = 0; virtual int rightmost() const = 0;
virtual void updateCollision( int x, int y, int w, int h ); virtual void updateCollision( int x, int y, int w, int h );
virtual void render( Renderer &renderer, virtual void render( Renderer &renderer, const SDL_Color &color,
const std::tuple< int, int, int, int > &color ) = 0; const SDL_Color &outline_color ) = 0;
virtual void render( Renderer &renderer, const SDL_Color &color ) = 0;
virtual void render( Renderer &renderer ) = 0; virtual void render( Renderer &renderer ) = 0;
int getX() const; int getX() const;
int getY() const; int getY() const;
void setColor( const std::string &color ); void setColor( const std::string &color );
void setOutlineColor( const std::string &color ); void setOutlineColor( const std::string &color );
virtual std::shared_ptr< CollisionPolygon > copySelf() = 0; virtual std::shared_ptr< CollisionPolygon > copySelf() = 0;
virtual std::vector< Line< int > > getLines() const = 0;
protected: protected:
Vec2D< double > original; Vec2D< double > original;

View File

@ -5,10 +5,12 @@
#include "sdlpp_vector.hpp" #include "sdlpp_vector.hpp"
#include "sdlpp_line.hpp" #include "sdlpp_line.hpp"
#include <algorithm> #include <algorithm>
#include <iostream>
namespace SDLPP { namespace SDLPP {
template < typename T > template < typename T >
Vec2D<T> pointProjectionOnLine( const Vec2D<T> &point, const Line<T> &line ) { Vec2D< T > pointProjectionOnLine( const Vec2D< T > &point,
const Line< T > &line ) {
/* from here - /* from here -
* https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment * https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
*/ */
@ -25,6 +27,45 @@ template<typename T>
double pointLineDistance( const Vec2D< T > &point, const Line< T > &line ) { double pointLineDistance( const Vec2D< T > &point, const Line< T > &line ) {
return vecDistance( point, pointProjectionOnLine( point, line ) ); return vecDistance( point, pointProjectionOnLine( point, line ) );
} }
template < typename T >
int _determinant( const Line< T > &line, const Vec2D< T > &point ) {
auto res = ( line.getEnd().getX() - line.getStart().getX() ) *
( point.getY() - line.getStart().getY() ) -
( line.getEnd().getY() - line.getStart().getY() ) *
( point.getX() - line.getStart().getX() );
if ( res < 0 )
return -1;
if ( res > 0 )
return 1;
return 0;
}
template < typename T >
bool linesCross( const Line< T > &a, const Line< T > &b ) {
auto det_a_s = _determinant( a, b.getStart() );
auto det_a_e = _determinant( a, b.getEnd() );
if ( det_a_s == det_a_e && det_a_s != 0 )
return false;
// det_a_s == det_a_e == 0, means that lines have the same vector,
// we need to find out if they overlap
if ( det_a_s == det_a_e ) {
if ( a.getStart().getX() == a.getEnd().getX() ) {
// vertical lines
return a.bottomost().getY() > b.topmost().getY() &&
a.topmost().getY() < b.bottomost().getY();
} else {
// horizontal lines
return a.leftmost().getX() < b.rightmost().getX() &&
a.rightmost().getX() > b.leftmost().getX();
}
}
auto det_b_s = _determinant( b, a.getStart() );
auto det_b_e = _determinant( b, a.getEnd() );
if ( det_b_s == det_b_e )
return false;
return true;
}
} // namespace SDLPP } // namespace SDLPP
#endif #endif

View File

@ -3,6 +3,7 @@
#include "sdlpp_common.hpp" #include "sdlpp_common.hpp"
#include "sdlpp_vector.hpp" #include "sdlpp_vector.hpp"
#include <iostream>
namespace SDLPP { namespace SDLPP {
template<typename T> template<typename T>
@ -11,14 +12,38 @@ public:
Line() = delete; Line() = delete;
~Line() = default; ~Line() = default;
Line( const Vec2D<T> &start, const Vec2D<T> &end ) Line( const Vec2D<T> &start, const Vec2D<T> &end )
: _start( start ), _end( end ) {} : _start( start ), _end( end ) {
updateMost();
}
Line( T x_1, T y_1, T x_2, T y_2 ) Line( T x_1, T y_1, T x_2, T y_2 )
: _start( { x_1, y_1 } ), _end( { x_2, y_2 } ) {} : Line( { x_1, y_1 }, { x_2, y_2 } ) {}
Line( const Vec2D<T> &start, const Vec2D<T> &end, bool infinite ) Line( const Vec2D<T> &start, const Vec2D<T> &end, bool infinite )
: _start( start ), _end( end ), _infinite( infinite ) {} : Line( start, end ), _infinite( infinite ) {}
Line( T x_1, T y_1, T x_2, T y_2, bool infinite ) Line( T x_1, T y_1, T x_2, T y_2, bool infinite )
: _start( { x_1, y_1 } ), _end( { x_2, y_2 } ), : Line( { x_1, y_1 }, { x_2, y_2 }, infinite ) {}
_infinite( infinite ) {} Line(const Line &input) : Line(input.getStart(), input.getEnd()) {}
Line &operator=(const Line &input) {
_start = input.getStart();
_end = input.getEnd();
updateMost();
return *this;
}
void updateMost() {
if(_start.getY() < _end.getY()) {
top = &_start;
bottom = &_end;
} else {
top = &_end;
bottom = &_start;
}
if(_start.getX() < _end.getX()) {
left = &_start;
right = &_end;
} else {
left = &_end;
right = &_start;
}
}
const Vec2D<T> &getStart() const { const Vec2D<T> &getStart() const {
return _start; return _start;
} }
@ -41,10 +66,26 @@ public:
_start += vec; _start += vec;
_end += vec; _end += vec;
} }
const Vec2D<T> &topmost() const {
return *top;
}
const Vec2D<T> &bottomost() const {
return *bottom;
}
const Vec2D<T> &leftmost() const {
return *left;
}
const Vec2D<T> &rightmost() const {
return *right;
}
private: private:
Vec2D<T> _start; Vec2D<T> _start;
Vec2D<T> _end; Vec2D<T> _end;
Vec2D<T> *top = nullptr;
Vec2D<T> *bottom = nullptr;
Vec2D<T> *left = nullptr;
Vec2D<T> *right = nullptr;
bool _infinite = false; bool _infinite = false;
}; };
} // namespace SDLPP } // namespace SDLPP

View File

@ -62,29 +62,27 @@ void RectColider::updateCollision( int x, int y, int w, int h ) {
_size_pixel = Vec2D< int >( width() * w, height() * h ); _size_pixel = Vec2D< int >( width() * w, height() * h );
} }
void RectColider::render( Renderer &renderer, void RectColider::render( Renderer &renderer, const SDL_Color &color,
const std::tuple< int, int, int, int > &color ) { const SDL_Color &outline_color ) {
auto rect = getRect(); auto rect = getRect();
// outline with desired color at 50% opacity SDL_SetRenderDrawColor( renderer.getRendererPtr(), color.r, color.g,
SDL_SetRenderDrawColor( renderer.getRendererPtr(), std::get< 0 >( color ), color.b, color.a );
std::get< 1 >( color ), std::get< 2 >( color ),
0x80 );
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
// fill with desired color at 25% opacity
SDL_SetRenderDrawColor( renderer.getRendererPtr(), std::get< 0 >( color ),
std::get< 1 >( color ), std::get< 2 >( color ),
0x40 );
SDL_RenderFillRect( renderer.getRendererPtr(), &rect ); SDL_RenderFillRect( renderer.getRendererPtr(), &rect );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), outline_color.r,
outline_color.g, outline_color.b, outline_color.a );
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
}
void RectColider::render( Renderer &renderer, const SDL_Color &color ) {
auto input_color = color;
auto outline_color = color;
input_color.a = 0x40;
outline_color.a = 0x80;
render( renderer, input_color, outline_color );
} }
void RectColider::render( Renderer &renderer ) { void RectColider::render( Renderer &renderer ) {
auto rect = getRect(); render( renderer, sdl_color, sdl_outline );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_color.r, sdl_color.g,
sdl_color.b, sdl_color.a );
SDL_RenderFillRect( renderer.getRendererPtr(), &rect );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_outline.r,
sdl_outline.g, sdl_outline.b, sdl_outline.a );
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
} }
SDL_Rect RectColider::getRect() { SDL_Rect RectColider::getRect() {
@ -111,14 +109,14 @@ std::shared_ptr< CollisionPolygon > RectColider::copySelf() {
return std::make_shared< RectColider >( *this ); return std::make_shared< RectColider >( *this );
} }
std::vector< Line< double > > RectColider::getLines() { std::vector< Line< int > > RectColider::getLines() const {
std::vector< Line< double > > ret{}; std::vector< Line< int > > ret{};
ret.emplace_back( original, original + Vec2D< double >( width(), 0 ) ); ret.emplace_back( position, position + Vec2D< int >( pixel_width(), 0 ) );
ret.emplace_back( original + Vec2D< double >( width(), 0 ), ret.emplace_back( position + Vec2D< int >( pixel_width(), 0 ),
original + _size ); position + _size_pixel );
ret.emplace_back( original, original + Vec2D< double >( 0, height() ) ); ret.emplace_back( position, position + Vec2D< int >( 0, pixel_height() ) );
ret.emplace_back( original + Vec2D< double >( 0, height() ), ret.emplace_back( position + Vec2D< int >( 0, pixel_height() ),
original + _size ); position + _size_pixel );
return ret; return ret;
} }

View File

@ -22,12 +22,12 @@ public:
virtual int leftmost() const override; virtual int leftmost() const override;
virtual int rightmost() const override; virtual int rightmost() const override;
virtual void updateCollision( int x, int y, int w, int h ) override; virtual void updateCollision( int x, int y, int w, int h ) override;
virtual void virtual void render( Renderer &renderer, const SDL_Color &color,
render( Renderer &renderer, const SDL_Color &outline_color ) override;
const std::tuple< int, int, int, int > &color ) override; virtual void render( Renderer &renderer, const SDL_Color &color ) override;
virtual void render( Renderer &renderer ) override; virtual void render( Renderer &renderer ) override;
virtual std::shared_ptr< CollisionPolygon > copySelf() override; virtual std::shared_ptr< CollisionPolygon > copySelf() override;
virtual std::vector<Line<double>> getLines(); virtual std::vector< Line< int > > getLines() const override;
private: private:
SDL_Rect getRect(); SDL_Rect getRect();

View File

@ -137,7 +137,7 @@ bool RenderObject::getKilled() {
return kill; return kill;
} }
void RenderObject::setColiderColor( const std::string &color ) { void RenderObject::setColiderColor( const std::string &color ) {
colider_color = getColorsHEX( color ); colider_color = getSDLColorHEX( color );
} }
void RenderObject::animate( int ticks ) { void RenderObject::animate( int ticks ) {

View File

@ -114,7 +114,7 @@ protected:
uint64_t id = -1; uint64_t id = -1;
bool hidden = false; bool hidden = false;
bool kill = false; bool kill = false;
std::tuple< int, int, int, int > colider_color = { 0x00, 0xFF, 0xFF, 0xFF }; SDL_Color colider_color = { 0x00, 0xFF, 0xFF, 0xFF };
uint64_t scene_id = -1; uint64_t scene_id = -1;
bool permanent = false; bool permanent = false;
bool is_static = true; bool is_static = true;

View File

@ -10,7 +10,7 @@ OUTPUTFLAG = -Fo
else else
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)
CXX ?= g++ CXX ?= g++
CXXFLAGS = -std=c++14 -Wall -Wextra -pedantic -O2 -DDEBUG -DFEATURE -g -fsanitize=address CXXFLAGS = -std=c++14 -Wall -Wextra -pedantic -O2 -DDEBUG -DFEATURE #-g -fsanitize=address
OBJEXT = o OBJEXT = o
LDFLAGS ?= -lSDL2 -lSDL2_image -lSDL2_gfx -lSDL2_ttf -pthread LDFLAGS ?= -lSDL2 -lSDL2_image -lSDL2_gfx -lSDL2_ttf -pthread
OUTPUTFLAG = -o OUTPUTFLAG = -o