Add missing variance for AI flight controls. Add HUD elements for Boost. Implemented Boost mechanic for Hamster Wheel powerup.

sigonasr2 3 months ago
parent e967e00257
commit 16b9ad521e
  1. BIN
      assets/boost.png
  2. BIN
      assets/boost_outline.png
  3. 46
      src/Hamster.cpp
  4. 3
      src/Hamster.h
  5. 2
      src/HamsterGame.cpp
  6. 29
      src/HamsterJet.cpp
  7. 4
      src/HamsterJet.h

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -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<float>(GetPos(),collisionRadius),geom2d::circle<float>(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;

@ -126,6 +126,9 @@ class Hamster{
std::optional<vf2d>temporaryNode;
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();

@ -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(){

@ -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()<variance){
if(action.type==HamsterAI::Action::LANDING){
state=LANDING;
easeInTimer=0.f;
}
hamster.ai.AdvanceToNextAction();
const HamsterAI::ActionOptRef&nextAction{hamster.ai.GetCurrentAction()};
if(nextAction.has_value()){
const HamsterAI::Action&futureAction{nextAction.value().get()};
if(futureAction.type==HamsterAI::Action::MOVE){
switch(hamster.ai.GetAIType()){
case HamsterAI::SMART:{
if(util::random()%100<2)hamster.ai.AdvanceToNextAction();
}break;
case HamsterAI::NORMAL:{
if(util::random()%100<25)hamster.ai.AdvanceToNextAction();
}break;
case HamsterAI::DUMB:{
if(util::random()%100<50)hamster.ai.AdvanceToNextAction();
}break;
}
}
}
if(hamster.chooseTemporaryNodeNext){
int MAX_SEARCH_AMT{100};
float SEARCH_RANGE{1.f};

@ -37,7 +37,7 @@ All rights reserved.
#pragma endregion
#pragma once
#include "olcUTIL_Geometry2D.h"
#include "olcPixelGameEngine.h"
#include "Terrain.h"
class Hamster;
@ -79,7 +79,7 @@ private:
public:
HamsterJet(Hamster&hamster);
void Update(const float fElapsedTime);
void Draw();
void Draw(const Pixel blendCol);
void DrawOverlay()const;
void HandlePlayerControls();
void HandleAIControls();

Loading…
Cancel
Save