From b7ab91a3e83b9e259513c0d1022b05eec82f744c Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Wed, 30 Aug 2023 02:30:09 -0500 Subject: [PATCH] Implement ability for units to attach to collection points. --- olcCodeJam2023Entry/CollectionPoint.h | 3 + olcCodeJam2023Entry/Constant.cpp | 2 + olcCodeJam2023Entry/Constant.h | 2 + olcCodeJam2023Entry/Image.h | 1 + olcCodeJam2023Entry/Unit.cpp | 62 +++++++++++++-- olcCodeJam2023Entry/Unit.h | 6 ++ olcCodeJam2023Entry/VirusAttack.cpp | 72 ++++++++++++------ olcCodeJam2023Entry/VirusAttack.h | 3 +- .../memory_collection_point_highlight.png | Bin 0 -> 12077 bytes 9 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 olcCodeJam2023Entry/assets/memory_collection_point_highlight.png diff --git a/olcCodeJam2023Entry/CollectionPoint.h b/olcCodeJam2023Entry/CollectionPoint.h index 891143e..7340236 100644 --- a/olcCodeJam2023Entry/CollectionPoint.h +++ b/olcCodeJam2023Entry/CollectionPoint.h @@ -2,6 +2,8 @@ #include "olcPixelGameEngine.h" #include "MemoryType.h" +class Unit; + class CollectionPoint{ public: vf2d pos; @@ -10,6 +12,7 @@ public: MemoryType type; vf2d randomOffset; float rot; + std::weak_ptrattachedUnit; CollectionPoint(PixelGameEngine*pge,vf2d pos,float rot,Renderable&collectionPointImg,MemoryType type); void Update(PixelGameEngine*pge,Renderable&matrixImg); }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/Constant.cpp b/olcCodeJam2023Entry/Constant.cpp index 0a3f694..aaa0c49 100644 --- a/olcCodeJam2023Entry/Constant.cpp +++ b/olcCodeJam2023Entry/Constant.cpp @@ -7,6 +7,8 @@ Pixel CONSTANT::ATKSPD_COLOR={140, 21, 13}; Pixel CONSTANT::MOVESPD_COLOR={11, 135, 212}; Pixel CONSTANT::PROCEDURE_COLOR={212, 11, 162}; +Pixel CONSTANT::MOVE_LINE_COL={147, 252, 66}; + vf2d CONSTANT::UNSELECTED={-99,-99}; vi2d CONSTANT::TILE_SIZE={24,24}; diff --git a/olcCodeJam2023Entry/Constant.h b/olcCodeJam2023Entry/Constant.h index e45e8df..edfdf0e 100644 --- a/olcCodeJam2023Entry/Constant.h +++ b/olcCodeJam2023Entry/Constant.h @@ -12,6 +12,8 @@ public: static Pixel MOVESPD_COLOR; static Pixel PROCEDURE_COLOR; + static Pixel MOVE_LINE_COL; + static vf2d UNSELECTED; static vi2d TILE_SIZE; diff --git a/olcCodeJam2023Entry/Image.h b/olcCodeJam2023Entry/Image.h index 5979da0..d79000e 100644 --- a/olcCodeJam2023Entry/Image.h +++ b/olcCodeJam2023Entry/Image.h @@ -31,5 +31,6 @@ enum Image{ RNG_ICON, SPD_ICON, RESOURCE, + MEMORY_COLLECTION_POINT_HIGHLIGHT, }; diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index 4c2d488..714bf64 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -186,7 +186,7 @@ void RAMBank::Update(PixelGameEngine*pge,std::map>& } void RAMBank::Draw(TileTransformedView&game,std::map>&IMAGES){ - game.DrawRotatedDecal(GetGhostPos(),img.Decal(),0,img.Sprite()->Size()/2,{1,1},friendly?Pixel{192,192,255}:Pixel{255,192,192}); + 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); } @@ -270,7 +270,7 @@ 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},friendly?Pixel{192,192,255}:Pixel{255,192,192}); + game.DrawRotatedDecal(ghostPos,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); } @@ -338,6 +338,13 @@ void Unit::DrawUnitDamageStats(PixelGameEngine*pge,TileTransformedView&game,std: lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4); util::ApplyMatrixEffect(game.GetPGE(),targetingLine,*IMAGES[TARGETING_LINE],IMAGES[MATRIX]); game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),targetingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*10,0},{lineToTarget.length(),24},{1,1},targetLineCol); + } else + if(targetLoc!=CONSTANT::UNSELECTED){ + geom2d::linelineToTarget(pos,targetLoc); + lineToTarget.start=lineToTarget.rpoint(GetUnitSize().x/2); + lineToTarget.end=lineToTarget.rpoint(lineToTarget.length()-GetUnitSize().x/4); + util::ApplyMatrixEffect(game.GetPGE(),targetingLine,*IMAGES[TARGETING_LINE],IMAGES[MATRIX]); + game.DrawPartialRotatedDecal(lineToTarget.upoint(0.5),targetingLine.Decal(),lineToTarget.vector().polar().y,{lineToTarget.length()/2,12},{lineShift*10,0},{lineToTarget.length(),24},{1,0.6},CONSTANT::MOVE_LINE_COL); } if(!appliedTarget.expired()){ geom2d::linelineToTarget(pos,appliedTarget.lock()->pos); @@ -435,6 +442,13 @@ void Unit::_Update(PixelGameEngine*pge,std::map>&SO float dist=geom2d::line(pos,targetLoc).length(); if(dist>24){ SetPos(GetPos()+(targetLoc-pos).norm()*GetMoveSpd()*24*pge->GetElapsedTime()); + } else { + if(willAttachWhenReachingDestination&&!attachTarget.expired()){ + attachedPoint=attachTarget; + attachedPoint.lock()->attachedUnit=self_ptr; + } + willAttachWhenReachingDestination=false; + targetLoc=CONSTANT::UNSELECTED; } } @@ -503,11 +517,13 @@ vf2d Unit::GetUnitSize(){ void Unit::SetTargetUnit(std::weak_ptrtarget){ this->target=target; this->targetLoc=CONSTANT::UNSELECTED; + willAttachWhenReachingDestination=false; } void Unit::SetTargetLocation(vf2d targetLoc){ this->target.reset(); this->targetLoc=targetLoc; + willAttachWhenReachingDestination=false; } bool Unit::InRange(std::shared_ptrtarget){ @@ -617,15 +633,15 @@ vf2d Unit::GetGhostPos(){ } bool Unit::IsMoveable(){ - return moveable; + return moveable&&attachedPoint.expired(); } bool Unit::CanInteractWithAllies(){ - return friendlyInteractable; + return friendlyInteractable&&attachedPoint.expired(); } bool Unit::CanInteractWithEnemies(){ - return enemyInteractable; + return enemyInteractable&&attachedPoint.expired(); } Renderable&Unit::GetImage(){ @@ -638,4 +654,40 @@ std::weak_ptrUnit::GetCurrentTarget(){ bool Unit::AutoAcquiresFriendlyTargets(){ return autoAcquireFriendlyTarget; +} + +bool Unit::CanMove(){ + return moveSpd.size>0&&attachedPoint.expired(); +} + +void Unit::SetTargetCollectionPoint(std::weak_ptrtargetCP,std::weak_ptrself_ptr){ + SetTargetLocation(targetCP.lock()->pos); + attachTarget=targetCP; + willAttachWhenReachingDestination=true; + this->self_ptr=self_ptr; +} + +Pixel Unit::GetUnitColor(){ + Pixel col; + if(!attachedPoint.expired()){ + switch(attachedPoint.lock()->type){ + case HEALTH:{ + return CONSTANT::HEALTH_COLOR/2; + }break; + case RANGE:{ + return CONSTANT::RANGE_COLOR/2; + }break; + case ATKSPD:{ + return CONSTANT::ATKSPD_COLOR/2; + }break; + case MOVESPD:{ + return CONSTANT::MOVESPD_COLOR/2; + }break; + case PROCEDURE:{ + return CONSTANT::PROCEDURE_COLOR/2; + }break; + } + } else { + return friendly?Pixel{192,192,255}:Pixel{255,192,192}; + } } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index 0f67593..c1cd72e 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -65,6 +65,9 @@ public: std::weak_ptrGetCurrentTarget(); void DrawUnitDamageStats(PixelGameEngine*pge,TileTransformedView&game,std::map>&IMAGES); bool AutoAcquiresFriendlyTargets(); + bool CanMove(); + void SetTargetCollectionPoint(std::weak_ptrtargetCP,std::weak_ptrself_ptr); + Pixel GetUnitColor(); std::vector& operator <<=(const int n){ for(int i=0;iattachedPoint; + std::weak_ptrattachTarget; + bool willAttachWhenReachingDestination=false; + std::weak_ptrself_ptr; }; struct BasicUnit:Unit{ diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index 407d2b9..be5bf4c 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -47,6 +47,7 @@ void VirusAttack::InitializeImages(){ LoadImage(RNG_ICON,"assets/rng_icon.png"); LoadImage(SPD_ICON,"assets/spd_icon.png"); LoadImage(RESOURCE,"assets/material.png"); + LoadImage(MEMORY_COLLECTION_POINT_HIGHLIGHT,"assets/memory_collection_point_highlight.png"); } bool VirusAttack::OnUserCreate(){ @@ -161,11 +162,25 @@ void VirusAttack::HandleRightClickMove(){ } if(!selectedTarget){ for(auto&u:units){ - if(u->IsFriendly()&&u->IsSelected()){ + if(u->IsFriendly()&&u->IsSelected()&&u->CanMove()){ + //First see if we can attach to a collection point. + for(auto&cp:collectionPoints){ + geom2d::rectcpRect=geom2d::rect({cp->pos-cp->img.Sprite()->Size()/2,cp->img.Sprite()->Size()}); + if(geom2d::overlaps(cpRect,GetWorldMousePos())){ + if(cp->attachedUnit.expired()){ + u->SetTargetCollectionPoint(cp,u); + goto targetFound; //We found a target, so now we can just leave. + } + } + } + + //Okay, nothing to do here. Simply move to the selected position. u->SetTargetLocation(GetWorldMousePos()); } } } + targetFound: + int a; } } @@ -311,23 +326,26 @@ void VirusAttack::RenderCollectionPoints(CollectionPoint*cp){ if(geom2d::overlaps(cpRect,viewRegion)){ Pixel col; switch(cp->type){ - case HEALTH:{ - col=CONSTANT::HEALTH_COLOR; - }break; - case RANGE:{ - col=CONSTANT::RANGE_COLOR; - }break; - case ATKSPD:{ - col=CONSTANT::ATKSPD_COLOR; - }break; - case MOVESPD:{ - col=CONSTANT::MOVESPD_COLOR; - }break; - case PROCEDURE:{ - col=CONSTANT::PROCEDURE_COLOR; - }break; + case HEALTH:{ + col=CONSTANT::HEALTH_COLOR; + }break; + case RANGE:{ + col=CONSTANT::RANGE_COLOR; + }break; + case ATKSPD:{ + col=CONSTANT::ATKSPD_COLOR; + }break; + case MOVESPD:{ + col=CONSTANT::MOVESPD_COLOR; + }break; + case PROCEDURE:{ + col=CONSTANT::PROCEDURE_COLOR; + }break; } game.DrawRotatedDecal(cp->pos,cp->img.Decal(),cp->rot,cp->img.Sprite()->Size()/2,{1,1},col); + if(geom2d::overlaps(cpRect,GetWorldMousePos())){ + game.DrawRotatedDecal(cp->pos,IMAGES[MEMORY_COLLECTION_POINT_HIGHLIGHT]->Decal(),cp->rot,cp->img.Sprite()->Size()/2,{1,1},col); + } } } @@ -416,6 +434,19 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ DrawSelectionRectangle(); RenderFogOfWar(); + DrawResourceBar(); + + DrawMinimap(); + + std::sort(units.begin(),units.end(),[&](auto&u1,auto&u2){ + float dist1=geom2d::line(u1->GetGhostPos(),GetWorldMousePos()).length(); + float dist2=geom2d::line(u2->GetGhostPos(),GetWorldMousePos()).length(); + return dist1>dist2;}); + + return true; +} + +void VirusAttack::DrawResourceBar(){ GradientFillRectDecal({0,0},{float(ScreenWidth()),12.f},BLACK,{VERY_DARK_BLUE.r,VERY_DARK_BLUE.g,VERY_DARK_BLUE.b,128},{VERY_DARK_BLUE.r,VERY_DARK_BLUE.g,VERY_DARK_BLUE.b,128},BLACK); DrawRectDecal({0,0},{float(ScreenWidth()),12.f},{3, 194, 252}); auto DrawResourceDisplay=[&](int index,int resourceValue,Pixel col){ @@ -427,15 +458,6 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ DrawResourceDisplay(2,player_resources.moveSpd,CONSTANT::MOVESPD_COLOR); DrawResourceDisplay(3,player_resources.range,CONSTANT::RANGE_COLOR); DrawResourceDisplay(4,player_resources.procedure,CONSTANT::PROCEDURE_COLOR); - - DrawMinimap(); - - std::sort(units.begin(),units.end(),[&](auto&u1,auto&u2){ - float dist1=geom2d::line(u1->GetGhostPos(),GetWorldMousePos()).length(); - float dist2=geom2d::line(u2->GetGhostPos(),GetWorldMousePos()).length(); - return dist1>dist2;}); - - return true; } void VirusAttack::RenderFogOfWar(){ diff --git a/olcCodeJam2023Entry/VirusAttack.h b/olcCodeJam2023Entry/VirusAttack.h index 3eca249..3017654 100644 --- a/olcCodeJam2023Entry/VirusAttack.h +++ b/olcCodeJam2023Entry/VirusAttack.h @@ -29,7 +29,7 @@ class VirusAttack : public olc::PixelGameEngine { private: std::vector>units; - std::vector>collectionPoints; + std::vector>collectionPoints; std::vector>deathAnimations; std::vectordebuffIcons; @@ -63,6 +63,7 @@ private: void RenderCollectionPoints(CollectionPoint*cp); void RenderFogOfWar(); void InitializeSounds(); + void DrawResourceBar(); public: VirusAttack(); diff --git a/olcCodeJam2023Entry/assets/memory_collection_point_highlight.png b/olcCodeJam2023Entry/assets/memory_collection_point_highlight.png new file mode 100644 index 0000000000000000000000000000000000000000..5b8f7c1c422104873991e9bce389f19f6cf9d1aa GIT binary patch literal 12077 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 literal 0 HcmV?d00001