added collision detection with border [WIP] - need to improve accuracy not to go through walls at connection points
This commit is contained in:
parent
7662a06e2c
commit
88351e0bd5
146
src/level.cpp
146
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 ((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
|
||||
|
||||
(*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; i<MyLevelBorders.size(); i++)
|
||||
{
|
||||
Point2D A, B;
|
||||
Point2D A, B, I;
|
||||
|
||||
A.x = MyLevelBorders[i]->A.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; i<MyLevelBorders.size();i++)
|
||||
delete MyLevelBorders[i];
|
||||
|
||||
MyLevelBorders.clear();
|
||||
|
||||
for( int i=0; i<map_level->w; i++)
|
||||
{
|
||||
for( int j=0; j<map_level->h; 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<MyLevelBorders.size(); i++)
|
||||
|
@ -609,5 +567,3 @@ void Level::UpdateBorders( void )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -41,8 +41,7 @@ class Level
|
|||
void ConvertTileToBorder( int16_t currentTile, libnum::num DeltaX, libnum::num DeltaY );
|
||||
void UpdateBorders( void );
|
||||
|
||||
bool CanGo( Player *MyPlayer );
|
||||
bool IsOnGround( Player *MyPlayer );
|
||||
bool CanGo( void );
|
||||
|
||||
private:
|
||||
int GetTileBackground( uint16_t x, uint16_t y );
|
||||
|
|
12
src/main.cpp
12
src/main.cpp
|
@ -122,7 +122,7 @@ static void render( void )
|
|||
|
||||
#if(BIAS)
|
||||
if (texttodraw>=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);
|
||||
|
|
|
@ -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;
|
||||
|
|
100
src/vector2D.cpp
100
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()
|
||||
{
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue