collision detection [WIP]

This commit is contained in:
Sylvain PILLOT 2023-05-22 22:54:49 +02:00
parent 88351e0bd5
commit 0db32702c6
4 changed files with 125 additions and 86 deletions

View File

@ -86,10 +86,10 @@ void Level::UpdateDataMap( void )
MyPlayer.currx = ((float) (i + 0.5f))*16.0f;
MyPlayer.curry = ((float) (j + 0.5f))*16.0f;
MyPlayer.vx = 0.0f;
MyPlayer.vy = 0.0f;
MyPlayer.vx = 0;
MyPlayer.vy = 0;
MyPlayer.Update( 0.0f );
MyPlayer.Update( 0 );
}
}
}
@ -187,21 +187,21 @@ int Level::GetTileForeground( uint16_t x, uint16_t y )
return currentTile;
}
bool CollisionSegSeg( Point2D A, Point2D B, Point2D C, Point2D D, Point2D *R )
// Compute the intersection Point between segments [AB] and [CD]
// if there is an intersection, return true and store the result into Point R
bool CollisionSegSeg( Point2D A, Point2D B, Vector2D N, Point2D C, Point2D D, Point2D *R )
{
Vector2D I, J;
I.x = B.x - A.x;
I.y = B.y - A.y;
if (I.x==0 && I.y==0) return false;
//if (I.x==0 && I.y==0) return false;
J.x = D.x - C.x;
J.y = D.y - C.y;
if (J.x==0 && J.y==0) return false;
//if (J.x==0 && J.y==0) return false;
libnum::num32 det;
det = I.x*J.y-I.y*J.x;
@ -214,16 +214,58 @@ bool CollisionSegSeg( Point2D A, Point2D B, Point2D C, Point2D D, Point2D *R )
libnum::num32 k;
k = (J.x*A.y - J.x*C.y - J.y*A.x + J.y*C.x) / det;
if ((m<libnum::num32(0) || m>libnum::num32(1) || k<libnum::num32(0) || k>libnum::num32(1)))
return false; // intersection of the lines, but not of the segments
if ((m>=libnum::num32(0) && m<=libnum::num32(1) && k>=libnum::num32(0) && k<=libnum::num32(1)))
{
if ( (J.x*N.x + J.y*N.y) >= libnum::num32(0))
return false;
else
{
(*R).x = C.x + k*J.x;
(*R).y = C.y + k*J.y;
return true;
}
}
else 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;
}
libnum::num32 ClosestPointOnSegment( Point2D A, Point2D B, Point2D P, Point2D *R )
{
Vector2D AB;
AB.x = B.x - A.x;
AB.y = B.y - A.y;
libnum::num32 t = AB.Dot( AB );
if (t==0)
{
(*R).x = A.x;
(*R).y = A.y;
return t;
}
Vector2D Pv, Av;
Pv.x = P.x;
Pv.y = P.y;
Av.x = A.x;
Av.y = A.y;
libnum::num32 t2 = (Pv.Dot(AB) - Av.Dot(AB)) / t;
if (t2<libnum::num32(0)) t2 = libnum::num32(0);
if (t2>libnum::num32(1)) t2 = libnum::num32(1);
Av.Add( AB, t );
(*R).x = A.x;
(*R).y = A.y;
return t2;
}
/*RETURN true if the player can go in the target position*/
bool Level::CanGo( void )
{
@ -238,21 +280,12 @@ bool Level::CanGo( void )
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++)
{
Point2D A, B, I;
A.x = MyLevelBorders[i]->A.x;
A.y = MyLevelBorders[i]->A.y;
B.x = MyLevelBorders[i]->B.x;
B.y = MyLevelBorders[i]->B.y;
Point2D I;
// Detection de collision entre [A,B] et [Player.Curr, Player.Next]
if (CollisionSegSeg( A, B, PlayerOrigin, PlayerTarget, &I ))
if (CollisionSegSeg( MyLevelBorders[i]->A, MyLevelBorders[i]->B, MyLevelBorders[i]->N, PlayerOrigin, PlayerTarget, &I ))
{
MyLevelBorders[i]->color = C_RED;
MyPlayer.nextx = I.x;
@ -263,22 +296,20 @@ bool Level::CanGo( void )
return false;
}
}
return true;
}
Border* Level::MakeBorder( libnum::num DX, libnum::num DY, float x1, float y1, float x2, float y2 )
Border* Level::MakeBorder( libnum::num32 DX, libnum::num32 DY, libnum::num32 x1, libnum::num32 y1, libnum::num32 x2, libnum::num32 y2 )
{
Border *Bord = new Border();
Bord->A.x = DX + libnum::num(x1*15.0);
Bord->A.y = DY + libnum::num(y1*15.0);
Bord->A.x = DX + libnum::num(15)*x1;
Bord->A.y = DY + libnum::num(15)*y1;
Bord->B.x = DX + libnum::num(x2*15.0);
Bord->B.y = DY + libnum::num(y2*15.0);
Bord->B.x = DX + libnum::num(15)*x2;
Bord->B.y = DY + libnum::num(15)*y2;
Bord->N.x = Bord->A.y - Bord->B.y;
Bord->N.y = Bord->B.x - Bord->A.x;
@ -288,7 +319,7 @@ 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 )
void Level::ConvertTileToBorder( int16_t currentTile, libnum::num32 DeltaX, libnum::num32 DeltaY )
{
Border *B1;
@ -298,35 +329,35 @@ void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum
case 0: break; // No borders (filling tile)
case 1:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
//45° diagonals
case 2:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 3:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 12:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 13:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
@ -334,43 +365,43 @@ void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum
//22.5° diagonals
case 4:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,0.5 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1)/libnum::num32(2) );
MyLevelBorders.push_back(B1);
break;
case 5:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.5, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1)/libnum::num32(2), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 6:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 1.0,0.5 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(1),libnum::num32(1)/libnum::num32(2) );
MyLevelBorders.push_back(B1);
break;
case 7:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.5, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1)/libnum::num32(2), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 14:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.5, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1)/libnum::num32(2), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 15:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 0.0,0.5 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(0),libnum::num32(1)/libnum::num32(2) );
MyLevelBorders.push_back(B1);
break;
case 16:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.5, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1)/libnum::num32(2), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 17:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.5 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(1)/libnum::num32(2) );
MyLevelBorders.push_back(B1);
break;
@ -380,43 +411,43 @@ void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum
case 24:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1)/libnum::num32(2),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 34:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 0.5,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1)/libnum::num32(2),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 25:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.5,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(1)/libnum::num32(2),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 35:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,0.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1)/libnum::num32(2),libnum::num32(0), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 26:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,1.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1)/libnum::num32(2),libnum::num32(1), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 36:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 0.5,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1)/libnum::num32(2),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 27:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.5,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(1)/libnum::num32(2),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 37:
B1 = MakeBorder( DeltaX, DeltaY, 0.5,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1)/libnum::num32(2),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
@ -424,83 +455,83 @@ void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum
// Blocks with 3 sides
case 8:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 9:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 18:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 19:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
// Blocks with 2 sides
case 28:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 29:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 38:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 39:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 48:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 49:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
@ -508,25 +539,25 @@ void Level::ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum
case 10:
case 44:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,0.0, 0.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(0), libnum::num32(0),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;
case 11:
case 46:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,1.0, 1.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(1), libnum::num32(1),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 20:
case 47:
B1 = MakeBorder( DeltaX, DeltaY, 0.0,0.0, 0.0,1.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(0),libnum::num32(0), libnum::num32(0),libnum::num32(1) );
MyLevelBorders.push_back(B1);
break;
case 21:
case 45:
B1 = MakeBorder( DeltaX, DeltaY, 1.0,1.0, 1.0,0.0 );
B1 = MakeBorder( DeltaX, DeltaY, libnum::num32(1),libnum::num32(1), libnum::num32(1),libnum::num32(0) );
MyLevelBorders.push_back(B1);
break;

View File

@ -38,7 +38,7 @@ class Level
void ChangeMap( int level );
void UpdateDataMap( void );
void ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum::num DeltaY );
void ConvertTileToBorder( int16_t currentTile, libnum::num32 DeltaX, libnum::num32 DeltaY );
void UpdateBorders( void );
bool CanGo( void );
@ -49,7 +49,7 @@ class Level
int GetTileBackgroundINT( uint8_t x, uint8_t y );
int GetTileForegroundINT( uint8_t x, uint8_t y );
Border* MakeBorder( libnum::num DX, libnum::num DY, float x1, float y1, float x2, float y2 );
Border* MakeBorder( libnum::num32 DX, libnum::num32 DY, libnum::num32 x1, libnum::num32 y1, libnum::num32 x2, libnum::num32 y2 );
};

View File

@ -56,6 +56,13 @@ Vector2D Vector2D::Clone( void )
return NewVector;
}
Vector2D Vector2D::MakeVector( Point2D A, Point2D B)
{
Vector2D NewVector( B.x-A.x, B.y-A.y );
return NewVector;
}
void Vector2D::AddVectors( Vector2D a, Vector2D b )
{
this->x = a.x + b.x;

View File

@ -42,6 +42,7 @@ class Vector2D
~Vector2D();
Vector2D Clone( void );
Vector2D MakeVector( Point2D A, Point2D B);
void AddVectors( Vector2D a, Vector2D b );
void Add( Vector2D v, libnum::num32 scale );