diff --git a/assets/burnmeter.png b/assets/burnmeter.png new file mode 100644 index 0000000..1fa24d2 Binary files /dev/null and b/assets/burnmeter.png differ diff --git a/assets/drownmeter.png b/assets/drownmeter.png new file mode 100644 index 0000000..48b9eee Binary files /dev/null and b/assets/drownmeter.png differ diff --git a/src/Hamster.cpp b/src/Hamster.cpp index e3c5e39..9c11d24 100644 --- a/src/Hamster.cpp +++ b/src/Hamster.cpp @@ -58,6 +58,7 @@ Hamster::Hamster(const vf2d spawnPos,const std::string_view img,const PlayerCont void Hamster::UpdateHamsters(const float fElapsedTime){ for(Hamster&h:HAMSTER_LIST){ + h.lastSafeLocationTimer=std::max(0.f,h.lastSafeLocationTimer-fElapsedTime); h.animations.UpdateState(h.internalAnimState,fElapsedTime); h.frictionEnabled=true; h.bumpTimer-=fElapsedTime; @@ -74,6 +75,49 @@ void Hamster::UpdateHamsters(const float fElapsedTime){ h.state=NORMAL; } }break; + case DROWNING:{ + if(h.imgScale>0.f){ + h.shrinkEffectColor=BLACK; + h.imgScale=std::max(0.f,h.imgScale-0.5f*fElapsedTime); + } + else{ + h.waitTimer=4.f; + h.state=WAIT; + } + }break; + case WAIT:{ + h.waitTimer=std::max(0.f,h.waitTimer-fElapsedTime); + if(h.waitTimer<=0.f){ + h.imgScale=1.f; + h.drownTimer=0.f; + h.pos=h.lastSafeLocation; + h.state=NORMAL; + h.RemoveAllPowerups(); + } + }break; + case BURNING:{ + if(h.imgScale>0.f){ + h.shrinkEffectColor=RED; + h.imgScale=std::max(0.f,h.imgScale-0.5f*fElapsedTime); + }else{ + h.waitTimer=4.f; + h.state=WAIT; + } + }break; + } + if((h.GetTerrainStandingOn()==Terrain::OCEAN||!h.HasPowerup(Powerup::SWAMP)&&h.GetTerrainStandingOn()==Terrain::SWAMP)&&h.state!=DROWNING&&h.state!=WAIT)h.drownTimer+=fElapsedTime; + else if((!h.HasPowerup(Powerup::LAVA)&&h.GetTerrainStandingOn()==Terrain::LAVA)&&h.state!=BURNING&&h.state!=WAIT)h.burnTimer+=fElapsedTime; + else if(h.lastSafeLocationTimer<=0.f&&h.state==NORMAL&&!h.StandingOnLethalTerrain()){ + h.lastSafeLocationTimer=0.5f; + h.drownTimer=0.f; + h.burnTimer=0.f; + h.lastSafeLocation=h.GetPos(); + } + if(h.drownTimer>=h.DEFAULT_DROWN_TIME&&h.state!=DROWNING&&h.state!=WAIT){ + h.state=DROWNING; + } + if(h.burnTimer>=h.DEFAULT_BURN_TIME&&h.state!=BURNING&&h.state!=WAIT){ + h.state=BURNING; } h.TurnTowardsTargetDirection(); h.MoveHamster(); @@ -99,9 +143,9 @@ void Hamster::DrawHamsters(TransformedView&tv){ const Animate2D::Frame&img{h.animations.GetState(h.internalAnimState)==HamsterGame::DEFAULT?anim.GetFrame(h.distanceTravelled/100.f):h.GetCurrentAnimation()}; const Animate2D::Frame&wheelTopImg{wheelTopAnim.GetFrame(h.distanceTravelled/80.f)}; const Animate2D::Frame&wheelBottomImg{wheelBottomAnim.GetFrame(h.distanceTravelled/80.f)}; - if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos,wheelBottomImg.GetSourceImage()->Decal(),h.rot,wheelBottomImg.GetSourceRect().size/2,wheelBottomImg.GetSourceRect().pos,wheelBottomImg.GetSourceRect().size); - tv.DrawPartialRotatedDecal(h.pos,img.GetSourceImage()->Decal(),h.rot,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size); - if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos,wheelTopImg.GetSourceImage()->Decal(),h.rot,wheelTopImg.GetSourceRect().size/2,wheelTopImg.GetSourceRect().pos,wheelTopImg.GetSourceRect().size,{1.f,1.f},{255,255,255,192}); + if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos,wheelBottomImg.GetSourceImage()->Decal(),h.rot,wheelBottomImg.GetSourceRect().size/2,wheelBottomImg.GetSourceRect().pos,wheelBottomImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); + tv.DrawPartialRotatedDecal(h.pos,img.GetSourceImage()->Decal(),h.rot,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); + if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos,wheelTopImg.GetSourceImage()->Decal(),h.rot,wheelTopImg.GetSourceRect().size/2,wheelTopImg.GetSourceRect().pos,wheelTopImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,{255,255,255,192},h.imgScale)); } } @@ -256,4 +300,25 @@ void Hamster::ObtainPowerup(const Powerup::PowerupType powerup){ } const bool Hamster::HasPowerup(const Powerup::PowerupType powerup)const{ return powerups.count(powerup); +} + +void Hamster::RemoveAllPowerups(){ + powerups.clear(); +} + +const bool Hamster::StandingOnLethalTerrain()const{ + return GetTerrainStandingOn()==Terrain::LAVA||GetTerrainStandingOn()==Terrain::OCEAN||GetTerrainStandingOn()==Terrain::SWAMP; +} + +const bool Hamster::IsDrowning()const{ + return drownTimer>0.f; +} +const bool Hamster::IsBurning()const{ + return burnTimer>0.f; +} +const float Hamster::GetDrownRatio()const{ + return drownTimer/DEFAULT_DROWN_TIME; +} +const float Hamster::GetBurnRatio()const{ + return burnTimer/DEFAULT_BURN_TIME; } \ No newline at end of file diff --git a/src/Hamster.h b/src/Hamster.h index 0f79c1b..87354a7 100644 --- a/src/Hamster.h +++ b/src/Hamster.h @@ -52,6 +52,10 @@ class Hamster{ enum HamsterState{ NORMAL, BUMPED, + DROWNING, + FLYING, + WAIT, + BURNING, }; static std::vectorHAMSTER_LIST; @@ -67,15 +71,24 @@ class Hamster{ const float DEFAULT_FRICTION{400.f}; const float DEFAULT_TURN_SPD{2.f*geom2d::pi}; const float DEFAULT_BUMP_AMT{100.f}; + const float DEFAULT_DROWN_TIME{5.f}; + const float DEFAULT_BURN_TIME{0.3f}; vf2d pos; vf2d vel; + vf2d lastSafeLocation{}; + float lastSafeLocationTimer{}; float rot{}; float targetRot{}; bool frictionEnabled{false}; float collisionRadius{12.f}; float bumpTimer{}; + float waitTimer{}; double distanceTravelled{}; + float drownTimer{}; + float burnTimer{}; + float imgScale{1.f}; + Pixel shrinkEffectColor{BLACK}; std::string img; Animate2D::Animationanimations; Animate2D::AnimationState internalAnimState; @@ -104,4 +117,10 @@ public: const float GetBumpAmount()const; void ObtainPowerup(const Powerup::PowerupType powerup); const bool HasPowerup(const Powerup::PowerupType powerup)const; + void RemoveAllPowerups(); + const bool StandingOnLethalTerrain()const; + const bool IsDrowning()const; + const bool IsBurning()const; + const float GetDrownRatio()const; + const float GetBurnRatio()const; }; \ No newline at end of file diff --git a/src/HamsterGame.cpp b/src/HamsterGame.cpp index 2b8778c..e48e8f5 100644 --- a/src/HamsterGame.cpp +++ b/src/HamsterGame.cpp @@ -39,6 +39,8 @@ void HamsterGame::LoadGraphics(){ _LoadImage("border.png"); _LoadImage("gametiles.png"); _LoadImage("shadow.png"); + _LoadImage("drownmeter.png"); + _LoadImage("burnmeter.png"); } void HamsterGame::LoadAnimations(){ @@ -109,23 +111,35 @@ void HamsterGame::DrawGame(){ DrawStringDecal(SCREEN_FRAME.pos+vf2d{1,1},"Terrain Type: "+Terrain::TerrainToString(Hamster::GetPlayer().GetTerrainStandingOn()),BLACK); DrawStringDecal(SCREEN_FRAME.pos,"Terrain Type: "+Terrain::TerrainToString(Hamster::GetPlayer().GetTerrainStandingOn())); - for(int y:std::ranges::iota_view(0,4)){ - for(int x:std::ranges::iota_view(0,2)){ - const int powerupInd{y*2+x}; - const float drawX{x*32.f+12.f}; - const float drawY{y*32.f+12.f+96.f}; - const Powerup::PowerupType powerupType{Powerup::PowerupType(powerupInd)}; - const geom2d::rectpowerupSubimageRect{Powerup::GetPowerupSubimageRect(powerupType)}; - if(Hamster::GetPlayer().HasPowerup(powerupType)){ - SetDecalMode(DecalMode::ADDITIVE); - DrawPartialRotatedDecal(vf2d{drawX,drawY}+16,GetGFX("gametiles.png").Decal(),0.f,{16.f,16.f},powerupSubimageRect.pos,powerupSubimageRect.size,{1.1f,1.1f}); - SetDecalMode(DecalMode::NORMAL); - DrawPartialDecal({drawX,drawY},GetGFX("gametiles.png").Decal(),powerupSubimageRect.pos,powerupSubimageRect.size); - }else{ - DrawPartialDecal({drawX,drawY},GetGFX("gametiles.png").Decal(),powerupSubimageRect.pos,powerupSubimageRect.size,{1.f,1.f},VERY_DARK_GREY); + #pragma region Powerup Display + for(int y:std::ranges::iota_view(0,4)){ + for(int x:std::ranges::iota_view(0,2)){ + const int powerupInd{y*2+x}; + const float drawX{x*32.f+12.f}; + const float drawY{y*32.f+12.f+96.f}; + const Powerup::PowerupType powerupType{Powerup::PowerupType(powerupInd)}; + const geom2d::rectpowerupSubimageRect{Powerup::GetPowerupSubimageRect(powerupType)}; + if(Hamster::GetPlayer().HasPowerup(powerupType)){ + SetDecalMode(DecalMode::ADDITIVE); + DrawPartialRotatedDecal(vf2d{drawX,drawY}+16,GetGFX("gametiles.png").Decal(),0.f,{16.f,16.f},powerupSubimageRect.pos,powerupSubimageRect.size,{1.1f,1.1f}); + SetDecalMode(DecalMode::NORMAL); + DrawPartialDecal({drawX,drawY},GetGFX("gametiles.png").Decal(),powerupSubimageRect.pos,powerupSubimageRect.size); + }else{ + DrawPartialDecal({drawX,drawY},GetGFX("gametiles.png").Decal(),powerupSubimageRect.pos,powerupSubimageRect.size,{1.f,1.f},VERY_DARK_GREY); + } } } - } + #pragma endregion + #pragma region Drown/Burn Bar. + if(Hamster::GetPlayer().IsDrowning()){ + DrawDecal({12.f,240.f},GetGFX("drownmeter.png").Decal()); + GradientFillRectDecal(vf2d{12.f,240.f}+vf2d{12.f,5.f},vf2d{Hamster::GetPlayer().GetDrownRatio()*57.f,4.f},{145,199,255},{226,228,255},{226,228,255},{145,199,255}); + } + else if(Hamster::GetPlayer().IsBurning()){ + DrawDecal({12.f,240.f},GetGFX("burnmeter.png").Decal()); + GradientFillRectDecal(vf2d{12.f,240.f}+vf2d{12.f,5.f},vf2d{Hamster::GetPlayer().GetBurnRatio()*57.f,4.f},{250,177,163},{226,228,255},{226,228,255},{250,177,163}); + } + #pragma endregion } const Terrain::TerrainType HamsterGame::GetTerrainTypeAtPos(const vf2d pos)const{