From 16b9ad521ece0b1c0c80d0899a68bb5f09b72563 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Thu, 22 Aug 2024 18:39:17 -0500 Subject: [PATCH] Add missing variance for AI flight controls. Add HUD elements for Boost. Implemented Boost mechanic for Hamster Wheel powerup. --- assets/boost.png | Bin 0 -> 2032 bytes assets/boost_outline.png | Bin 0 -> 2111 bytes src/Hamster.cpp | 46 +++++++++++++++++++++++++++++++-------- src/Hamster.h | 3 +++ src/HamsterGame.cpp | 2 ++ src/HamsterJet.cpp | 29 +++++++++++++++++++++--- src/HamsterJet.h | 4 ++-- 7 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 assets/boost.png create mode 100644 assets/boost_outline.png diff --git a/assets/boost.png b/assets/boost.png new file mode 100644 index 0000000000000000000000000000000000000000..8d05ee7e5530d9be7928f55bcad9d4bb7b753f78 GIT binary patch literal 2032 zcmVEX>4Tx04R}tkv&MmKpe$iQ^lec2P=p;WT;Mdu_BJ8ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfc5qU3krMxx6k5c1aNLh~_a1le0HIlBs@W3*RLwHd ziMW`{uZn%I2w(&Qh$1L4Q%`0Vv+x{W_we!cF2b|C&;29%C|}6A ztZ?4qtXAu+eNXeSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00qcNL_t(|+U;FCavdQM1PbXax{V?!Q=kJVQLIq06CXf< zGCA^Xd=`7FaI~*hyj^yH0S4%}SwP=fvt`71Sfw)m)d}vY^u;5Gr^1J|SU z@#9^+zIC1B9uPq`07P$UhT;a;H3UR& zW`-;caas7}&=~!5R{|RD!L5}5!VZ(=U}9c{@UfY)v=E_ z$T-R7hN%F(SAia4H?2m$#6?)|d8JeVYz0paQ*!ikfYJ#_MT^*DtALSAP|xD`lB1DG zkhOLQ@z3&+kYjNJP^OKQpj6>|xsNe6&l-7A41iOliDbe%eqn^l!V@*p8*NXg0Hv582?H~z zCOn>96w2NP9__yaGN;uhw}t`LtB9;y!vO39076h~E7)HHU>cFhpDhtAP^T;4Foi8C zIOiKNdaEG0aZ~Ox=BN^uOMI00x-H8&NYBmO1ZrshTyVH;TwYb{s7D2MnGnj z;A#W4goR#D3r#^>X$}L3aW*Hhk00;f{z{17`x8QZG~E{F>IO=m!ED{N#J)SIyK4ed z3EmU_@9$5glv20%Pep#e2gJTL%n5NfS)`EgKDI{4IYuv|zdHj^2oH_KBjG7Vpd3pO zFU1TX)&wC?g^w|UwDvgly@5?$9b4K6{zWOd1_)i`B8-D-uZ}(3A?#%XMEbF6h@ZO; zAYy}PX5@;`(FR^Bf#i*k+xw^JX&`3)Z#?bkTmd=Yq?XAoSt(tB!TZT;S|tZ3oVcc2cZD~00000000000000000000c<>+Y?s1^hgBcEX>4Tx04R}tkv&MmKpe$iQ^lec2P=p;WT;Mdu_BJ8ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfc5qU3krMxx6k5c1aNLh~_a1le0HIlBs@W3*RLwHd ziMW`{uZn%I2w(&Qh$1L4Q%`0Vv+x{W_we!cF2b|C&;29%C|}6A ztZ?4qtXAu+eNX02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00tLHL_t(|+U;FE&JZ~aokW3x7Q`7i0EgHP2?;t1Zm<>G zP|`rPH=v*c35kwFZ~)GLprzOyiLJ5<`6iP%e|E<2NeF!~Kepeq<78&OY#RUodSQBA zZ2#-;U%6x4>pu;`E+>X&hQSbl+*q34#(w=^w*cwaIgZMLpOB~QD z1PQS;vy4SGsL%S5LNK$9)m{yHCsJ!t8H&NZ4Am-vk>sahnv133Bwy2zFsh2Sioi%9 z|LP)`O+G~gRtovE@5KeKc&4W9Rx%+q3nMFx`;r7_r5n7m2)If=MT}Nr_Fr)*kQz@b zHQTNv0!hBa9NQIwzv3_;&E^!Rb^}xc0)PPImf0)x0TO)(xpp-Mr=Ce`>F8&oXRJSd z`+nnkcBDc6c}qfD>){_o=a?^_|34SiKwg~PNTd9*vqUhfj~V%pYIdC6 zNTYg-KuV*Uv!hlZ9C0?WQ%5Ix!)lB=DpR?JrM73_dTiapzE<*&;(W%X7pa?>IiW&p zf-0ql$k~zdCH(i)HCoAUZUQ-)wWENo+%TSHp0qf-aNP3409VI;&b* z)!hOz5OZuPErwNwiiF|HpkbK|K`q*qTa6R z%b?OlixMZaKOZPbgwhy$0hN+pB!F5G#sEc`Sq>6#DYX)7`W?CuvBD87yqA*}3|nU(#iAnp5}R;P2~t3e6*H9k`Ps;vT|r-5gITLsd6uu`*scKPMH zcPa+dYkN+pOZ65Rq}z7OmHiT%u+{ylsRCFERt`Hd`+J~dCLk3Ywo|Ksl^mdz$zR1s zD=|RMxl53r^GAY@!v#>Xpy2~lOFYM7P|ZE5e$MbKD*!z5T@RE#z|PE;ecykZ8~2ze zb1ntGO_WVY#=JeE&B`?_)W#B__RA1QMPG*4l6u12InnM~(k} zg=^pUWtu*UUsNIZ81(k5FNJoW22yvt0C=xFeO1NI+qr}gh0v_>jw8?jq0Q~CF(S<>{ zEK$UQDBVB6^-v=qvr2TC26_c?H+r1=0<2~$W%m&A>j0Erxk4o={4;|5rGG<64DMy& zUbBJGUj}i{TBv&mE%#1fZGex6|L4=YZQHi(_M>M*uD=3EJ4{Kb0+eh$BR)nbgqC}( zlKsmGpd{dDnV2HJLKTyknCk_Ar002ovPDHLkV1jrqzc>H@ literal 0 HcmV?d00001 diff --git a/src/Hamster.cpp b/src/Hamster.cpp index a93cf27..f1c338d 100644 --- a/src/Hamster.cpp +++ b/src/Hamster.cpp @@ -66,6 +66,8 @@ void Hamster::UpdateHamsters(const float fElapsedTime){ h.aiNodeTime+=fElapsedTime; h.frictionEnabled=true; h.bumpTimer-=fElapsedTime; + h.boostTimer=std::max(0.f,h.boostTimer-fElapsedTime); + h.canCollectWheelPowerupTimer=std::max(0.f,h.canCollectWheelPowerupTimer-fElapsedTime); h.HandleCollision(); switch(h.state){ case NORMAL:{ @@ -277,19 +279,23 @@ void Hamster::DrawHamsters(TransformedView&tv){ if(animCycle>=0.8f){ yHopAmt=-abs(sin(geom2d::pi*(animCycle/0.35f)))*12.f; } - if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); + Pixel blendCol{PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)}; + if(h.boostTimer!=0.f&&fmod(HamsterGame::Game().GetRuntime(),0.5f)<0.25f)blendCol=RED; + if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(blendCol); HamsterGame::Game().SetZ(h.z+0.02f); tv.DrawRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},HamsterGame::GetGFX("shadow.png").Decal(),0.f,HamsterGame::GetGFX("shadow.png").Sprite()->Size()/2); HamsterGame::Game().SetZ(h.z+0.025f); - tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY+yHopAmt},img.GetSourceImage()->Decal(),0.f,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale*vf2d{facingXScale,1.f},PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); + tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY+yHopAmt},img.GetSourceImage()->Decal(),0.f,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale*vf2d{facingXScale,1.f},blendCol); HamsterGame::Game().SetZ(0.f); }else{ - if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); + Pixel blendCol{PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)}; + if(h.boostTimer!=0.f&&fmod(HamsterGame::Game().GetRuntime(),0.5f)<0.25f)blendCol=RED; + if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(blendCol); HamsterGame::Game().SetZ(h.z+0.02f); - if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},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+vf2d{0.f,h.drawingOffsetY},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+vf2d{0.f,h.drawingOffsetY},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,blendCol,h.imgScale)); + tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},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,blendCol,h.imgScale)); HamsterGame::Game().SetZ(h.z+0.025f); - if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},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)); + if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},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,{blendCol.r,blendCol.g,blendCol.b,192},h.imgScale)); HamsterGame::Game().SetZ(0.f); } } @@ -340,6 +346,18 @@ void Hamster::DrawOverlay(){ HamsterGame::Game().DrawPartialDecal(jetDisplayOffset+vf2d{24.f,139.f}+vf2d{0.f,jetFuelBarHeight*(1.f-GetPlayer().jetFuelDisplayAmt)},HamsterGame::GetGFX("fuelbar.png").Decal(),{0.f,jetFuelBarHeight*(1.f-GetPlayer().jetFuelDisplayAmt)},{float(HamsterGame::GetGFX("fuelbar.png").Sprite()->width),jetFuelBarHeight*jetFuelLandingCost},{1.f,1.f},{255,0,0,192}); } if(GetPlayer().HasPowerup(Powerup::JET))HamsterGame::Game().DrawDecal(jetDisplayOffset+vf2d{22.f,137.f},HamsterGame::GetGFX("fuelbar_outline.png").Decal(),{1.f,1.f},GetPlayer().jetFuel<=0.2f?(fmod(GetPlayer().readyFlashTimer,1.f)<=0.5f?RED:BLACK):BLACK); + if(GetPlayer().HasPowerup(Powerup::WHEEL)){ + for(int i:std::ranges::iota_view(0,3)){ + if(fmod(HamsterGame::Game().GetRuntime(),2.f)<1.f&&GetPlayer().boostCounter>i)HamsterGame::Game().DrawDecal(HamsterGame::SCREEN_FRAME.pos+vf2d{i*16.f+4.f,HamsterGame::SCREEN_FRAME.size.y-20.f},HamsterGame::GetGFX("boost_outline.png").Decal(),{0.125f,0.125f},GetPlayer().boostCounter>i?WHITE:BLACK); + else HamsterGame::Game().DrawDecal(HamsterGame::SCREEN_FRAME.pos+vf2d{i*16.f+4.f,HamsterGame::SCREEN_FRAME.size.y-20.f},HamsterGame::GetGFX("boost.png").Decal(),{0.125f,0.125f},GetPlayer().boostCounter>i?WHITE:BLACK); + } + for(int y:std::ranges::iota_view(-1,2)){ + for(int x:std::ranges::iota_view(-1,2)){ + HamsterGame::Game().DrawStringDecal(HamsterGame::SCREEN_FRAME.pos+vf2d{3*16.f+8.f,HamsterGame::SCREEN_FRAME.size.y-12.f}+vi2d{x,y},"\"R\" - BOOST",fmod(HamsterGame::Game().GetRuntime(),2.f)<1.f?RED:BLACK); + } + } + HamsterGame::Game().DrawStringDecal(HamsterGame::SCREEN_FRAME.pos+vf2d{3*16.f+8.f,HamsterGame::SCREEN_FRAME.size.y-12.f},"\"R\" - BOOST",YELLOW); + } } const Animate2D::Frame&Hamster::GetCurrentAnimation()const{ @@ -377,6 +395,10 @@ void Hamster::HandlePlayerControls(){ vel=vf2d{std::min(GetMaxSpeed(),vel.polar().x),vel.polar().y}.cart(); frictionEnabled=false; } + if(HamsterGame::Game().GetKey(R).bPressed&&boostCounter>0){ + boostCounter--; + boostTimer=1.f; + } if(HamsterGame::Game().GetKey(SPACE).bPressed){ if(lastTappedSpace<=0.6f&&HasPowerup(Powerup::JET)){ SetState(FLYING); @@ -450,7 +472,7 @@ void Hamster::HandleCollision(){ } for(Powerup&powerup:Powerup::GetPowerups()){ if(z<=0.1f&& - (!HasPowerup(powerup.GetType())||HasPowerup(Powerup::JET)&&powerup.GetType()==Powerup::JET&&jetFuel!=1.f) + (!HasPowerup(powerup.GetType())||HasPowerup(Powerup::JET)&&powerup.GetType()==Powerup::JET&&jetFuel!=1.f||HasPowerup(Powerup::WHEEL)&&boostCounter<3&&canCollectWheelPowerupTimer==0.f) &&geom2d::overlaps(geom2d::circle(GetPos(),collisionRadius),geom2d::circle(powerup.GetPos(),20.f))){ ObtainPowerup(powerup.GetType()); if(IsPlayerControlled)HamsterAI::OnPowerupCollection(this->pos); @@ -549,11 +571,13 @@ const float Hamster::GetMaxSpeed()const{ }break; } if(HasPowerup(Powerup::WHEEL))finalMaxSpd*=1.5f; + if(boostTimer!=0.f)finalMaxSpd*=1.5f; if(hamsterJet.has_value()){ if(hamsterJet.value().GetState()==HamsterJet::LANDING)finalMaxSpd*=1.5f; else if(FlyingInTheAir())finalMaxSpd*=8.f; } if(!IsPlayerControlled){ + if(temporaryNode.has_value()||aiNodeTime>3.f)finalMaxSpd*=0.5f; //Slow down a bit... switch(ai.GetAIType()){ case HamsterAI::SMART:{ finalMaxSpd*=0.99f; @@ -589,6 +613,10 @@ const float Hamster::GetBumpAmount()const{ } void Hamster::ObtainPowerup(const Powerup::PowerupType powerup){ + if(powerup==Powerup::WHEEL){ + boostCounter=3; + canCollectWheelPowerupTimer=5.f; + } powerups.insert(powerup); } @@ -636,7 +664,7 @@ void Hamster::SetPos(const vf2d pos){ this->pos=vf2d{this->pos.x,pos.y}; movedY=true; } - if(IsPlayerControlled&&(movedX||movedY)&&HamsterGame::Game().GetTerrainTypeAtPos(this->pos)!=Terrain::TUNNEL)HamsterAI::OnMove(this->pos); + if(IsPlayerControlled&&(movedX||movedY)&&HamsterGame::Game().GetTerrainTypeAtPos(this->pos)!=Terrain::TUNNEL&&state!=FLYING)HamsterAI::OnMove(this->pos); } void Hamster::SetZ(const float z){ @@ -845,7 +873,7 @@ void Hamster::HandleAIControls(){ } if(aimingDir!=vf2d{}){ targetRot=aimingDir.norm().polar().y; - const vf2d currentVel{vel}; + vf2d currentVel{vel}; vel=vf2d{currentVel.polar().x+((GetMaxSpeed()/GetTimeToMaxSpeed())*HamsterGame::Game().GetElapsedTime()),rot}.cart(); vel=vf2d{std::min(GetMaxSpeed(),vel.polar().x),vel.polar().y}.cart(); frictionEnabled=false; diff --git a/src/Hamster.h b/src/Hamster.h index cafbd46..2a22b47 100644 --- a/src/Hamster.h +++ b/src/Hamster.h @@ -126,6 +126,9 @@ class Hamster{ std::optionaltemporaryNode; bool chooseTemporaryNodeNext{false}; int randomId{}; + uint8_t boostCounter{}; + float boostTimer{}; + float canCollectWheelPowerupTimer{}; public: Hamster(const vf2d spawnPos,const std::string&img,const PlayerControlled IsPlayerControlled=NPC); static const Hamster&GetPlayer(); diff --git a/src/HamsterGame.cpp b/src/HamsterGame.cpp index 91c975c..9e5fcff 100644 --- a/src/HamsterGame.cpp +++ b/src/HamsterGame.cpp @@ -93,6 +93,8 @@ void HamsterGame::LoadGraphics(){ _LoadImage("radar.png"); _LoadImage("checkpoint_arrow.png"); _LoadImage("radaricons.png"); + _LoadImage("boost.png"); + _LoadImage("boost_outline.png"); } void HamsterGame::LoadAnimations(){ diff --git a/src/HamsterJet.cpp b/src/HamsterJet.cpp index 0d2c333..63752d4 100644 --- a/src/HamsterJet.cpp +++ b/src/HamsterJet.cpp @@ -133,7 +133,7 @@ void HamsterJet::Update(const float fElapsedTime){ }break; } } -void HamsterJet::Draw(){ +void HamsterJet::Draw(const Pixel blendCol){ float drawingOffsetY{0.f}; hamster.SetDrawingOffsetY(0.f); if((state==HAMSTER_CONTROL||state==LANDING)&&z>2.f){ @@ -147,7 +147,7 @@ void HamsterJet::Draw(){ HamsterGame::Game().SetZ(z); const Animate2D::FrameSequence&jetAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",AnimationState::JET)}; const Animate2D::Frame&jetFrame{jetAnim.GetFrame(HamsterGame::Game().GetRuntime())}; - HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},jetFrame.GetSourceImage()->Decal(),0.f,jetFrame.GetSourceRect().size/2,jetFrame.GetSourceRect().pos,jetFrame.GetSourceRect().size); + HamsterGame::Game().tv.DrawPartialRotatedDecal(pos+vf2d{0,drawingOffsetY},jetFrame.GetSourceImage()->Decal(),0.f,jetFrame.GetSourceRect().size/2,jetFrame.GetSourceRect().pos,jetFrame.GetSourceRect().size,{1.f,1.f},blendCol); const Animate2D::FrameSequence&flameAnim{HamsterGame::Game().GetAnimation("hamster_jet.png",AnimationState::JET_FLAMES)}; const Animate2D::Frame&flameFrame{flameAnim.GetFrame(HamsterGame::Game().GetRuntime())}; HamsterGame::Game().SetZ(z+0.01f); @@ -264,14 +264,37 @@ void HamsterJet::HandleAIControls(){ if(GetState()==LANDING){ fallSpd=hamster.GetAILandingSpeed(); } + + vf2d targetLoc{action.pos}; + if(action.type==HamsterAI::Action::MOVE)targetLoc+=hamster.GetAINodePositionVariance()*8.f; + if(hamster.temporaryNode.has_value())targetLoc=hamster.temporaryNode.value(); vf2d diff{action.pos-hamster.GetPos()}; - if(diff.mag()<172.f){ + float variance{hamster.GetAINodeDistanceVariance()*10.75f}; + if(action.type!=HamsterAI::Action::MOVE)variance=172.f; + if(diff.mag()