diff --git a/sdlpp/sdlpp_circlecolider.cpp b/sdlpp/sdlpp_circlecolider.cpp index 078ff2a..9355163 100644 --- a/sdlpp/sdlpp_circlecolider.cpp +++ b/sdlpp/sdlpp_circlecolider.cpp @@ -1,47 +1,34 @@ #include "sdlpp_circlecolider.hpp" +#include "sdlpp_geometry.hpp" namespace SDLPP { CircleColider::CircleColider( double x, double y, double rad ) - : CircleColider( {x, y}, rad ) {}; + : CircleColider( { x, y }, rad ){}; CircleColider::CircleColider( const Vec2D< double > ¢er, double rad ) : CollisionPolygon( center ), original_rad( rad ) {} bool CircleColider::colidesWith( const SDLPP::CollisionPolygon &other ) const { 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 totalDist = otherRad + thisRad; - int xdiff = other.leftmost() + otherRad - ( leftmost() + thisRad ); - int ydiff = other.topmost() + otherRad - ( topmost() + thisRad ); + int xdiff = other.getX() - getX(); + int ydiff = other.getY() - getY(); return ( xdiff * xdiff + ydiff * ydiff ) <= totalDist * totalDist; } else if ( other.isInfinite() ) { return infinityIntersection( other, *this ); } - int rad = rad_; - int centerx = getX(); - int centery = getY(); - if ( other.topmost() <= centery && other.bottommost() >= centery ) { - return other.leftmost() <= rightmost() && - other.rightmost() >= leftmost(); - } else if ( other.leftmost() <= centerx && other.rightmost() >= centerx ) { - return other.topmost() <= bottommost() && - other.bottommost() >= topmost(); + /* other is not a circle */ + int rad = getRadius(); + for ( auto &line : other.getLines() ) { + auto distance = pointLineDistance( position, line ); + if ( distance * distance <= rad * rad ) + return true; } - int pointx = 0, pointy = 0; - 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; + return false; } bool CircleColider::isCircle() const { @@ -61,12 +48,12 @@ int CircleColider::rightmost() const { } void CircleColider::updateCollision( int x, int y, int w, int h ) { - position = Vec2D ( original.getX() * w + x, original.getY() * h + y ); + position = Vec2D< int >( original.getX() * w + x, original.getY() * h + y ); rad_ = original_rad * w; } -void CircleColider::render( Renderer &renderer, - const std::tuple< int, int, int, int > &color ) { +void CircleColider::render( Renderer &renderer, const SDL_Color &color, + const SDL_Color &outline_color ) { std::vector< int > rect = { leftmost(), topmost(), rightmost(), bottommost() }; auto center_x = getX(); @@ -76,14 +63,13 @@ void CircleColider::render( Renderer &renderer, auto xdiff = center_x - i; auto xdist = xdiff * xdiff; auto allowed_rad = sqrt( radsq - xdist ); - SDL_SetRenderDrawColor( renderer.getRendererPtr(), - std::get< 0 >( color ), std::get< 1 >( color ), - std::get< 2 >( color ), 0x40 ); + SDL_SetRenderDrawColor( renderer.getRendererPtr(), color.r, color.g, + color.b, color.a ); SDL_RenderDrawLine( renderer.getRendererPtr(), i, center_y - allowed_rad, i, center_y + allowed_rad ); - SDL_SetRenderDrawColor( renderer.getRendererPtr(), - std::get< 0 >( color ), std::get< 1 >( color ), - std::get< 2 >( color ), 0x80 ); + SDL_SetRenderDrawColor( renderer.getRendererPtr(), outline_color.r, + outline_color.g, outline_color.b, + outline_color.a ); SDL_RenderDrawLine( renderer.getRendererPtr(), i, center_y - allowed_rad, i, center_y - allowed_rad + 2 ); @@ -91,39 +77,18 @@ void CircleColider::render( Renderer &renderer, center_y + allowed_rad, i, 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 ) { - std::vector< int > rect = { leftmost(), topmost(), rightmost(), - 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 ); - } + render( renderer, sdl_color, sdl_outline ); } int CircleColider::getRadius() const { @@ -133,4 +98,8 @@ int CircleColider::getRadius() const { std::shared_ptr< CollisionPolygon > CircleColider::copySelf() { return std::make_shared< CircleColider >( *this ); } + +std::vector< Line< int > > CircleColider::getLines() const { + return {}; +} } // namespace SDLPP diff --git a/sdlpp/sdlpp_circlecolider.hpp b/sdlpp/sdlpp_circlecolider.hpp index 62ca485..3199197 100644 --- a/sdlpp/sdlpp_circlecolider.hpp +++ b/sdlpp/sdlpp_circlecolider.hpp @@ -21,11 +21,12 @@ public: virtual int rightmost() const override; virtual void updateCollision( int x, int y, int w, int h ) override; - virtual void - render( Renderer &renderer, - const std::tuple< int, int, int, int > &color ) override; + virtual void render( Renderer &renderer, const SDL_Color &color, + const SDL_Color &outline_color ) override; + virtual void render( Renderer &renderer, const SDL_Color &color ) override; virtual void render( Renderer &renderer ) override; virtual std::shared_ptr copySelf() override; + virtual std::vector> getLines() const override; private: int getRadius() const; diff --git a/sdlpp/sdlpp_circlerenderer.cpp b/sdlpp/sdlpp_circlerenderer.cpp index d2432f9..99a5992 100644 --- a/sdlpp/sdlpp_circlerenderer.cpp +++ b/sdlpp/sdlpp_circlerenderer.cpp @@ -28,7 +28,7 @@ CircleRender::CircleRender( Vec2D< double > center, double rad, CircleRender::CircleRender( Vec2D< double > center, double rad, std::shared_ptr< Renderer > &r, - std::shared_ptr< Texture > &t ) + std::shared_ptr< Texture > &/*UNUSED*/ ) : CircleRender( center, rad, r ) { throw "I don't support textures yet!!!"; } diff --git a/sdlpp/sdlpp_collision.cpp b/sdlpp/sdlpp_collision.cpp index f0901de..f8dc63f 100644 --- a/sdlpp/sdlpp_collision.cpp +++ b/sdlpp/sdlpp_collision.cpp @@ -1,4 +1,5 @@ #include "sdlpp_collision.hpp" +#include "sdlpp_geometry.hpp" namespace SDLPP { CollisionPolygon::CollisionPolygon( double x, double y ) @@ -53,8 +54,14 @@ bool infinityIntersection( const SDLPP::CollisionPolygon &infinite, bool intersects( const SDLPP::CollisionPolygon &p1, const SDLPP::CollisionPolygon &p2 ) { - return !( - p1.rightmost() < p2.leftmost() || p2.rightmost() < p1.leftmost() || - p1.topmost() > p2.bottommost() || p2.topmost() > p1.bottommost() ); + if(p1.rightmost() < p2.leftmost() || p2.rightmost() < p1.leftmost() || p1.bottommost() < p2.topmost() || p2.bottommost() < p1.topmost()) + return false; + for(auto &line : p1.getLines()) { + for(auto &line2 : p2.getLines()) { + if(linesCross(line, line2)) + return true; + } + } + return false; } } // namespace SDLPP diff --git a/sdlpp/sdlpp_collision.hpp b/sdlpp/sdlpp_collision.hpp index 347f9e8..2193443 100644 --- a/sdlpp/sdlpp_collision.hpp +++ b/sdlpp/sdlpp_collision.hpp @@ -4,13 +4,15 @@ #include "sdlpp_common.hpp" #include "sdlpp_renderer.hpp" #include "sdlpp_vector.hpp" +#include "sdlpp_line.hpp" #include +#include namespace SDLPP { class SDLPPSCOPE CollisionPolygon { public: CollisionPolygon( double x, double y ); - CollisionPolygon( const Vec2D &input ); + CollisionPolygon( const Vec2D< double > &input ); virtual ~CollisionPolygon() {} virtual bool colidesWith( const CollisionPolygon &other ) const = 0; virtual bool isCircle() const = 0; @@ -21,18 +23,20 @@ public: virtual int leftmost() const = 0; virtual int rightmost() const = 0; virtual void updateCollision( int x, int y, int w, int h ); - virtual void render( Renderer &renderer, - const std::tuple< int, int, int, int > &color ) = 0; + virtual void render( Renderer &renderer, const SDL_Color &color, + const SDL_Color &outline_color ) = 0; + virtual void render( Renderer &renderer, const SDL_Color &color ) = 0; virtual void render( Renderer &renderer ) = 0; int getX() const; int getY() const; void setColor( const std::string &color ); void setOutlineColor( const std::string &color ); virtual std::shared_ptr< CollisionPolygon > copySelf() = 0; + virtual std::vector< Line< int > > getLines() const = 0; protected: - Vec2D original; - Vec2D position; + Vec2D< double > original; + Vec2D< int > position; bool infinite = false; SDL_Color sdl_color = { 0, 0, 0, 0 }; SDL_Color sdl_outline = { 0, 0, 0, 0 }; diff --git a/sdlpp/sdlpp_geometry_line.hpp b/sdlpp/sdlpp_geometry_line.hpp index b0e21ad..c5ecda9 100644 --- a/sdlpp/sdlpp_geometry_line.hpp +++ b/sdlpp/sdlpp_geometry_line.hpp @@ -5,10 +5,12 @@ #include "sdlpp_vector.hpp" #include "sdlpp_line.hpp" #include +#include namespace SDLPP { -template -Vec2D pointProjectionOnLine( const Vec2D &point, const Line &line ) { +template < typename T > +Vec2D< T > pointProjectionOnLine( const Vec2D< T > &point, + const Line< T > &line ) { /* from here - * https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment */ @@ -21,10 +23,49 @@ Vec2D pointProjectionOnLine( const Vec2D &point, const Line &line ) { length_squared ) ); return line.getStart() + t * ( line.getEnd() - line.getStart() ); } -template -double pointLineDistance( const Vec2D &point, const Line &line ) { +template < typename T > +double pointLineDistance( const Vec2D< T > &point, const Line< T > &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 #endif diff --git a/sdlpp/sdlpp_line.hpp b/sdlpp/sdlpp_line.hpp index 687ac36..e988b09 100644 --- a/sdlpp/sdlpp_line.hpp +++ b/sdlpp/sdlpp_line.hpp @@ -3,6 +3,7 @@ #include "sdlpp_common.hpp" #include "sdlpp_vector.hpp" +#include namespace SDLPP { template @@ -11,14 +12,38 @@ public: Line() = delete; ~Line() = default; Line( const Vec2D &start, const Vec2D &end ) - : _start( start ), _end( end ) {} + : _start( start ), _end( end ) { + updateMost(); + } 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 &start, const Vec2D &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 ) - : _start( { x_1, y_1 } ), _end( { x_2, y_2 } ), - _infinite( infinite ) {} + : Line( { x_1, y_1 }, { x_2, y_2 }, 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 &getStart() const { return _start; } @@ -41,10 +66,26 @@ public: _start += vec; _end += vec; } + const Vec2D &topmost() const { + return *top; + } + const Vec2D &bottomost() const { + return *bottom; + } + const Vec2D &leftmost() const { + return *left; + } + const Vec2D &rightmost() const { + return *right; + } private: Vec2D _start; Vec2D _end; + Vec2D *top = nullptr; + Vec2D *bottom = nullptr; + Vec2D *left = nullptr; + Vec2D *right = nullptr; bool _infinite = false; }; } // namespace SDLPP diff --git a/sdlpp/sdlpp_rectcolider.cpp b/sdlpp/sdlpp_rectcolider.cpp index e41d8f7..658046b 100644 --- a/sdlpp/sdlpp_rectcolider.cpp +++ b/sdlpp/sdlpp_rectcolider.cpp @@ -62,29 +62,27 @@ void RectColider::updateCollision( int x, int y, int w, int h ) { _size_pixel = Vec2D< int >( width() * w, height() * h ); } -void RectColider::render( Renderer &renderer, - const std::tuple< int, int, int, int > &color ) { +void RectColider::render( Renderer &renderer, const SDL_Color &color, + const SDL_Color &outline_color ) { auto rect = getRect(); - // outline with desired color at 50% opacity - SDL_SetRenderDrawColor( renderer.getRendererPtr(), std::get< 0 >( color ), - 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_SetRenderDrawColor( renderer.getRendererPtr(), color.r, color.g, + color.b, color.a ); 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 ) { - auto rect = getRect(); - 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 ); + render( renderer, sdl_color, sdl_outline ); } SDL_Rect RectColider::getRect() { @@ -111,14 +109,14 @@ std::shared_ptr< CollisionPolygon > RectColider::copySelf() { return std::make_shared< RectColider >( *this ); } -std::vector< Line< double > > RectColider::getLines() { - std::vector< Line< double > > ret{}; - ret.emplace_back( original, original + Vec2D< double >( width(), 0 ) ); - ret.emplace_back( original + Vec2D< double >( width(), 0 ), - original + _size ); - ret.emplace_back( original, original + Vec2D< double >( 0, height() ) ); - ret.emplace_back( original + Vec2D< double >( 0, height() ), - original + _size ); +std::vector< Line< int > > RectColider::getLines() const { + std::vector< Line< int > > ret{}; + ret.emplace_back( position, position + Vec2D< int >( pixel_width(), 0 ) ); + ret.emplace_back( position + Vec2D< int >( pixel_width(), 0 ), + position + _size_pixel ); + ret.emplace_back( position, position + Vec2D< int >( 0, pixel_height() ) ); + ret.emplace_back( position + Vec2D< int >( 0, pixel_height() ), + position + _size_pixel ); return ret; } diff --git a/sdlpp/sdlpp_rectcolider.hpp b/sdlpp/sdlpp_rectcolider.hpp index e302816..1784d0a 100644 --- a/sdlpp/sdlpp_rectcolider.hpp +++ b/sdlpp/sdlpp_rectcolider.hpp @@ -13,7 +13,7 @@ namespace SDLPP { class SDLPPSCOPE RectColider : public CollisionPolygon { public: RectColider( double x, double y, double w, double h ); - RectColider( const Vec2D &top_left, const Vec2D &size ); + RectColider( const Vec2D< double > &top_left, const Vec2D< double > &size ); virtual ~RectColider() {} virtual bool colidesWith( const CollisionPolygon &other ) const override; virtual bool isCircle() const override; @@ -22,12 +22,12 @@ public: virtual int leftmost() const override; virtual int rightmost() const override; virtual void updateCollision( int x, int y, int w, int h ) override; - virtual void - render( Renderer &renderer, - const std::tuple< int, int, int, int > &color ) override; + virtual void render( Renderer &renderer, const SDL_Color &color, + const SDL_Color &outline_color ) override; + virtual void render( Renderer &renderer, const SDL_Color &color ) override; virtual void render( Renderer &renderer ) override; - virtual std::shared_ptr copySelf() override; - virtual std::vector> getLines(); + virtual std::shared_ptr< CollisionPolygon > copySelf() override; + virtual std::vector< Line< int > > getLines() const override; private: SDL_Rect getRect(); @@ -37,8 +37,8 @@ private: int pixel_width() const; int pixel_height() const; - Vec2D _size; - Vec2D _size_pixel; + Vec2D< double > _size; + Vec2D< int > _size_pixel; }; } // end of namespace SDLPP #endif diff --git a/sdlpp/sdlpp_renderobject.cpp b/sdlpp/sdlpp_renderobject.cpp index c35da6c..2348073 100644 --- a/sdlpp/sdlpp_renderobject.cpp +++ b/sdlpp/sdlpp_renderobject.cpp @@ -137,7 +137,7 @@ bool RenderObject::getKilled() { return kill; } void RenderObject::setColiderColor( const std::string &color ) { - colider_color = getColorsHEX( color ); + colider_color = getSDLColorHEX( color ); } void RenderObject::animate( int ticks ) { diff --git a/sdlpp/sdlpp_renderobject.hpp b/sdlpp/sdlpp_renderobject.hpp index bd60f05..df09cb1 100644 --- a/sdlpp/sdlpp_renderobject.hpp +++ b/sdlpp/sdlpp_renderobject.hpp @@ -114,7 +114,7 @@ protected: uint64_t id = -1; bool hidden = 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; bool permanent = false; bool is_static = true; diff --git a/tetris/Makefile b/tetris/Makefile index 409b2f0..b384009 100644 --- a/tetris/Makefile +++ b/tetris/Makefile @@ -10,7 +10,7 @@ OUTPUTFLAG = -Fo else UNAME_S := $(shell uname -s) 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 LDFLAGS ?= -lSDL2 -lSDL2_image -lSDL2_gfx -lSDL2_ttf -pthread OUTPUTFLAG = -o