From a524c5f08e603071b14f8df910d552c9ffac5d8c Mon Sep 17 00:00:00 2001 From: SlyVTT Date: Tue, 22 Aug 2023 23:34:18 +0200 Subject: [PATCH] Boss with satellite guns - Bullet Hell versions to test framerate --- CMakeLists.txt | 5 +- assets-cg/Sprites/Boss/BossGun.png | Bin 0 -> 1073 bytes .../Sprites/Bullets/bullet_enemy_blue.png | Bin 118 -> 131 bytes .../Sprites/Bullets/bullet_enemy_green.png | Bin 0 -> 136 bytes .../Sprites/Bullets/bullet_enemy_red.png | Bin 0 -> 137 bytes captures/fxlink-image-2023.08.14-13h38-14.png | Bin 16382 -> 0 bytes captures/fxlink-image-2023.08.14-13h38-17.png | Bin 15941 -> 0 bytes captures/fxlink-image-2023.08.14-13h38-41.png | Bin 13253 -> 0 bytes src/boss.cpp | 157 +++++++++- src/boss.h | 22 +- src/bullet.cpp | 21 +- src/bullet.h | 2 + src/config.h | 6 +- src/enemy.cpp | 1 - src/main.cpp | 4 +- src/vector2D.h | 278 ++++++++++++++++++ 16 files changed, 478 insertions(+), 18 deletions(-) create mode 100644 assets-cg/Sprites/Boss/BossGun.png create mode 100644 assets-cg/Sprites/Bullets/bullet_enemy_green.png create mode 100644 assets-cg/Sprites/Bullets/bullet_enemy_red.png delete mode 100644 captures/fxlink-image-2023.08.14-13h38-14.png delete mode 100644 captures/fxlink-image-2023.08.14-13h38-17.png delete mode 100644 captures/fxlink-image-2023.08.14-13h38-41.png create mode 100644 src/vector2D.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 142822a..36a46e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,8 @@ set(ASSETS_cg assets-cg/Sprites/Bullets/bullet_blue.png assets-cg/Sprites/Bullets/bullet_laser.png assets-cg/Sprites/Bullets/bullet_enemy_blue.png + assets-cg/Sprites/Bullets/bullet_enemy_red.png + assets-cg/Sprites/Bullets/bullet_enemy_green.png assets-cg/Sprites/Players/mainship1.png assets-cg/Sprites/Players/Satellite_Lvl1.png @@ -74,7 +76,8 @@ set(ASSETS_cg assets-cg/Sprites/Enemies/Enemy_Red_Lvl1.png assets-cg/Sprites/Boss/Boss1.png - + assets-cg/Sprites/Boss/BossGun.png + assets-cg/Levels/tileset.png assets-cg/Levels/Level2.json # assets-cg/Levels/Tileset_Space.json diff --git a/assets-cg/Sprites/Boss/BossGun.png b/assets-cg/Sprites/Boss/BossGun.png new file mode 100644 index 0000000000000000000000000000000000000000..9f404d2a3e89d7569840b1c9720d6f85ac7a2d98 GIT binary patch literal 1073 zcmV-11kU@3P)d;%PNQ**^;C4+t z+S7x$d5-czYz(!R>bP*GZb84u&EF}FK?Y`L=LillFgP?wTg!cn7v96X>k#7438u%b z=nQ(I%ih7I;wJsqYw=*NOJc1nfudp!OE1grM=4Z|A2|X_h(h+`Bpa<)&p+J%Rtr zadZ||V%ibIu-X}aqaWI-8I;gamaX*Q@riD9d8<+BT$r4)QqXaJepS>t+1dN1L;Mgf z0z<(|*cHM3v#r>ib$Bihprf&YQNLSgZc1DtBN%J$Brq?7N46deg|8y6jpIJ!xNlBT zbeh)o8yHslpbPS6W^4eY7DcgQ%u7aSG|XNaWxB>r!rpjhZ8lUk!Grcrd`(e^*%_o1 zG}WIJ0IErgf_H2fV%&zN$A#e^&J&Othw{6bsToP+<}6Ixw_#BfWLG;@E=pl3yJkb zICNR?xYohkm0wx!uV?tt-CY18W5Y(7os~u7#9G*xxu{AD@=M;ozr_oK0^ zv9E9-W=xk85c(#ZXRv~1_tu!ffBJ`>57W>$ktoe2?;dP-_na~b{0-+ zgL!c4Hgaed`$aR!uSe5*rIo!OeaxDaWU=U>yRIoM5|cPl_5D~>P7*6~ z6F7OQx?o0`qok;qmw$oD_^Py&>FUM|nqUz7lD-oA49!9&SX rv@UbQf`-hjta(2*J!5IG|Es?N<=la%{nvBD00000NkvXXu0mjf%SaSM literal 0 HcmV?d00001 diff --git a/assets-cg/Sprites/Bullets/bullet_enemy_blue.png b/assets-cg/Sprites/Bullets/bullet_enemy_blue.png index 33456cb696888a782f9d855b5f4ddbd4535faf21..4e7b05f6776f59cf2278b67c24366a9bc3a29ab1 100644 GIT binary patch delta 19 acmXSGW}KkH#aJBV?!>U}oXpFKilG2I;|7ob delta 8 PcmZo>ESsP*(J%-A46*{l diff --git a/assets-cg/Sprites/Bullets/bullet_enemy_green.png b/assets-cg/Sprites/Bullets/bullet_enemy_green.png new file mode 100644 index 0000000000000000000000000000000000000000..ba0130032b1130c0a4a795d5df6a26dd98547fac GIT binary patch literal 136 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 z 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 OL8^+H3e|Gfq5lWB9Vit5 diff --git a/captures/fxlink-image-2023.08.14-13h38-41.png b/captures/fxlink-image-2023.08.14-13h38-41.png deleted file mode 100644 index 376855b9a9147d12f2e4634f42232dab32af300e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13253 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 oh?t{wg(cztdllt303Z_|z=0op*D?EnA( diff --git a/src/boss.cpp b/src/boss.cpp index 7d5ebb7..ed8773a 100644 --- a/src/boss.cpp +++ b/src/boss.cpp @@ -10,15 +10,23 @@ #include #include "collections.h" +#include "player.h" +#include "vector2D.h" extern bopti_image_t img_Lifebar; extern bopti_image_t img_Boss1; +extern bopti_image_t img_BossGun; extern font_t milifont_prop; +extern std::vector MyEnemiesBullets; +extern Player *MyPlayer; + #define NB_PIECES_BOSS 12 +#define NB_GUNS 12 + libnum::num XdataBossInternal[NB_PIECES_BOSS]; libnum::num YdataBossInternal[NB_PIECES_BOSS]; libnum::num XdataBossExternal[NB_PIECES_BOSS]; @@ -26,6 +34,10 @@ libnum::num YdataBossExternal[NB_PIECES_BOSS]; BossPart Pieces[NB_PIECES_BOSS*2]; +libnum::num xGuns[NB_GUNS]; +libnum::num yGuns[NB_GUNS]; + +BossGun Guns[NB_GUNS]; #include @@ -108,10 +120,9 @@ Boss::Boss( int16_t _x, int16_t _y, uint8_t _id ) lastshoot0 = rtc_ticks(); lastshoot1 = rtc_ticks(); - lastshoot2 = rtc_ticks(); - radiusInt = libnum::num( 75 ); - radiusExt = libnum::num( 100 ); + radiusInt = libnum::num( 80 ); + radiusExt = libnum::num( 90 ); rotAngle = 0.0f; rotSpeed = 2; @@ -135,6 +146,11 @@ Boss::Boss( int16_t _x, int16_t _y, uint8_t _id ) Pieces[i*2+1].color = 0x528a; //darker gray } + for( int i=0; i360.0f) rotAngle-=360.0f; + /* Management of the shield part of the boss (rotating circles made of triangles)*/ uint16_t angleint = (uint16_t) rotAngle; uint16_t angledelta = (uint16_t) (360/NB_PIECES_BOSS); @@ -182,6 +199,63 @@ void Boss::Update( float dt ) if (angleint>=360) angleint -= 360; } + /* Management of the Guns part of the boss (rotating cannons made of sprites)*/ + + angledelta = (uint16_t) (360/NB_GUNS); + angleint = (uint16_t) rotAngle + angledelta/2; + if (angleint>=360) angleint -= 360; + + for( int i=0; ix + (this->radiusInt + this->radiusExt) / 2 * FastCosInt( angleint ); + yGuns[i] = this->y + (this->radiusInt + this->radiusExt) / 2 * FastSinInt( angleint ); + angleint += angledelta; + if (angleint>=360) angleint -= 360; + } + + + uint32_t tempshoot = rtc_ticks(); + + bool hasExternalGun = false; + + if (Shoot_OK( tempshoot, BULLET_ENEMY_RED )) + { + /* shoot from the rotating cannons (aiming directly the position of the player )*/ + for( int i=0; ix - xGuns[i], MyPlayer->y - yGuns[i] ); + shootDirection.Normalise(); + + Bullet *b = new Bullet( (int) xGuns[i] , (int) yGuns[i], (int) shootDirection.x, (int) shootDirection.y, BULLET_ENEMY_RED ); + MyEnemiesBullets.push_back( b ); + + hasExternalGun = true; + } + } + } + + if (hasExternalGun==false) + if(Shoot_OK( tempshoot, BULLET_ENEMY_GREEN )) + { + /* central shoot from the main ship only if no more other gun shooting */ + + Bullet *b0 = new Bullet( xmin, (int) y, -3, 0, BULLET_ENEMY_GREEN ); + MyEnemiesBullets.push_back( b0 ); + + Bullet *b1 = new Bullet( xmin, (int) y, -2, -2, BULLET_ENEMY_BLUE ); + MyEnemiesBullets.push_back( b1 ); + + Bullet *b2 = new Bullet( xmin, (int) y, -2, 2, BULLET_ENEMY_BLUE ); + MyEnemiesBullets.push_back( b2 ); + + Bullet *b3 = new Bullet( xmin, (int) y, -3, -1, BULLET_ENEMY_GREEN ); + MyEnemiesBullets.push_back( b3 ); + + Bullet *b4 = new Bullet( xmin, (int) y, -3, 1, BULLET_ENEMY_GREEN ); + MyEnemiesBullets.push_back( b4 ); + } } @@ -189,7 +263,7 @@ void Boss::Update( float dt ) void Boss::Render( void ) { - if (ID==0 && toberemoved==false) + if (toberemoved==false) { for( int i=0; ilife0*2/3) azrp_subimage_p8_effect((int) x - img_Lifebar.width/2, ymin - 9, &img_Lifebar, 0, 7, (img_Lifebar.width*life)/life0, 5, DIMAGE_NONE ); else if (life>life0/3) azrp_subimage_p8_effect((int) x - img_Lifebar.width/2, ymin - 9, &img_Lifebar, 0, 12, (img_Lifebar.width*life)/life0, 5, DIMAGE_NONE ); else azrp_subimage_p8_effect((int) x - img_Lifebar.width/2, ymin - 9, &img_Lifebar, 0, 17, (img_Lifebar.width*life)/life0, 5, DIMAGE_NONE ); + }; } bool Boss::Test_Impact( Bullet *projectile ) { + /* We check if the bullet collides with teh shield of the boss */ for( int i=0; i< NB_PIECES_BOSS; i++ ) { if (Pieces[i*2].toberemoved == false) @@ -273,13 +368,65 @@ bool Boss::Test_Impact( Bullet *projectile ) } } + /* We check if the bullet collides with the cannons of the boss */ + for( int i=0; ix >= (int) xGuns[i] - img_BossGun.width/2 && + projectile->x <= (int) xGuns[i] + img_BossGun.width/2 && + projectile->y >= (int) yGuns[i] - img_BossGun.height/2 && + projectile->y <= (int) yGuns[i] + img_BossGun.height/2 ) + { + Guns[i].life -= projectile->strength; + if (Guns[i].life<0) + { + Guns[i].toberemoved = true; + Create_Explosion( (int) projectile->x, (int) projectile->y ); + } + projectile->toberemoved = true; + return true; + } + } + } + + /* We check if the bullet collides with the main ship part of the boss */ if (projectile->x >= xmin && projectile->x <= xmax && projectile->y >= ymin && projectile->y <= ymax ) { life -= projectile->strength; - if (life<0) this->toberemoved = true; + if (life<0) + { + this->toberemoved = true; + Create_Explosion( (int) projectile->x, (int) projectile->y ); + } projectile->toberemoved = true; return true; } else return false; } + + +bool Boss::Shoot_OK( uint32_t tempshoot, uint8_t shootID ) +{ + if (shootID==BULLET_ENEMY_RED) + { + if(tempshoot-lastshoot0>10) + { + lastshoot0=tempshoot; + return true; + } + else return false; + } + else if (shootID==BULLET_ENEMY_GREEN) + { + if(tempshoot-lastshoot1>25) + { + lastshoot1=tempshoot; + return true; + } + else return false; + } + else return false; + +} \ No newline at end of file diff --git a/src/boss.h b/src/boss.h index 42e1a2f..be773f2 100644 --- a/src/boss.h +++ b/src/boss.h @@ -10,7 +10,7 @@ #include #include #include "bullet.h" - +#include "trajectory.h" typedef struct @@ -22,6 +22,12 @@ typedef struct } BossPart; +typedef struct +{ + int16_t life; + bool toberemoved; +} BossGun; + class Boss { @@ -40,15 +46,21 @@ class Boss uint8_t ID; int16_t life, life0; uint8_t speed; // speed of the boss - uint32_t lastshoot0 = 0; - uint32_t lastshoot1 = 0; - uint32_t lastshoot2 = 0; + uint32_t lastshoot = 0; uint8_t rotSpeed; bool toberemoved; + bool hasTrajectory = false; + Trajectory *pathToFollow; + private: float rotAngle; - libnum::num radiusInt, radiusExt; + libnum::num radiusInt, radiusExt; + + uint32_t lastshoot0 = 0; + uint32_t lastshoot1 = 0; + + bool Shoot_OK( uint32_t tempshoot, uint8_t shootID ); }; diff --git a/src/bullet.cpp b/src/bullet.cpp index 24fc0da..bb5c375 100644 --- a/src/bullet.cpp +++ b/src/bullet.cpp @@ -15,7 +15,8 @@ extern bopti_image_t img_bullet_normal; extern bopti_image_t img_bullet_blue; extern bopti_image_t img_bullet_laser; extern bopti_image_t img_bullet_enemy_blue; - +extern bopti_image_t img_bullet_enemy_red; +extern bopti_image_t img_bullet_enemy_green; Bullet::Bullet( uint16_t lx, uint16_t ly, int16_t dx, int16_t dy, uint8_t id ) @@ -44,6 +45,14 @@ Bullet::Bullet( uint16_t lx, uint16_t ly, int16_t dx, int16_t dy, uint8_t id ) { strength = 2; } + else if (ID==BULLET_ENEMY_RED) + { + strength = 3; + } + else if (ID==BULLET_ENEMY_GREEN) + { + strength = 5; + } toberemoved = false; } @@ -87,5 +96,15 @@ void Bullet::Render( ) azrp_image_p8( px-img_bullet_enemy_blue.width/2, py-img_bullet_enemy_blue.height/2, &img_bullet_enemy_blue, DIMAGE_NONE ); return; } + else if (ID==BULLET_ENEMY_RED) + { + azrp_image_p8( px-img_bullet_enemy_red.width/2, py-img_bullet_enemy_red.height/2, &img_bullet_enemy_red, DIMAGE_NONE ); + return; + } + else if (ID==BULLET_ENEMY_GREEN) + { + azrp_image_p8( px-img_bullet_enemy_green.width/2, py-img_bullet_enemy_green.height/2, &img_bullet_enemy_green, DIMAGE_NONE ); + return; + } } diff --git a/src/bullet.h b/src/bullet.h index a3bc480..8ae9470 100644 --- a/src/bullet.h +++ b/src/bullet.h @@ -11,6 +11,8 @@ enum BULLET_BLUE, BULLET_LASER, BULLET_ENEMY_BLUE, + BULLET_ENEMY_RED, + BULLET_ENEMY_GREEN, }; diff --git a/src/config.h b/src/config.h index e738a22..dc55aa7 100644 --- a/src/config.h +++ b/src/config.h @@ -3,9 +3,9 @@ -#define DEBUG_MODE 0 -#define USB 0 -#define MORE_RAM 0 +#define DEBUG_MODE 0 +#define USB 1 +#define MORE_RAM 1 #define CALCEMU 0 diff --git a/src/enemy.cpp b/src/enemy.cpp index b69d03d..9a0914c 100644 --- a/src/enemy.cpp +++ b/src/enemy.cpp @@ -107,7 +107,6 @@ void Enemy::Update( float dt ) Bullet *b = new Bullet( xmin, (int) y, -1, 0, BULLET_ENEMY_BLUE ); MyEnemiesBullets.push_back( b ); } - } diff --git a/src/main.cpp b/src/main.cpp index d8c9f51..f788db2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -484,7 +484,7 @@ int main(void) azrp_starfield_init( 250 ); - Create_Enemies( ); + //Create_Enemies( ); MyPlayer = new Player( azrp_width/4, azrp_height/2, 0); @@ -546,7 +546,7 @@ int main(void) elapsedTime = ((float) (time_update+time_render)); -#if(DEBUG_MODE) +#if(DEBUG_MODE && USB) if (textoutput && usb_is_open()) { diff --git a/src/vector2D.h b/src/vector2D.h new file mode 100644 index 0000000..52b77ea --- /dev/null +++ b/src/vector2D.h @@ -0,0 +1,278 @@ +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#include +#include + +#define numPI 3.14159265 + +libnum::num32 sqrt_num32(libnum::num32 v) { + uint32_t t, q, b, r; + r = v.v; + b = 0x40000000; + q = 0; + while (b > 0x40) { + t = q + b; + if (r >= t) { + r -= t; + q = t + b; + } + r <<= 1; + b >>= 1; + } + q >>= 8; + libnum::num32 ret; + ret.v = q; + return ret; +} + +/* TO DO : rework these functions for sine and cosine calculation */ + +libnum::num32 cos_num32(libnum::num32 angle) { + // Taylor serie for cos(x) = 1 - x²/2! + x⁴/4! + x⁶/6! + x⁸/8! + ... + + // Cosine function is even + if (angle < libnum::num32(0)) + return cos_num32(-angle); + + // Look for an angle in the range [0, 2*pi [ + libnum::num32 anglereduced = angle; + while (anglereduced >= libnum::num32(2 * numPI)) + anglereduced -= libnum::num32(2 * numPI); + + // Exploit the symetry for angle and angle+Pi to reduce the order of the + // limited developpement + if (anglereduced >= libnum::num(numPI)) + return -cos_num32(anglereduced - libnum::num(numPI)); + + libnum::num32 sum = libnum::num32(1); + libnum::num32 angle2 = anglereduced * anglereduced; + + // set first value of the Taylor serie : x⁰/0! = 1/1 + libnum::num32 numerator = libnum::num32(1); + libnum::num32 denominator = libnum::num32(1); + + for (int i = 2; i <= 8; i += 2) { + numerator *= (-angle2); + denominator *= libnum::num32(i - 1) * libnum::num32(i); + sum += (numerator / denominator); + } + + return sum; +} + +libnum::num32 sin_num32(libnum::num32 angle) { + // Taylor serie for cos(x) = x/1! - x³/3! + x⁵/5! - x⁷/7! + x⁹/9! + ... + + // Sine function is odd + if (angle < libnum::num32(0)) + return -sin_num32(-angle); + + // Look for an angle in the range [0, 2*pi [ + libnum::num32 anglereduced = angle; + while (anglereduced >= libnum::num32(2 * numPI)) + anglereduced -= libnum::num32(2 * numPI); + + // Exploit the symetry for angle and angle+Pi to reduce the order of the + // limited developpement + if (anglereduced >= libnum::num(numPI)) + return -sin_num32(anglereduced - libnum::num(numPI)); + + libnum::num32 sum = anglereduced; + libnum::num32 angle2 = anglereduced * anglereduced; + + // set first value of the Taylor serie : x¹/1! = x/1 + libnum::num32 numerator = anglereduced; + libnum::num32 denominator = libnum::num32(1); + + for (int i = 2; i <= 8; i += 2) { + numerator *= (-angle2); + denominator *= libnum::num32(i) * libnum::num32(i + 1); + sum += (numerator / denominator); + } + + return sum; +} + +class Vector2D { + +public: + Vector2D() { + this->x = libnum::num32(0); + this->y = libnum::num32(0); + } + + Vector2D(float x, float y) { + this->x = libnum::num32(x); + this->y = libnum::num32(y); + } + + Vector2D(libnum::num32 x, libnum::num32 y) { + this->x = x; + this->y = y; + } + + Vector2D(const Vector2D &v) { + this->x = v.x; + this->y = v.y; + } + + ~Vector2D() {} + + void Set(Vector2D v) { + this->x = v.x; + this->y = v.y; + } + + void Normalise(void) { + libnum::num32 len = this->Length(); + this->x /= len; + this->y /= len; + } + + Vector2D Clone(void) { + Vector2D NewVector(this->x, this->y); + return NewVector; + } + + Vector2D MakeVector(Vector2D A, Vector2D B) { + Vector2D NewVector(B.x - A.x, B.y - A.y); + return NewVector; + } + + void AddVectors(Vector2D a, Vector2D b) { + this->x = a.x + b.x; + this->y = a.y + b.y; + } + + void Add(Vector2D v, libnum::num32 scale) { + this->x += v.x * scale; + this->y += v.y * scale; + } + + void SubtractVectors(Vector2D a, Vector2D b) { + this->x = a.x - b.x; + this->y = a.y - b.y; + } + + void Subtract(Vector2D v, libnum::num32 scale) { + this->x -= v.x * scale; + this->y -= v.y * scale; + } + + libnum::num32 Length(void) { + return sqrt_num32(this->x * this->x + this->y * this->y); + } + + void Scale(libnum::num32 scale) { + this->x *= scale; + this->y *= scale; + } + + libnum::num32 Dot(Vector2D v) { return (this->x * v.x + this->y * v.y); } + + libnum::num32 Det(Vector2D v) { return (this->x * v.y - this->y * v.x); } + + Vector2D PerpCW(void) { + Vector2D temp(-this->y, this->x); + return temp; + } + + Vector2D PerpCCW(void) { + Vector2D temp(this->y, -this->x); + return temp; + } + + /* overloading of most interesting operators */ + libnum::num32 operator[](uint8_t pos) { return pos == 0 ? x : y; } + + Vector2D &operator=(const Vector2D &v) { + this->x = v.x; + this->y = v.y; + return *this; + } + + Vector2D operator+(const Vector2D &v) const { + return Vector2D(x + v.x, y + v.y); + } + + Vector2D operator-(const Vector2D &v) const { + return Vector2D(x - v.x, y - v.y); + } + + Vector2D &operator+=(Vector2D const &other) { + this->x += other.x; + this->y += other.y; + return *this; + } + + Vector2D operator-() const { return (Vector2D(-x, -y)); } + + Vector2D operator+() const { return *this; } + + Vector2D &operator-=(Vector2D const &other) { + this->x -= other.x; + this->y -= other.y; + return *this; + } + + Vector2D &operator*=(libnum::num32 scale) { + this->x *= scale; + this->y *= scale; + return *this; + } + + Vector2D &operator/=(libnum::num32 scale) { + this->x /= scale; + this->y /= scale; + return *this; + } + + friend Vector2D operator*(libnum::num32 scale, Vector2D const &v) { + Vector2D r; + r.x = v.x * scale; + r.y = v.y * scale; + return r; + } + + friend Vector2D operator*(Vector2D const &v, libnum::num32 scale) { + Vector2D r; + r.x = v.x * scale; + r.y = v.y * scale; + return r; + } + + friend Vector2D operator/(Vector2D const &v, libnum::num32 scale) { + Vector2D r; + r.x = v.x / scale; + r.y = v.y / scale; + return r; + } + + libnum::num32 x; + libnum::num32 y; +}; + + +Vector2D ClosestPointOnSegment(Vector2D P, Vector2D A, Vector2D B) { + Vector2D AB = B - A; + + libnum::num32 t = AB.Dot(AB); + + if (t == 0) + return A; + + libnum::num32 t2 = (P.Dot(AB) - A.Dot(AB)) / t; + + if (t2 < libnum::num32(0)) + t2 = libnum::num32(0); + if (t2 > libnum::num32(1)) + t2 = libnum::num32(1); + + Vector2D C = A.Clone(); + C.Add(AB, t2); + + return C; +} + +#endif \ No newline at end of file