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 0000000..9f404d2 Binary files /dev/null and b/assets-cg/Sprites/Boss/BossGun.png differ diff --git a/assets-cg/Sprites/Bullets/bullet_enemy_blue.png b/assets-cg/Sprites/Bullets/bullet_enemy_blue.png index 33456cb..4e7b05f 100644 Binary files a/assets-cg/Sprites/Bullets/bullet_enemy_blue.png and b/assets-cg/Sprites/Bullets/bullet_enemy_blue.png differ 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 0000000..ba01300 Binary files /dev/null and b/assets-cg/Sprites/Bullets/bullet_enemy_green.png differ diff --git a/assets-cg/Sprites/Bullets/bullet_enemy_red.png b/assets-cg/Sprites/Bullets/bullet_enemy_red.png new file mode 100644 index 0000000..2c31146 Binary files /dev/null and b/assets-cg/Sprites/Bullets/bullet_enemy_red.png differ diff --git a/captures/fxlink-image-2023.08.14-13h38-14.png b/captures/fxlink-image-2023.08.14-13h38-14.png deleted file mode 100644 index de27b17..0000000 Binary files a/captures/fxlink-image-2023.08.14-13h38-14.png and /dev/null differ diff --git a/captures/fxlink-image-2023.08.14-13h38-17.png b/captures/fxlink-image-2023.08.14-13h38-17.png deleted file mode 100644 index 19fcc8e..0000000 Binary files a/captures/fxlink-image-2023.08.14-13h38-17.png and /dev/null differ 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 376855b..0000000 Binary files a/captures/fxlink-image-2023.08.14-13h38-41.png and /dev/null differ 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