Working on implementation of Boss with multiple parts to be exploded [WIP]

This commit is contained in:
Sylvain PILLOT 2023-08-13 17:33:25 +02:00
parent e6c1e93874
commit 36bce711cc
7 changed files with 379 additions and 7 deletions

View File

@ -43,7 +43,7 @@ set(SOURCES
src/starfieldshader.cpp
src/background.cpp
src/bonus.cpp
src/boss.cpp
src/point2D.cpp
src/trajectory.cpp
@ -71,6 +71,8 @@ set(ASSETS_cg
assets-cg/Sprites/Enemies/mainship2.png
assets-cg/Sprites/Enemies/Enemy_Blue_Lvl1.png
assets-cg/Sprites/Enemies/Enemy_Red_Lvl1.png
assets-cg/Sprites/Boss/Boss1.png
assets-cg/Levels/tileset.png
assets-cg/Levels/Level2.json

View File

@ -27,7 +27,7 @@ The SHMUP Todo list :
# Bosses
- Créer des bosses avec différentes zones, mobiles les unes par rapport aux autres
- Créer des hitboxes pour chacune des zones du boss avec différentes sensibilités (par exemple le coeur/générateur = zone critique, mais mieux défendues)
- Créer des protections des certaines zones qui peuvent "sauter" (boucliers qui s'usent)
- Créer des protections pour certaines zones qui peuvent "sauter" (boucliers qui s'usent)
# Autres :
- plein de trucs dont boss "multi-morceaux et multi-hitboxes"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,5 @@
*.png:
type: bopti-image
name_regex: (.*)\.png img_\1
section: .data
profile: p8_rgb565a

264
src/boss.cpp Normal file
View File

@ -0,0 +1,264 @@
#include "boss.h"
#include "bullet.h"
#include <cstdint>
#include <num/num.h>
#include <gint/rtc.h>
#include <sys/types.h>
#include "fast_trig.h"
#include <gint/gint.h>
#include "collections.h"
extern bopti_image_t img_Lifebar;
extern bopti_image_t img_Boss1;
#define NB_PIECES_BOSS 12
libnum::num XdataBossInternal[NB_PIECES_BOSS];
libnum::num YdataBossInternal[NB_PIECES_BOSS];
libnum::num XdataBossExternal[NB_PIECES_BOSS];
libnum::num YdataBossExternal[NB_PIECES_BOSS];
BossPart Pieces[NB_PIECES_BOSS*2];
#include <stdio.h>
void savedata( void )
{
FILE* exportfp = fopen("databosPtxt", "w" );
if(exportfp)
{
fprintf(exportfp, "Points : \n" );
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
fprintf(exportfp, "Ext[ %d ] : X= %d - Y= %d \n", i, (int) XdataBossExternal[i], (int) YdataBossExternal[i] );
}
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
fprintf(exportfp, "Int[ %d ] : X= %d - Y= %d \n", i, (int) XdataBossInternal[i], (int) YdataBossInternal[i] );
}
fprintf(exportfp, "Triangles : \n" );
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
fprintf(exportfp, "Tri ext[ %d ] : P1= %d - P2= %d - P3= %d \n", i, Pieces[2*i].P1, Pieces[2*i].P2, Pieces[2*i].P3 );
}
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
fprintf(exportfp, "Tri int[ %d ] : P1= %d - P2= %d - P3= %d \n", i, Pieces[2*i+1].P1, Pieces[2*i+1].P2, Pieces[2*i+1].P3 );
}
fclose( exportfp );
}
}
bool Is_Point_Inside_Triangle( int Px, int Py, int P1x, int P1y, int P2x, int P2y, int P3x, int P3y )
{
int as_x = Px - P1x;
int as_y = Py - P1y;
bool s_ab = (P2x - P1x) * as_y - (P2y - P1y) * as_x > 0;
if ((P3x - P1x) * as_y - (P3y - P1y) * as_x > 0 == s_ab)
return false;
if ((P3x - P2x) * (Py - P2y) - (P3y - P2y)*(Px - P2x) > 0 != s_ab)
return false;
return true;
}
Boss::Boss( int16_t _x, int16_t _y, uint8_t _id )
{
x = libnum::num(_x);
y = libnum::num(_y);
ID = _id;
speed = 10;
toberemoved = false;
width = img_Boss1.width/2;
height = img_Boss1.height/2;
xmin = (int) x - width;
xmax = (int) x + width;
ymin = (int) y - height;
ymax = (int) y + height;
if (ID==0)
{
life = 1000;
life0 = 1000;
}
lastshoot0 = rtc_ticks();
lastshoot1 = rtc_ticks();
lastshoot2 = rtc_ticks();
radiusInt = libnum::num( 75 );
radiusExt = libnum::num( 100 );
rotAngle = 0.0f;
rotSpeed = 2;
this->Update(0.0f);
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
Pieces[i*2].P1 = i%NB_PIECES_BOSS; //exterior circle
Pieces[i*2].P2 = (i+1)%NB_PIECES_BOSS; //exterior circle
Pieces[i*2].P3 = (i+1)%NB_PIECES_BOSS; //interior circle
Pieces[i*2].life = 100;
Pieces[i*2].toberemoved = false;
Pieces[i*2].color = 0xbdf7; //light gray
Pieces[i*2+1].P1 = i%NB_PIECES_BOSS; //interior circle
Pieces[i*2+1].P2 = (i+1)%NB_PIECES_BOSS; //interior circle
Pieces[i*2+1].P3 = i%NB_PIECES_BOSS; //exterior circle
Pieces[i*2+1].life = 100;
Pieces[i*2+1].toberemoved = false;
Pieces[i*2+1].color = 0x528a; //darker gray
}
/* FOR DEBUGGING */
// gint_world_switch( GINT_CALL( savedata ) );
}
Boss::~Boss()
{
}
void Boss::Update( float dt )
{
xmin = (int) x - width;
xmax = (int) x + width;
ymin = (int) y - height;
ymax = (int) y + height;
rotAngle += rotSpeed * dt / 25000.0f;
if (rotAngle>360.0f) rotAngle-=360.0f;
uint16_t angleint = (uint16_t) rotAngle;
uint16_t angledelta = (uint16_t) (360/NB_PIECES_BOSS);
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
XdataBossInternal[ i ] = this->x + this->radiusInt * FastCosInt( angleint );
YdataBossInternal[ i ] = this->y + this->radiusInt * FastSinInt( angleint );
angleint += angledelta;
if (angleint>=360) angleint -= 360;
}
// Pour le cercle Exterieur on se décale d'un demi-incrément d'angle pour le sommet du triangle
angleint = (uint16_t) rotAngle + angledelta/2;
if (angleint>=360) angleint -= 360;
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
XdataBossExternal[ i ] = this->x + this->radiusExt * FastCosInt( angleint );
YdataBossExternal[ i ] = this->y + this->radiusExt * FastSinInt( angleint );
angleint += angledelta;
if (angleint>=360) angleint -= 360;
}
}
void Boss::Render( void )
{
if (ID==0 && toberemoved==false)
{
for( int i=0; i<NB_PIECES_BOSS; i++ )
{
if (Pieces[i*2].toberemoved == false)
azrp_triangle( (int) XdataBossExternal[ Pieces[i*2].P1 ], (int) YdataBossExternal[ Pieces[i*2].P1 ],
(int) XdataBossExternal[ Pieces[i*2].P2 ], (int) YdataBossExternal[ Pieces[i*2].P2 ],
(int) XdataBossInternal[ Pieces[i*2].P3 ], (int) YdataBossInternal[ Pieces[i*2].P3 ],
Pieces[i*2].color );
if (Pieces[i*2+1].toberemoved == false)
azrp_triangle( (int) XdataBossInternal[ Pieces[i*2+1].P1 ], (int) YdataBossInternal[ Pieces[i*2+1].P1 ],
(int) XdataBossInternal[ Pieces[i*2+1].P2 ], (int) YdataBossInternal[ Pieces[i*2+1].P2 ],
(int) XdataBossExternal[ Pieces[i*2+1].P3 ], (int) YdataBossExternal[ Pieces[i*2+1].P3 ],
Pieces[i*2+1].color );
}
azrp_image_p8_effect(xmin, ymin, &img_Boss1, DIMAGE_NONE);
if (life>life0*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 )
{
for( int i=0; i< NB_PIECES_BOSS; i++ )
{
if (Pieces[i*2].toberemoved == false)
{
if (Is_Point_Inside_Triangle( (int) projectile->x, (int) projectile->y,
(int) XdataBossExternal[ Pieces[i*2].P1 ], (int) YdataBossExternal[ Pieces[i*2].P1 ],
(int) XdataBossExternal[ Pieces[i*2].P2 ], (int) YdataBossExternal[ Pieces[i*2].P2 ],
(int) XdataBossInternal[ Pieces[i*2].P3 ], (int) YdataBossInternal[ Pieces[i*2].P3 ] ))
{
Pieces[i*2].life -= projectile->strength;
if (Pieces[i*2].life<=0)
{
Pieces[i*2].toberemoved = true;
Create_Explosion( (int) projectile->x, (int) projectile->y );
}
projectile->toberemoved = true;
return true;
}
}
if (Pieces[i*2+1].toberemoved == false)
{
if (Is_Point_Inside_Triangle( (int) projectile->x, (int) projectile->y,
(int) XdataBossInternal[ Pieces[i*2+1].P1 ], (int) YdataBossInternal[ Pieces[i*2+1].P1 ],
(int) XdataBossInternal[ Pieces[i*2+1].P2 ], (int) YdataBossInternal[ Pieces[i*2+1].P2 ],
(int) XdataBossExternal[ Pieces[i*2+1].P3 ], (int) YdataBossExternal[ Pieces[i*2+1].P3 ] ))
{
Pieces[i*2+1].life -= projectile->strength;
if (Pieces[i*2+1].life<=0)
{
Pieces[i*2+1].toberemoved = true;
Create_Explosion( (int) projectile->x, (int) projectile->y );
}
projectile->toberemoved = true;
return true;
}
}
}
if (projectile->x >= xmin && projectile->x <= xmax && projectile->y >= ymin && projectile->y <= ymax )
{
life -= projectile->strength;
if (life<0) toberemoved = true;
projectile->toberemoved = true;
return true;
}
else return false;
}

55
src/boss.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef BOSS_H
#define BOSS_H
#include <azur/azur.h>
#include <azur/gint/render.h>
#include <cstdint>
#include <stdlib.h>
#include <num/num.h>
#include <sys/types.h>
#include "bullet.h"
typedef struct
{
uint8_t P1, P2, P3;
uint16_t life;
bool toberemoved;
int color;
} BossPart;
class Boss
{
public:
Boss( int16_t _x, int16_t _y, uint8_t _id );
~Boss();
void Update( float dt );
void Render( void );
bool Test_Impact( Bullet *projectile );
libnum::num x, y; // center position of the boss
uint8_t width, height; // width and height -for the hitbox
int16_t xmin, xmax, ymin, ymax; // square hitbox (to speed up the bullet impact calculations)
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;
uint8_t rotSpeed;
bool toberemoved;
private:
float rotAngle;
libnum::num radiusInt, radiusExt;
};
#endif

View File

@ -1,6 +1,7 @@
#define DEBUG_MODE 0
#define USB 1
#define MORE_RAM 1
#define CALCEMU 0
#include <azur/azur.h>
#include <azur/gint/render.h>
@ -43,7 +44,7 @@
#include "bonus.h"
#include "impact.h"
#include "background.h"
#include "boss.h"
#include "trajectory.h"
#include <vector>
@ -89,6 +90,7 @@ std::vector<Bonus*> MyBonuses;
Background MyBackground;
Player *MyPlayer;
Boss *MyBoss;
KeyboardExtra MyKeyboard;
@ -164,6 +166,24 @@ static void update( float dt )
delete( MyEnemies[i] );
MyEnemies.erase( MyEnemies.begin() + i );
}
if (MyBoss)
{
if (MyBoss->toberemoved == true)
{
Bonus *b = new Bonus( (int) MyBoss->x, (int) MyBoss->y, rand() % 2 );
MyBonuses.push_back( b );
Create_Explosion( (int) MyBoss->x, (int) MyBoss->y );
delete( MyBoss );
MyBoss=nullptr;
}
}
}
if (MyBoss)
{
MyBoss->Update( dt );
}
for(unsigned int i=0; i<MyParticles.size(); i++)
@ -191,6 +211,14 @@ static void update( float dt )
}
}
if (MyBoss)
if(MyBoss->Test_Impact(MyPlayerBullets[i])==true)
{
//TODO : we can create a list of impacts here, to be rendered later on
Create_Impact( (int) MyPlayerBullets[i]->x, (int) MyPlayerBullets[i]->y );
}
// Check if the property toberemoved has been set to "true" for particle deletion
if (MyPlayerBullets[i]->toberemoved == true)
{
@ -292,7 +320,6 @@ static void render( void )
static void get_inputs( float dt )
{
uint8_t speed = 4;
uint32_t tempshoot = rtc_ticks();
if(MyKeyboard.IsKeyPressed(MYKEY_F1))
@ -340,7 +367,7 @@ static void get_inputs( float dt )
bool AddMoreRAM( void )
{
#if(MORE_RAM)
#if(MORE_RAM && !CALCEMU)
/* allow more RAM */
char const *osv = (char*) 0x80020020;
@ -386,11 +413,24 @@ bool AddMoreRAM( void )
kmalloc_add_arena(&extended_ram );
return true;
}
#elif (MORE_RAM && CALCEMU)
extended_ram.name = "extram";
extended_ram.is_default = true;
extended_ram.start = (void *)0x8c200000;
extended_ram.end = (void *)0x8c4e0000 ;
kmalloc_init_arena(&extended_ram, true);
kmalloc_add_arena(&extended_ram );
return true;
#else
return false;
#endif
return false;
}
void FreeMoreRAM( void )
@ -429,7 +469,7 @@ int main(void)
_uram = kmalloc_get_arena("_uram");
#endif
bool canWeAllocate3Mb = AddMoreRAM();
bool canWeAllocateMoreRam = AddMoreRAM();
__printf_enable_fp();
__printf_enable_fixed();
@ -447,6 +487,8 @@ int main(void)
MyPlayer = new Player( azrp_width/4, azrp_height/2, 0);
MyBoss = new Boss( 3*azrp_width/4, azrp_height/2, 0);
/*
#if(DBGCRSH)
debug_crash( 1 );
@ -475,6 +517,8 @@ int main(void)
// update as per the time spend to do the loop
update( elapsedTime );
MyBoss->Update(elapsedTime);
// update the RAM consumption status
#if(MORE_RAM)
_uram_stats = kmalloc_get_gint_stats(_uram);
@ -494,6 +538,8 @@ int main(void)
render();
MyBoss->Render();
azrp_update();
}
@ -533,7 +579,7 @@ int main(void)
usb_close();
#endif
FreeMoreRAM( );
if (canWeAllocateMoreRam) FreeMoreRAM( );
return 1;
}