diff --git a/olcCodeJam2023Entry/Constant.cpp b/olcCodeJam2023Entry/Constant.cpp index 1b6934f..8adf792 100644 --- a/olcCodeJam2023Entry/Constant.cpp +++ b/olcCodeJam2023Entry/Constant.cpp @@ -30,4 +30,5 @@ float CONSTANT::COLLECTION_WAIT_TIME=8; int CONSTANT::MEMORY_ALLOCATOR_COST=5; -float CONSTANT::UNIT_BUILD_TIME=10; \ No newline at end of file +float CONSTANT::UNIT_BUILD_TIME=10; +int CONSTANT::STARTING_RESOURCE_COUNT=5; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Constant.h b/olcCodeJam2023Entry/Constant.h index df804d6..483de35 100644 --- a/olcCodeJam2023Entry/Constant.h +++ b/olcCodeJam2023Entry/Constant.h @@ -35,4 +35,5 @@ public: static int MEMORY_ALLOCATOR_COST; static float UNIT_BUILD_TIME; + static int STARTING_RESOURCE_COUNT; }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Resources.h b/olcCodeJam2023Entry/Resources.h index ea315c2..b4cadf2 100644 --- a/olcCodeJam2023Entry/Resources.h +++ b/olcCodeJam2023Entry/Resources.h @@ -1,10 +1,10 @@ #pragma once - +#include "Constant.h" struct Resources{ - int health=0; - int atkSpd=0; - int moveSpd=0; - int range=0; - int procedure=0; + int health=CONSTANT::STARTING_RESOURCE_COUNT; + int atkSpd=CONSTANT::STARTING_RESOURCE_COUNT; + int moveSpd=CONSTANT::STARTING_RESOURCE_COUNT; + int range=CONSTANT::STARTING_RESOURCE_COUNT; + int procedure=CONSTANT::STARTING_RESOURCE_COUNT; }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index ae50101..a0152c0 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -105,7 +105,38 @@ MemoryAllocator::MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::map>&otherUnits){ + +} + +void MemoryAllocator::Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits){ + if(IsBuilding()){ + buildTime-=pge->GetElapsedTime(); + if(buildTime<=0){ + for(int i=0;i>&IMAGES){ + if(IsBuilding()){ + game.GetPGE()->SetDrawTarget(img.Sprite()); + game.GetPGE()->Clear(BLANK); + Renderable&targetImg=buildTransformUnit->GetImage(); + game.GetPGE()->SetDrawTarget(nullptr); + game.DrawPartialRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{0,0},{float(img.Sprite()->width),float((buildTime/CONSTANT::UNIT_BUILD_TIME)*img.Sprite()->height)},{1,1},GetUnitColor()/3); + game.DrawPartialRotatedDecal(GetGhostPos()+vf2d{0.f,(buildTime/CONSTANT::UNIT_BUILD_TIME)*buildTransformUnit->GetImage().Sprite()->height},buildTransformUnit->GetImage().Decal(),0,buildTransformUnit->GetImage().Sprite()->Size()/2,{0.f,(buildTime/CONSTANT::UNIT_BUILD_TIME)*buildTransformUnit->GetImage().Sprite()->height},{float(buildTransformUnit->GetImage().Sprite()->width),float(buildTransformUnit->GetImage().Sprite()->height-(buildTime/CONSTANT::UNIT_BUILD_TIME)*buildTransformUnit->GetImage().Sprite()->height)},{1,1},GetUnitColor()/1.5f); + if(fmod(buildTime,1)>0.5){ + game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),{0, 202, 217}); + } + } else { + game.DrawRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{1,1},GetUnitColor()); + if(IsSelected()){ + game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE); + } + } } std::vector RAMBank::resourceCost={{RANGE,0},{ATKSPD,0},{MOVESPD,0},{PROCEDURE,25},{HEALTH,16}}; @@ -140,7 +171,7 @@ void RAMBank::Attack(Unit&victim,std::vector>&otherUnits){ } -void RAMBank::Update(PixelGameEngine*pge,std::map>&SOUNDS){ +void RAMBank::Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits){ pge->SetDrawTarget(img.Sprite()); for(int y=0;yheight;y++){ for(int x=0;xwidth;x++){ @@ -293,9 +324,9 @@ void Unit::DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std:: } void Unit::Draw(TileTransformedView&game,std::map>&IMAGES){ - game.DrawRotatedDecal(ghostPos,img.Decal(),0,img.Sprite()->Size()/2,{1,1},GetUnitColor()); + game.DrawRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{1,1},GetUnitColor()); if(IsSelected()){ - game.DrawRotatedDecal(ghostPos,IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE); + game.DrawRotatedDecal(GetGhostPos(),IMAGES[SELECTION_CIRCLE]->Decal(),0,IMAGES[SELECTION_CIRCLE]->Sprite()->Size()/2,vf2d(img.Sprite()->Size())/IMAGES[SELECTION_CIRCLE]->Sprite()->Size(),WHITE); } } @@ -457,17 +488,19 @@ void Unit::_RunAI(PixelGameEngine*pge){ RunAI(pge); } -void Unit::_Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources){ +void Unit::_Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector>&queuedUnits){ if(!target.expired()){ auto ptrTarget=target.lock(); - if(!InRange(ptrTarget)){ + if(!InRange(ptrTarget)&&CanMove()){ SetPos(GetPos()+(ptrTarget->GetPos()-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime()); } } else if(targetLoc!=CONSTANT::UNSELECTED){ float dist=geom2d::line(pos,targetLoc).length(); if(dist>24){ - SetPos(GetPos()+(targetLoc-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime()); + if(CanMove()){ + SetPos(GetPos()+(targetLoc-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime()); + } } else { if(willAttachWhenReachingDestination&&!attachTarget.expired()&&attachTarget.lock()->attachedUnit.expired()){ attachedPoint=attachTarget; @@ -515,7 +548,7 @@ void Unit::_Update(PixelGameEngine*pge,std::map>&SO lineShift-=pge->GetElapsedTime(); if(lineShift<-25)lineShift+=25; - Update(pge,SOUNDS); + Update(pge,SOUNDS,queuedUnits); } std::vector operator <<(Unit&u,const int n){ @@ -636,7 +669,7 @@ void Unit::AttemptAttack(std::weak_ptrattacker,std::weak_ptrunit,std } } -void Unit::Update(PixelGameEngine*pge,std::map>&SOUNDS){} +void Unit::Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits){} void Unit::Attacked(std::weak_ptrattacker){} @@ -756,4 +789,8 @@ bool Unit::IsAllocator(){ void Unit::SetBuildUnit(float buildTime,std::unique_ptrfinalUnit){ this->buildTime=buildTime; this->buildTransformUnit=std::move(finalUnit); +} + +bool Unit::IsBuilding(){ + return buildTime>0; } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index c53d13f..68fcc62 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -34,7 +34,7 @@ public: int GetMemorySize(); std::vectormemory; std::vectorghostMemory; - virtual void Update(PixelGameEngine*pge,std::map>&SOUNDS); + virtual void Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits); virtual void Attack(Unit&victim,std::vector>&otherUnits)=0; virtual void Draw(TileTransformedView&game,std::map>&IMAGES); virtual void DrawHud(TileTransformedView&game,std::map>&IMAGES); @@ -55,7 +55,7 @@ public: bool GhostInFogOfWar(); void HideGhost(); vf2d GetGhostPos(); - void _Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources); + void _Update(PixelGameEngine*pge,std::map>&SOUNDS,Resources&player_resources,Resources&enemy_resources,std::vector>&queuedUnits); bool IsMoveable(); void DrawRangeIndicator(PixelGameEngine*pge,TileTransformedView&game,std::map>&IMAGES); bool CanInteractWithEnemies(); @@ -75,6 +75,7 @@ public: virtual bool ClickHandled(TileTransformedView&game,Resources&player_resources,std::vector>&units,std::map>&IMAGES); //If you return true here, then the left click does not pass back to the main Virus Attack class. bool IsAllocator(); void SetBuildUnit(float buildTime,std::unique_ptrfinalUnit); + bool IsBuilding(); std::vector& operator <<=(const int n){ for(int i=0;ibuildTransformUnit; + float buildTime=0; private: Renderable targetingLine; Renderable attackingLine; @@ -136,8 +139,6 @@ private: bool willAttachWhenReachingDestination=false; std::weak_ptrself_ptr; float collectionTime=0; - float buildTime=0; - std::unique_ptrbuildTransformUnit; }; struct BasicUnit:Unit{ @@ -185,7 +186,9 @@ struct Corrupter:Unit{ struct MemoryAllocator:Unit{ MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); - void Attack(Unit&victim,std::vector>&otherUnits)override; + void Attack(Unit&victim,std::vector>&units)override; + void Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits)override; + void Draw(TileTransformedView&game,std::map>&IMAGES)override; static std::vector resourceCost; }; @@ -199,7 +202,7 @@ struct RAMBank:Unit{ QuickGUI::Manager allocatorManager; QuickGUI::ImageButton*allocatorButton; RAMBank(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false); - void Update(PixelGameEngine*pge,std::map>&SOUNDS)override; + void Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits)override; void Attack(Unit&victim,std::vector>&otherUnits)override; void Draw(TileTransformedView&game,std::map>&IMAGES)override; void OnDeath(std::map>&SOUNDS)override; diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index 627577f..5991ba6 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -124,54 +124,60 @@ void VirusAttack::InitializeSounds(){ bool VirusAttack::UnitCreationClickHandled(){ if(leftShifterButton->bPressed){ for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(LeftShifter::resourceCost)){ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,LeftShifter::resourceCost)){ std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); + ExpendResources(player_resources,LeftShifter::resourceCost); } } return true; } if(rightShifterButton->bPressed){ for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(RightShifter::resourceCost)){ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,RightShifter::resourceCost)){ std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); + ExpendResources(player_resources,RightShifter::resourceCost); } } return true; } if(bitRestorerButton->bPressed){ for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(BitRestorer::resourceCost)){ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,BitRestorer::resourceCost)){ std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); + ExpendResources(player_resources,BitRestorer::resourceCost); } } return true; } if(memorySwapperButton->bPressed){ for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(MemorySwapper::resourceCost)){ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,MemorySwapper::resourceCost)){ std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); + ExpendResources(player_resources,MemorySwapper::resourceCost); } } return true; } if(corrupterButton->bPressed){ for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(Corrupter::resourceCost)){ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,Corrupter::resourceCost)){ std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); + ExpendResources(player_resources,Corrupter::resourceCost); } } return true; } if(platformButton->bPressed){ for(auto&u:units){ - if(u->IsSelected()&&u->IsAllocator()&&CanAfford(MemoryAllocator::resourceCost)){ + if(u->IsSelected()&&u->IsAllocator()&&CanAfford(player_resources,MemoryAllocator::resourceCost)){ std::unique_ptrbuildUnit=std::make_unique(this,u->GetPos(),IMAGES,u->IsFriendly()); u->SetBuildUnit(CONSTANT::UNIT_BUILD_TIME,std::move(buildUnit)); + ExpendResources(player_resources,MemoryAllocator::resourceCost); } } return true; @@ -179,6 +185,17 @@ bool VirusAttack::UnitCreationClickHandled(){ return false; }; +void VirusAttack::UpdateUnitCreationListGUI(bool allocatorSelected){ + unitCreationList.DisplayAllControls(allocatorSelected); + leftShifterButton->Enable(CanAfford(player_resources,LeftShifter::resourceCost)); + rightShifterButton->Enable(CanAfford(player_resources,RightShifter::resourceCost)); + bitRestorerButton->Enable(CanAfford(player_resources,BitRestorer::resourceCost)); + memorySwapperButton->Enable(CanAfford(player_resources,MemorySwapper::resourceCost)); + corrupterButton->Enable(CanAfford(player_resources,Corrupter::resourceCost)); + platformButton->Enable(CanAfford(player_resources,MemoryAllocator::resourceCost)); + unitCreationList.Update(this); +} + void VirusAttack::HandleDraggingSelection(){ auto NotClickingOnMinimap=[&](){return !(GetMouseX()>=ScreenWidth()-64&&GetMouseY()>=ScreenHeight()-64);}; bool allocatorSelected=false; @@ -188,14 +205,7 @@ void VirusAttack::HandleDraggingSelection(){ allocatorSelected=true; } } - unitCreationList.DisplayAllControls(allocatorSelected); - leftShifterButton->Enable(CanAfford(LeftShifter::resourceCost)); - rightShifterButton->Enable(CanAfford(RightShifter::resourceCost)); - bitRestorerButton->Enable(CanAfford(BitRestorer::resourceCost)); - memorySwapperButton->Enable(CanAfford(MemorySwapper::resourceCost)); - corrupterButton->Enable(CanAfford(Corrupter::resourceCost)); - platformButton->Enable(CanAfford(MemoryAllocator::resourceCost)); - unitCreationList.Update(this); + UpdateUnitCreationListGUI(allocatorSelected); if(GetMouse(0).bPressed){ if(NotClickingOnMinimap()){ for(auto&u:units){ @@ -482,7 +492,7 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ } } u->AttemptAttack(u,closestUnit,units,debuffIcons,IMAGES); - u->_Update(this,SOUNDS,player_resources,enemy_resources); + u->_Update(this,SOUNDS,player_resources,enemy_resources,queuedUnits); } std::erase_if(units,[&](std::shared_ptru){ @@ -495,6 +505,11 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ } }); + for(auto&queuedUnit:queuedUnits){ + units.push_back(std::move(queuedUnit)); + } + + queuedUnits.clear(); game.DrawPartialDecal({0,0},CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE,IMAGES[TILE]->Decal(),{0,0},CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE,DARK_GREEN); @@ -575,29 +590,51 @@ void VirusAttack::RenderFogOfWar(){ } } -bool VirusAttack::CanAfford(std::vector&unitCosts){ +bool VirusAttack::CanAfford(Resources&resources,std::vector&unitCosts){ for(Memory&mem:unitCosts){ switch(mem.type){ case HEALTH:{ - if(player_resources.health&unitCosts){ + for(Memory&mem:unitCosts){ + switch(mem.type){ + case HEALTH:{ + resources.health-=mem.size; + }break; + case ATKSPD:{ + resources.atkSpd-=mem.size; + }break; + case MOVESPD:{ + resources.moveSpd-=mem.size; + }break; + case RANGE:{ + resources.range-=mem.size; + }break; + case PROCEDURE:{ + resources.procedure-=mem.size; + }break; + } + } +} + int main() { VirusAttack app; diff --git a/olcCodeJam2023Entry/VirusAttack.h b/olcCodeJam2023Entry/VirusAttack.h index 880960d..2d5c2c0 100644 --- a/olcCodeJam2023Entry/VirusAttack.h +++ b/olcCodeJam2023Entry/VirusAttack.h @@ -21,6 +21,7 @@ struct Letter{ class VirusAttack : public olc::PixelGameEngine { private: + std::vector>queuedUnits; std::vector>units; std::vector>collectionPoints; std::vector>deathAnimations; @@ -67,7 +68,9 @@ private: void DrawResourceBar(); bool UnitCreationClickHandled(); void InitializeUnitCreationGUI(); - bool CanAfford(std::vector&unitCosts); + bool CanAfford(Resources&resources,std::vector&unitCosts); + void ExpendResources(Resources&resources,std::vector&unitCosts); + void UpdateUnitCreationListGUI(bool allocatorSelected); public: VirusAttack(); diff --git a/olcCodeJam2023Entry/olcPGEX_QuickGUI.h b/olcCodeJam2023Entry/olcPGEX_QuickGUI.h index a21deef..75f814b 100644 --- a/olcCodeJam2023Entry/olcPGEX_QuickGUI.h +++ b/olcCodeJam2023Entry/olcPGEX_QuickGUI.h @@ -693,11 +693,11 @@ namespace olc::QuickGUI void Button::Update(TileTransformedView&pge) { + bPressed = false; + bReleased = false; if (m_state == State::Disabled || !bVisible) return; - bPressed = false; - bReleased = false; float fElapsedTime = pge.GetPGE()->GetElapsedTime(); olc::vf2d vMouse = pge.ScreenToWorld(pge.GetPGE()->GetMousePos()); @@ -735,11 +735,11 @@ namespace olc::QuickGUI void Button::Update(PixelGameEngine*pge) { + bPressed = false; + bReleased = false; if (m_state == State::Disabled || !bVisible) return; - bPressed = false; - bReleased = false; float fElapsedTime = pge->GetElapsedTime(); olc::vf2d vMouse = pge->GetMousePos();