diff --git a/Crawler/Animation.h b/Crawler/Animation.h index 6f2a21db..08cf327f 100644 --- a/Crawler/Animation.h +++ b/Crawler/Animation.h @@ -17,5 +17,5 @@ enum AnimationState{ WARRIOR_SWINGSONICSWORD_S,WARRIOR_SWINGSONICSWORD_E,WARRIOR_SWINGSONICSWORD_N,WARRIOR_SWINGSONICSWORD_W, WIZARD_IDLE_ATTACK_S,WIZARD_IDLE_ATTACK_E,WIZARD_IDLE_ATTACK_N,WIZARD_IDLE_ATTACK_W, WIZARD_ATTACK_S,WIZARD_ATTACK_E,WIZARD_ATTACK_N,WIZARD_ATTACK_W, - ENERGY_BOLT,ENERGY_PARTICLE + ENERGY_BOLT,ENERGY_PARTICLE,SPLASH_EFFECT, }; \ No newline at end of file diff --git a/Crawler/Bullet.cpp b/Crawler/Bullet.cpp index 70848b26..b031e45b 100644 --- a/Crawler/Bullet.cpp +++ b/Crawler/Bullet.cpp @@ -5,11 +5,11 @@ INCLUDE_ANIMATION_DATA INCLUDE_game -Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,Pixel col) - :pos(pos),vel(vel),radius(radius),damage(damage),col(col){}; +Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col) + :pos(pos),vel(vel),radius(radius),damage(damage),col(col),friendly(friendly){}; -Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool hitsMultiple,float lifetime,bool rotatesWithAngle,Pixel col) - :pos(pos),vel(vel),radius(radius),damage(damage),col(col),animated(true),rotates(rotatesWithAngle),lifetime(lifetime),hitsMultiple(hitsMultiple){ +Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool hitsMultiple,float lifetime,bool rotatesWithAngle,bool friendly,Pixel col) + :pos(pos),vel(vel),radius(radius),damage(damage),col(col),animated(true),rotates(rotatesWithAngle),lifetime(lifetime),hitsMultiple(hitsMultiple),friendly(friendly){ this->animation.AddState(animation,ANIMATION_DATA[animation]); this->animation.ChangeState(internal_animState,animation); }; @@ -18,14 +18,28 @@ Animate2D::Frame Bullet::GetFrame(){ return animation.GetFrame(internal_animState); } -void Bullet::Update(float fElapsedTime){ +void Bullet::UpdateFadeTime(float fElapsedTime) +{ + if(fadeOutTime>0){ + if(fadeOutTimer==0){ + lifetime=fadeOutTime; + } + fadeOutTimer+=fElapsedTime; + } } +void Bullet::Update(float fElapsedTime){} + void Bullet::Draw(){ + auto lerp=[](uint8_t f1,uint8_t f2,float t){return uint8_t((float(f2)*t)+f1*(1-t));}; + if(animated){ - game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,{1,1},col); + game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,{1,1},fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))}); } else { - game->view.DrawDecal(pos,game->GFX_BulletCircle.Decal(),{radius,radius},col); - game->view.DrawDecal(pos,game->GFX_BulletCircleOutline.Decal(),{radius,radius},WHITE); + game->view.DrawDecal(pos,game->GFX_BulletCircle.Decal(),{radius,radius},fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))}); + game->view.DrawDecal(pos,game->GFX_BulletCircleOutline.Decal(),{radius,radius},fadeOutTime==0?WHITE:Pixel{WHITE.r,WHITE.g,WHITE.b,lerp(WHITE.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))}); } -} \ No newline at end of file +} + +bool Bullet::PlayerHit(Player&player){return true;} +bool Bullet::MonsterHit(Monster&monster){return true;} \ No newline at end of file diff --git a/Crawler/Bullet.h b/Crawler/Bullet.h index 67b2f128..52e1790a 100644 --- a/Crawler/Bullet.h +++ b/Crawler/Bullet.h @@ -7,6 +7,7 @@ #define INFINITE 999999 struct Bullet{ + friend class Crawler; vf2d pos; vf2d vel; float radius; @@ -16,14 +17,25 @@ struct Bullet{ bool hitsMultiple=false; bool rotates=false; bool animated=false; + bool deactivated=false; //A deactivated bullet no longer interacts with the world. It's just a visual. + float fadeOutTime=0; + bool friendly=false; //Whether or not it's a player bullet or enemy bullet. +private: + float fadeOutTimer=0; + void UpdateFadeTime(float fElapsedTime); +public: Animate2D::Animationanimation; Animate2D::AnimationState internal_animState; std::maphitList; - Bullet(vf2d pos,vf2d vel,float radius,int damage,Pixel col=WHITE); + Bullet(vf2d pos,vf2d vel,float radius,int damage,bool friendly=false,Pixel col=WHITE); //Initializes a bullet with an animation. - Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool hitsMultiple=false,float lifetime=INFINITE,bool rotatesWithAngle=false,Pixel col=WHITE); + Bullet(vf2d pos,vf2d vel,float radius,int damage,AnimationState animation,bool hitsMultiple=false,float lifetime=INFINITE,bool rotatesWithAngle=false,bool friendly=false,Pixel col=WHITE); public: virtual void Update(float fElapsedTime); + //Return true when the bullet should be destroyed. Return false to handle it otherwise (like deactivating it instead). You become responsible for getting rid of the bullet. + virtual bool PlayerHit(Player&player); + //Return true when the bullet should be destroyed. Return false to handle it otherwise (like deactivating it instead). You become responsible for getting rid of the bullet. + virtual bool MonsterHit(Monster&monster); Animate2D::Frame GetFrame(); void Draw(); }; \ No newline at end of file diff --git a/Crawler/BulletTypes.h b/Crawler/BulletTypes.h index c41c53eb..40557cdd 100644 --- a/Crawler/BulletTypes.h +++ b/Crawler/BulletTypes.h @@ -3,6 +3,8 @@ struct EnergyBolt:public Bullet{ float lastParticleSpawn=0; - EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,Pixel col=WHITE); + EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly=false,Pixel col=WHITE); void Update(float fElapsedTime)override; + bool PlayerHit(Player&player)override; + bool MonsterHit(Monster&monster)override; }; \ No newline at end of file diff --git a/Crawler/Class.cpp b/Crawler/Class.cpp index ccdf88fd..f2b14c50 100644 --- a/Crawler/Class.cpp +++ b/Crawler/Class.cpp @@ -147,7 +147,7 @@ bool Warrior::Ability3(){ p.UpdateAnimation(AnimationState::WARRIOR_SWINGSONICSWORD_S); }break; } - PLAYER_BULLET_LIST.push_back(std::make_unique(p.pos,bulletVel,30,p.GetAttack()*8,AnimationState::SONICSLASH,true,2.25,true)); + PLAYER_BULLET_LIST.push_back(std::make_unique(p.pos,bulletVel,30,p.GetAttack()*8,AnimationState::SONICSLASH,true,2.25,true,true,WHITE)); game->SetupWorldShake(0.5); return true; } @@ -283,7 +283,7 @@ bool Wizard::AutoAttack(){ ACCESS_PLAYER p.attack_cooldown_timer=p.MAGIC_ATTACK_COOLDOWN; float angleToCursor=atan2(game->GetWorldMousePos().y-p.pos.y,game->GetWorldMousePos().x-p.pos.x); - PLAYER_BULLET_LIST.push_back(std::make_unique(EnergyBolt(p.pos,{cos(angleToCursor)*200,sin(angleToCursor)*200},12,p.GetAttack()))); + PLAYER_BULLET_LIST.push_back(std::make_unique(EnergyBolt(p.pos,{cos(angleToCursor)*200,sin(angleToCursor)*200},12,p.GetAttack(),true,WHITE))); return true; } diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index 3f037e3e..b30b3386 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -60,6 +60,7 @@ bool Crawler::OnUserCreate(){ GFX_BulletCircleOutline.Load("assets/circle_outline.png"); GFX_EnergyBolt.Load("assets/energy_bolt.png"); GFX_EnergyParticle.Load("assets/energy_particle.png"); + GFX_Splash_Effect.Load("assets/splash_effect.png"); //Animations InitializeAnimations(); @@ -355,6 +356,12 @@ void Crawler::InitializeAnimations(){ energy_particle.AddFrame({&GFX_EnergyParticle,{{i*3,0},{3,3}}}); } ANIMATION_DATA[AnimationState::ENERGY_PARTICLE]=energy_particle; + + Animate2D::FrameSequence splash_animation(0.05); + for(int i=0;i<5;i++){ + splash_animation.AddFrame({&GFX_Splash_Effect,{{i*24,0},{24,24}}}); + } + ANIMATION_DATA[AnimationState::SPLASH_EFFECT]=splash_animation; } bool Crawler::LeftHeld(){ @@ -597,18 +604,21 @@ void Crawler::UpdateEffects(float fElapsedTime){ void Crawler::UpdateBullets(float fElapsedTime){ for(auto it=BULLET_LIST.begin();it!=BULLET_LIST.end();++it){ Bullet*b=(*it).get(); + b->UpdateFadeTime(fElapsedTime); b->Update(fElapsedTime); b->pos+=b->vel*fElapsedTime; - if(geom2d::overlaps(geom2d::circle(player.GetPos(),12*player.GetSizeMult()/2),geom2d::circle(b->pos,b->radius))){ + if(!b->deactivated&&geom2d::overlaps(geom2d::circle(player.GetPos(),12*player.GetSizeMult()/2),geom2d::circle(b->pos,b->radius))){ if(player.Hurt(b->damage)){ - it=BULLET_LIST.erase(it); - if(it==BULLET_LIST.end()){ - break; + if(b->PlayerHit(player)){ + it=BULLET_LIST.erase(it); + if(it==BULLET_LIST.end()){ + break; + } } continue; } } - if(b->pos.xpos.x>view.GetWorldBR().x||b->pos.ypos.y>view.GetWorldBR().y){ + if(b->pos.x+b->radiuspos.x-b->radius>view.GetWorldBR().x||b->pos.y+b->radiuspos.y-b->radius>view.GetWorldBR().y){ it=BULLET_LIST.erase(it); if(it==BULLET_LIST.end()){ break; @@ -627,19 +637,24 @@ void Crawler::UpdateBullets(float fElapsedTime){ } for(std::vector>::iterator it=PLAYER_BULLET_LIST.begin();it!=PLAYER_BULLET_LIST.end();++it){ std::unique_ptr&b=*it; + b->UpdateFadeTime(fElapsedTime); b->Update(fElapsedTime); b->pos+=b->vel*fElapsedTime; - for(Monster&m:MONSTER_LIST){ - if(geom2d::overlaps(geom2d::circle(m.GetPos(),12*m.GetSizeMult()),geom2d::circle(b->pos,b->radius))){ - if(b->hitList.find(&m)==b->hitList.end()&&m.Hurt(b->damage)){ - if(!b->hitsMultiple){ - it=PLAYER_BULLET_LIST.erase(it); - if(it==PLAYER_BULLET_LIST.end()){ - goto outsidePlayerBulletLoop; + if(!b->deactivated){ + for(Monster&m:MONSTER_LIST){ + if(geom2d::overlaps(geom2d::circle(m.GetPos(),12*m.GetSizeMult()),geom2d::circle(b->pos,b->radius))){ + if(b->hitList.find(&m)==b->hitList.end()&&m.Hurt(b->damage)){ + if(!b->hitsMultiple){ + if(b->MonsterHit(m)){ + it=PLAYER_BULLET_LIST.erase(it); + if(it==PLAYER_BULLET_LIST.end()){ + goto outsidePlayerBulletLoop; + } + } + goto continuePlayerBulletLoop; } - goto continuePlayerBulletLoop; + b->hitList[&m]=true; } - b->hitList[&m]=true; } } } diff --git a/Crawler/Crawler.h b/Crawler/Crawler.h index 3fc0db9a..a191e080 100644 --- a/Crawler/Crawler.h +++ b/Crawler/Crawler.h @@ -22,7 +22,8 @@ class Crawler : public olc::PixelGameEngine Renderable GFX_Warrior_Sheet,GFX_Slime_Sheet,GFX_Circle, GFX_Effect_GroundSlam_Back,GFX_Effect_GroundSlam_Front, GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet, - GFX_Battlecry_Effect,GFX_Mana,GFX_SonicSlash,GFX_EnergyParticle; + GFX_Battlecry_Effect,GFX_Mana,GFX_SonicSlash,GFX_EnergyParticle, + GFX_Splash_Effect; public: Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt; private: diff --git a/Crawler/EnergyBolt.cpp b/Crawler/EnergyBolt.cpp index 19af65da..dcad7bac 100644 --- a/Crawler/EnergyBolt.cpp +++ b/Crawler/EnergyBolt.cpp @@ -5,8 +5,8 @@ INCLUDE_game -EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,Pixel col) -:Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,false,INFINITE,true,col){} +EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool friendly,Pixel col) +:Bullet(pos,vel,radius,damage,AnimationState::ENERGY_BOLT,false,INFINITE,true,friendly,col){} void EnergyBolt::Update(float fElapsedTime){ lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); @@ -14,4 +14,20 @@ void EnergyBolt::Update(float fElapsedTime){ lastParticleSpawn=0.03; game->AddEffect(Effect(pos,float(rand()%500)/500,AnimationState::ENERGY_PARTICLE,float(rand()%1000)/500,0.5,{float(rand()%60)-30,float(rand()%60)-30})); } -} \ No newline at end of file +} + +bool EnergyBolt::PlayerHit(Player& player) +{ + deactivated=true; + fadeOutTime=0.2f; + game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,player.GetSizeMult(),0.25)); + return false; +} + +bool EnergyBolt::MonsterHit(Monster& monster) +{ + deactivated=true; + fadeOutTime=0.2f; + game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,monster.GetSizeMult(),0.25)); + return false; +} diff --git a/Crawler/Monster.cpp b/Crawler/Monster.cpp index 71ad4f36..6aca2d13 100644 --- a/Crawler/Monster.cpp +++ b/Crawler/Monster.cpp @@ -155,7 +155,7 @@ bool Monster::Update(float fElapsedTime){ if(queueShotTimer<0){ queueShotTimer=0; { - BULLET_LIST.push_back(std::make_unique(Bullet(pos + vf2d{ 0,-4 }, geom2d::line(pos + vf2d{ 0,-4 }, game->GetPlayer().GetPos()).vector().norm() * 24 * 3.f, 2, GetAttack(), { 75 / 2,162 / 2,225 / 2 }))); + BULLET_LIST.push_back(std::make_unique(Bullet(pos + vf2d{ 0,-4 }, geom2d::line(pos + vf2d{ 0,-4 }, game->GetPlayer().GetPos()).vector().norm() * 24 * 3.f, 2, GetAttack(),false, { 75 / 2,162 / 2,225 / 2 }))); } } } diff --git a/Crawler/Version.h b/Crawler/Version.h index 9953e422..515af79c 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -2,7 +2,7 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 0 -#define VERSION_BUILD 373 +#define VERSION_BUILD 391 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/assets/splash_effect.png b/Crawler/assets/splash_effect.png new file mode 100644 index 00000000..d84bed80 Binary files /dev/null and b/Crawler/assets/splash_effect.png differ