From 88351e0bd53ee407b4496fcdb27d5b4efa0f8237 Mon Sep 17 00:00:00 2001 From: SlyVTT Date: Mon, 22 May 2023 00:26:08 +0200 Subject: [PATCH] added collision detection with border [WIP] - need to improve accuracy not to go through walls at connection points --- src/level.cpp | 146 +++++++++++++++++------------------------------ src/level.h | 3 +- src/main.cpp | 12 +++- src/player.cpp | 7 ++- src/vector2D.cpp | 100 +------------------------------- src/vector2D.h | 18 ++---- 6 files changed, 74 insertions(+), 212 deletions(-) diff --git a/src/level.cpp b/src/level.cpp index 2ce5d8f..fd72dba 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -134,14 +134,11 @@ void Level::Render( void ) ((int) MyLevelBorders[i]->A.x+(int) MyLevelBorders[i]->B.x)/2 + (int) MyLevelBorders[i]->N.x/2, ((int) MyLevelBorders[i]->A.y+(int) MyLevelBorders[i]->B.y)/2 + (int) MyLevelBorders[i]->N.y/2, C_BLUE ); #endif - } void Level::RenderSelected( uint8_t i, uint8_t j ) { - //azrp_image_p8( i*16, j*16, &img_selected, DIMAGE_NONE ); - //azrp_draw_text( i*16+1, j*16+1, "B=%d", GetTileBackgroundINT( i, j ) ); - //azrp_draw_text( i*16+1, j*16+1, "F=%d", GetTileForegroundINT( i, j ) ); + } @@ -191,64 +188,60 @@ int Level::GetTileForeground( uint16_t x, uint16_t y ) } -bool CollisionDroiteSeg(Point2D A,Point2D B,Point2D O,Point2D P) +bool CollisionSegSeg( Point2D A, Point2D B, Point2D C, Point2D D, Point2D *R ) { - Vector2D AO,AP,AB; - AB.x = B.x - A.x; - AB.y = B.y - A.y; - AP.x = P.x - A.x; - AP.y = P.y - A.y; - AO.x = O.x - A.x; - AO.y = O.y - A.y; - libnum::num part1 = AB.x*AP.y - AB.y*AP.x; - libnum::num part2 = AB.x*AO.y - AB.y*AO.x; - - if (part1*part2<0) - return true; - else - return false; -} + Vector2D I, J; -bool CollisionSegSeg( Point2D A, Point2D B, Point2D O, Point2D P) -{ - if (CollisionDroiteSeg(A,B,O,P)==false) - return false; // inutile d'aller plus loin si le segment [OP] ne touche pas la droite (AB) - - Vector2D AB,OP; - AB.x = B.x - A.x; - AB.y = B.y - A.y; - OP.x = P.x - O.x; - OP.y = P.y - O.y; + I.x = B.x - A.x; + I.y = B.y - A.y; + + if (I.x==0 && I.y==0) return false; - libnum::num part1 = (A.x*OP.y-O.x*OP.y-OP.x*A.y+OP.x*O.y); - libnum::num part2 = (AB.x*OP.y-AB.y*OP.x); - libnum::num k = - part1 / part2; - - if (k<0 || k>1) - return false; - else - return true; + J.x = D.x - C.x; + J.y = D.y - C.y; + + if (J.x==0 && J.y==0) return false; + + libnum::num32 det; + det = I.x*J.y-I.y*J.x; + + if (det==0) return false; // the segments are parallel + + libnum::num32 m; + m = (I.x*A.y - I.x*C.y - I.y*A.x + I.y*C.x) / det; + + libnum::num32 k; + k = (J.x*A.y - J.x*C.y - J.y*A.x + J.y*C.x) / det; + + if ((mlibnum::num32(1) || klibnum::num32(1))) + return false; // intersection of the lines, but not of the segments + + (*R).x = C.x + k*J.x; + (*R).y = C.y + k*J.y; + + return true; } /*RETURN true if the player can go in the target position*/ -bool Level::CanGo( Player *MyPlayer ) +bool Level::CanGo( void ) { Point2D PlayerOrigin, PlayerTarget; - PlayerOrigin.x = MyPlayer->currx; - PlayerOrigin.y = MyPlayer->curry; + PlayerOrigin.x = MyPlayer.currx; + PlayerOrigin.y = MyPlayer.curry; - PlayerTarget.x = MyPlayer->nextx; - PlayerTarget.y = MyPlayer->nexty; + PlayerTarget.x = MyPlayer.nextx; + PlayerTarget.y = MyPlayer.nexty; - if (PlayerTarget.x == PlayerOrigin.x && PlayerTarget.y == PlayerOrigin.y) return true; - if (MyLevelBorders.size() == 0) return true; + if (PlayerTarget.x == PlayerOrigin.x && PlayerTarget.y == PlayerOrigin.y) return true; // velocity is 0 so Player.next = Player.Curr so we can stay here, that's obvious + if (MyLevelBorders.size() == 0) return true; // there is no surrounding border so no need to check if there are collisions (also obvious) - for (unsigned int i=0; i<=MyLevelBorders.size(); i++) + + for (unsigned int i=0; iA.x; A.y = MyLevelBorders[i]->A.y; @@ -256,33 +249,26 @@ bool Level::CanGo( Player *MyPlayer ) B.x = MyLevelBorders[i]->B.x; B.y = MyLevelBorders[i]->B.y; - if (CollisionSegSeg( A, B, PlayerOrigin, PlayerTarget )) + // Detection de collision entre [A,B] et [Player.Curr, Player.Next] + + + if (CollisionSegSeg( A, B, PlayerOrigin, PlayerTarget, &I )) { MyLevelBorders[i]->color = C_RED; - return false; + MyPlayer.nextx = I.x; + MyPlayer.nexty = I.y; + MyPlayer.vx = libnum::num32(0); + MyPlayer.vy = libnum::num32(0); + + return false; } - else - { - MyLevelBorders[i]->color = C_RGB( 255, 0, 255 ); - } - + } return true; } -/*RETURN true if the player is above a solid tile*/ -/*TO DO : TO BE IMPROVED, THIS IS REALLY DIRTY !!!!*/ -bool Level::IsOnGround( Player *MyPlayer ) -{ - if (this->GetTileBackgroundINT( (int) MyPlayer->currx, (int) MyPlayer->curry +1 ) !=0) - { - return true; - } - - return false; -} Border* Level::MakeBorder( libnum::num DX, libnum::num DY, float x1, float y1, float x2, float y2 ) { @@ -302,7 +288,6 @@ Border* Level::MakeBorder( libnum::num DX, libnum::num DY, float x1, float y1, f return Bord; } - void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum::num DeltaY ) { Border *B1; @@ -550,33 +535,6 @@ void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum } } - -#if 0 - -void Level::UpdateBorders( void ) -{ - for(unsigned int i=0; iw; i++) - { - for( int j=0; jh; j++) - { - uint16_t index = j * map_level->w + i; - int16_t currentTile = map_level->layers[0][ index ]; - - libnum::num DeltaX = libnum::num( i*16 ); - libnum::num DeltaY = libnum::num( j*16 ); - - ConvertTileToBorder( currentTile, DeltaX, DeltaY ); - } - } -} - -#else - void Level::UpdateBorders( void ) { for(unsigned int i=0; i=1) azrp_draw_text(1,01, "FPS = %.0f - Mem Free = %d", (float) (1000.0f / elapsedTime), _uram_stats->free_memory + extram_stats->free_memory ); - if (texttodraw>=1) azrp_draw_text(1,11, "PlayX = %d - PlayY = %d", MyPlayer.tileX, MyPlayer.tileY ); + if (texttodraw>=1) azrp_draw_text(1,11, "PlayX = %d - PlayY = %d - VX = %d - VY = %d", MyPlayer.tileX, MyPlayer.tileY, MyPlayer.nextx.v - MyPlayer.currx.v, MyPlayer.nexty.v - MyPlayer.curry.v ); if (texttodraw>=2) azrp_draw_text(1,31, "Update = %.3f ms", (float) time_update / 1000.0f ); if (texttodraw>=2) azrp_draw_text(1,41, "Render = %.3f ms", (float) time_render / 1000.0f ); @@ -301,8 +301,16 @@ int main(void) azrp_circle( (int) MyPlayer.currx, (int) MyPlayer.curry, 8, C_RED ); + azrp_line( (int) MyPlayer.currx-3, (int) MyPlayer.curry , (int) MyPlayer.currx+3, (int) MyPlayer.curry , C_GREEN ); + azrp_line( (int) MyPlayer.currx , (int) MyPlayer.curry-3, (int) MyPlayer.currx , (int) MyPlayer.curry+3, C_GREEN ); + + azrp_line( (int) MyPlayer.nextx-3, (int) MyPlayer.nexty , (int) MyPlayer.nextx+3, (int) MyPlayer.nexty , C_BLUE ); + azrp_line( (int) MyPlayer.nextx , (int) MyPlayer.nexty-3, (int) MyPlayer.nextx , (int) MyPlayer.nexty+3, C_BLUE ); + + azrp_update(); - } + + } prof_leave(perf_render); time_render = prof_time(perf_render); diff --git a/src/player.cpp b/src/player.cpp index faf82c3..1151ba9 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -56,13 +56,14 @@ void Player::Update( float dt ) this->vy += this->ay * DeltaTime; this->vx += this->ax * DeltaTime; - if (this->vx >= MAXRUNSPEED) this->vx = MAXRUNSPEED; - if (this->vy >= MAXFALLSPEED) this->vy = MAXFALLSPEED; + + //if (this->vx >= MAXRUNSPEED) this->vx = MAXRUNSPEED; + //if (this->vy >= MAXFALLSPEED) this->vy = MAXFALLSPEED; this->nextx = this->currx + this->vx * DeltaTime; this->nexty = this->curry + this->vy * DeltaTime; - if (MyLevel.CanGo( this )) + if (MyLevel.CanGo()) { this->currx = this->nextx; this->curry = this->nexty; diff --git a/src/vector2D.cpp b/src/vector2D.cpp index 10305db..a935c6a 100644 --- a/src/vector2D.cpp +++ b/src/vector2D.cpp @@ -29,8 +29,8 @@ libnum::num32 sqrt_num32(libnum::num32 v) Vector2D::Vector2D() { - this->x = 0.0; - this->y = 0.0; + this->x = libnum::num32(0); + this->y = libnum::num32(0); } Vector2D::Vector2D( float x, float y ) @@ -47,8 +47,7 @@ Vector2D::Vector2D( libnum::num32 x, libnum::num32 y ) Vector2D::~Vector2D() { - this->x = 0.0; - this->y = 0.0; + } Vector2D Vector2D::Clone( void ) @@ -104,99 +103,6 @@ Vector2D Vector2D::Perp( void ) } -bool CollisionDroite(Point2D A,Point2D B, Circle C) -{ - Vector2D u; - u.x = B.x - A.x; - u.y = B.y - A.y; - Vector2D AC; - AC.x = C.x - A.x; - AC.y = C.y - A.y; - libnum::num numerateur = u.x*AC.y - u.y*AC.x; // norme du vecteur v - if (numerateur <0) - numerateur = -numerateur ; // valeur absolue ; si c'est négatif, on prend l'opposé. - libnum::num denominateur = sqrt_num32(u.x*u.x + u.y*u.y); // norme de u - libnum::num CI = numerateur / denominateur; - - if (CI < C.r) - return true; - else - return false; -} - - -bool CollisionSegment(Point2D A,Point2D B, Circle C) -{ - if (CollisionDroite(A,B,C) == false) - return false; // si on ne touche pas la droite, on ne touchera jamais le segment - - Vector2D AB,AC,BC; - AB.x = B.x - A.x; - AB.y = B.y - A.y; - AC.x = C.x - A.x; - AC.y = C.y - A.y; - BC.x = C.x - B.x; - BC.y = C.y - B.y; - - libnum::num pscal1 = AB.x*AC.x + AB.y*AC.y; // produit scalaire - libnum::num pscal2 = (-AB.x)*BC.x + (-AB.y)*BC.y; // produit scalaire - - if (pscal1 >= 0 && pscal2 >= 0) - return true; // I entre A et B, ok. - - return false; -} - - -bool CollisionBorder(Border *B, Circle C) -{ - return CollisionSegment( B->A, B->B, C ); -} - - -Vector2D GetNormale(Point2D A,Point2D B,Point2D C) -{ - Vector2D AC,u,N; - u.x = B.x - A.x; - u.y = B.y - A.y; - AC.x = C.x - A.x; - AC.y = C.y - A.y; - libnum::num parenthesis = u.x*AC.y-u.y*AC.x; // calcul une fois pour les deux - - N.x = -u.y*(parenthesis); - N.y = u.x*(parenthesis); - - // normalisons - libnum::num norme = sqrt_num32(N.x*N.x + N.y*N.y); - N.x/=norme; - N.y/=norme; - - return N; -} - -Point2D ProjectionI(Point2D A,Point2D B,Point2D C) -{ - Vector2D u,AC; - u.x = B.x - A.x; - u.y = B.y - A.y; - AC.x = C.x - A.x; - AC.y = C.y - A.y; - libnum::num ti = (u.x*AC.x + u.y*AC.y)/(u.x*u.x + u.y*u.y); - Point2D I; - I.x = A.x + ti*u.x; - I.y = A.y + ti*u.y; - return I; -} - -Vector2D ComputeVectorRebound(Vector2D v,Vector2D N) -{ - Vector2D v2; - libnum::num pscal = (v.x*N.x + v.y*N.y); - v2.x = v.x -2*pscal*N.x; - v2.y = v.y -2*pscal*N.y; - return v2; -} - Border::Border() { diff --git a/src/vector2D.h b/src/vector2D.h index a314a4e..3aa53e7 100644 --- a/src/vector2D.h +++ b/src/vector2D.h @@ -13,8 +13,8 @@ class Point2D Point2D() {}; ~Point2D() {}; - libnum::num x; - libnum::num y; + libnum::num32 x; + libnum::num32 y; }; class Circle @@ -23,9 +23,9 @@ class Circle Circle() {}; ~Circle() {}; - libnum::num x; - libnum::num y; - libnum::num r; + libnum::num32 x; + libnum::num32 y; + libnum::num32 r; }; @@ -122,12 +122,4 @@ class Border uint16_t color; }; - -bool CollisionDroite(Point2D A,Point2D B, Circle C); -bool CollisionSegment(Point2D A,Point2D B,Circle C); -bool CollisionBorder(Border* B, Circle C); -Vector2D GetNormale(Point2D A,Point2D B,Point2D C); -Point2D ProjectionI(Point2D A,Point2D B,Point2D C); -Vector2D ComputeVectorRebound(Vector2D v,Vector2D N); - #endif \ No newline at end of file