|
|
|
#define OLC_PGE_APPLICATION
|
|
|
|
#define OLC_SOUNDWAVE
|
|
|
|
#define OLC_PGEX_TRANSFORMEDVIEW
|
|
|
|
#define AUDIO_LISTENER_IMPLEMENTATION
|
|
|
|
#define AUDIO_SOURCE_IMPLEMENTATION
|
|
|
|
#include "olcUTIL_Geometry2D.h"
|
|
|
|
#include "TileManager.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
#include "VirusAttack.h"
|
|
|
|
|
|
|
|
VirusAttack::VirusAttack()
|
|
|
|
{
|
|
|
|
// Name your application
|
|
|
|
sAppName = "olcCodeJam 2023 Entry";
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::InitializeImages(){
|
|
|
|
auto LoadImage=[&](Image img,std::string filepath,bool filter=false,bool clamp=true){
|
|
|
|
IMAGES[img]=std::make_unique<Renderable>();
|
|
|
|
IMAGES[img]->Load(filepath,nullptr,filter,clamp);
|
|
|
|
};
|
|
|
|
LoadImage(TILE,"assets/tile.png",false,false);
|
|
|
|
LoadImage(MINIMAP_HUD,"assets/minimap_hud.png");
|
|
|
|
LoadImage(OUTLINE,"assets/outline.png");
|
|
|
|
LoadImage(VIRUS_IMG1,"assets/unit.png");
|
|
|
|
LoadImage(SELECTION_CIRCLE,"assets/selection_circle.png");
|
|
|
|
LoadImage(MEMORY_COLLECTION_POINT,"assets/memory_collection_point.png");
|
|
|
|
LoadImage(LEFT_SHIFTER,"assets/left_shifter.png");
|
|
|
|
LoadImage(RIGHT_SHIFTER,"assets/right_shifter.png");
|
|
|
|
LoadImage(BIT_RESTORER,"assets/bit_restorer.png");
|
|
|
|
LoadImage(MEMORY_SWAPPER,"assets/memory_swapper.png");
|
|
|
|
LoadImage(CORRUPTER,"assets/corrupter.png");
|
|
|
|
LoadImage(UNIT_ALLOCATOR,"assets/shell.png");
|
|
|
|
LoadImage(RAM_BANK,"assets/ram_bank.png");
|
|
|
|
LoadImage(RANGE_INDICATOR,"assets/range_indicator.png");
|
|
|
|
LoadImage(DOWN_ARROW,"assets/down_arrow.png");
|
|
|
|
LoadImage(RED_X,"assets/red_x.png");
|
|
|
|
LoadImage(RLD,"assets/rld.png");
|
|
|
|
LoadImage(PRC,"assets/prc.png");
|
|
|
|
LoadImage(RNG,"assets/rng.png");
|
|
|
|
LoadImage(SPD,"assets/spd.png");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VirusAttack::OnUserCreate(){
|
|
|
|
SetPixelMode(Pixel::MASK);
|
|
|
|
|
|
|
|
game.Initialise(GetScreenSize());
|
|
|
|
|
|
|
|
InitializeImages();
|
|
|
|
|
|
|
|
IMAGES[MINIMAP_OUTLINE]=std::make_unique<Renderable>();
|
|
|
|
IMAGES[MINIMAP_OUTLINE]->Create(64,64);
|
|
|
|
|
|
|
|
IMAGES[MATRIX]=std::make_unique<Renderable>();
|
|
|
|
IMAGES[MATRIX]->Create(64,64,false,false);
|
|
|
|
IMAGES[MATRIX]->Sprite()->SetSampleMode(Sprite::PERIODIC);
|
|
|
|
|
|
|
|
AL.AudioSystemInit();
|
|
|
|
InitializeSounds();
|
|
|
|
|
|
|
|
units.push_back(std::make_unique<LeftShifter>(vf2d{128,128},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<RightShifter>(vf2d{129,129},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<BitRestorer>(vf2d{130,130},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<BitRestorer>(vf2d{130,140},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<MemorySwapper>(vf2d{131,131},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<Corrupter>(vf2d{132,132},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<MemoryAllocator>(vf2d{133,133},IMAGES,true));
|
|
|
|
units.push_back(std::make_unique<RAMBank>(this,vf2d{134,134},IMAGES,true));
|
|
|
|
|
|
|
|
|
|
|
|
for(int i=0;i<5;i++){
|
|
|
|
collectionPoints.push_back(std::make_unique<CollectionPoint>(this,vf2d{32.f+48*i,32.f},0,*IMAGES[MEMORY_COLLECTION_POINT],MemoryType(i)));
|
|
|
|
collectionPoints.push_back(std::make_unique<CollectionPoint>(this,vf2d{32.f,32.f+48*i},-PI/2,*IMAGES[MEMORY_COLLECTION_POINT],MemoryType(i)));
|
|
|
|
}
|
|
|
|
|
|
|
|
units.push_back(std::make_unique<RAMBank>(this,vf2d{320,320},IMAGES,false));
|
|
|
|
|
|
|
|
units.push_back(std::make_unique<RightShifter>(vf2d{360,300},IMAGES,false));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::InitializeSounds(){
|
|
|
|
int soundIndex=0;
|
|
|
|
auto LoadSound=[&](Audio&audio,std::string soundFilename){
|
|
|
|
audio.AL=&AL;
|
|
|
|
audio.LoadAudioSample(soundIndex,std::string("./assets/"+soundFilename).c_str());
|
|
|
|
soundIndex++;
|
|
|
|
};
|
|
|
|
|
|
|
|
AS_Test.SetDefaults(5,1,0,1,false);
|
|
|
|
AS_Test.fPlaySpeed=5;
|
|
|
|
|
|
|
|
LoadSound(AS_Test,"test.wav");
|
|
|
|
LoadSound(explosion,"SampleA.wav");
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::HandleDraggingSelection(){
|
|
|
|
auto NotClickingOnMinimap=[&](){return !(GetMouseX()>=ScreenWidth()-64&&GetMouseY()>=ScreenHeight()-64);};
|
|
|
|
if(GetMouse(0).bPressed){
|
|
|
|
if(NotClickingOnMinimap()){
|
|
|
|
for(auto&u:units){
|
|
|
|
u->Deselect();
|
|
|
|
}
|
|
|
|
if(startingDragPos==CONSTANT::UNSELECTED){
|
|
|
|
startingDragPos=GetWorldMousePos();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(GetMouse(0).bReleased&&startingDragPos!=CONSTANT::UNSELECTED){
|
|
|
|
vf2d endDragPos=GetWorldMousePos();
|
|
|
|
if(endDragPos.x<startingDragPos.x){std::swap(startingDragPos.x,endDragPos.x);}
|
|
|
|
if(endDragPos.y<startingDragPos.y){std::swap(startingDragPos.y,endDragPos.y);}
|
|
|
|
geom2d::rect<float> selectionRegion(startingDragPos,endDragPos-startingDragPos);
|
|
|
|
if(selectionRegion.size.x<12){
|
|
|
|
selectionRegion.pos.x-=12-selectionRegion.size.x/2;
|
|
|
|
selectionRegion.size.x+=12-selectionRegion.size.x/2;
|
|
|
|
}
|
|
|
|
if(selectionRegion.size.y<12){
|
|
|
|
selectionRegion.pos.y-=12-selectionRegion.size.y/2;
|
|
|
|
selectionRegion.size.y+=12-selectionRegion.size.y/2;
|
|
|
|
}
|
|
|
|
for(auto&u:units){
|
|
|
|
if(u->IsFriendly()){
|
|
|
|
if(geom2d::overlaps(selectionRegion,geom2d::circle<float>(u->GetPos(),u->GetUnitSize().x/2))){
|
|
|
|
u->Select();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
startingDragPos=CONSTANT::UNSELECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vf2d VirusAttack::GetWorldMousePos(){
|
|
|
|
return game.ScreenToWorld(GetMousePos());
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::DrawSelectionRectangle(){
|
|
|
|
if(startingDragPos!=CONSTANT::UNSELECTED){
|
|
|
|
game.FillRectDecal(startingDragPos,GetWorldMousePos()-startingDragPos,{255,255,0,128});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::HandleRightClickMove(){
|
|
|
|
if (GetMouse(1).bHeld){
|
|
|
|
bool selectedTarget=false;
|
|
|
|
for(auto&u:units){
|
|
|
|
geom2d::rect<float> unitRegion(u->GetPos()-u->GetUnitSize()/2,u->GetUnitSize());
|
|
|
|
if(geom2d::overlaps(unitRegion,GetWorldMousePos())){
|
|
|
|
for(auto&u2:units){
|
|
|
|
if(&u!=&u2){
|
|
|
|
if(!u->IsFriendly()&&u2->IsFriendly()&&u2->IsSelected()&&u2->CanInteractWithEnemies()){
|
|
|
|
u2->SetTargetUnit(u);
|
|
|
|
} else
|
|
|
|
if(u->IsFriendly()&&u2->IsFriendly()&&u2->IsSelected()&&u2->CanInteractWithAllies()){
|
|
|
|
u2->SetTargetUnit(u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
selectedTarget=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!selectedTarget){
|
|
|
|
for(auto&u:units){
|
|
|
|
if(u->IsFriendly()&&u->IsSelected()){
|
|
|
|
u->SetTargetLocation(GetWorldMousePos());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::CollisionChecking(std::shared_ptr<Unit>u,std::shared_ptr<Unit>u2){
|
|
|
|
if(u!=u2&&geom2d::overlaps(geom2d::circle<float>(u->GetPos(),u->GetUnitSize().x/2),geom2d::circle<float>(u2->GetPos(),u2->GetUnitSize().x/2))){
|
|
|
|
geom2d::line<float>collisionLine(u->GetPos(),u2->GetPos());
|
|
|
|
float maxDist=u->GetUnitSize().x/2+u2->GetUnitSize().x/2;
|
|
|
|
float dist=maxDist-collisionLine.length();
|
|
|
|
vf2d dir=collisionLine.vector().norm();
|
|
|
|
if(u->IsMoveable()){
|
|
|
|
u->SetPos(u->GetPos()-dir*dist/2);
|
|
|
|
}
|
|
|
|
if(u2->IsMoveable()){
|
|
|
|
u2->SetPos(u2->GetPos()+dir*dist/2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::IdentifyClosestTarget(std::weak_ptr<Unit>&closestUnit,float&closestDist,std::shared_ptr<Unit>u,std::shared_ptr<Unit>u2){
|
|
|
|
if(u==u2)return;
|
|
|
|
bool canInteract;
|
|
|
|
canInteract=
|
|
|
|
(u->IsFriendly()&&u->CanInteractWithEnemies()&&!u2->IsFriendly())||
|
|
|
|
(u->IsFriendly()&&u->CanInteractWithAllies()&&u2->IsFriendly())||
|
|
|
|
(!u->IsFriendly()&&u->CanInteractWithEnemies()&&u2->IsFriendly())||
|
|
|
|
(!u->IsFriendly()&&u->CanInteractWithAllies()&&!u2->IsFriendly());
|
|
|
|
if(canInteract){
|
|
|
|
geom2d::line<float>unitLine(u->GetPos(),u2->GetPos());
|
|
|
|
if(unitLine.length()<closestDist){
|
|
|
|
closestUnit=u2;
|
|
|
|
closestDist=unitLine.length();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::DrawMinimap(){
|
|
|
|
DrawDecal(GetScreenSize()-IMAGES[MINIMAP_HUD]->Sprite()->Size(),IMAGES[MINIMAP_HUD]->Decal(),{1,1});
|
|
|
|
vf2d minimapTL=GetScreenSize()-vf2d{64,64};
|
|
|
|
vi2d worldPixelSize=CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE;
|
|
|
|
vf2d viewingTilesPct=vf2d{float(ScreenWidth()),float(ScreenHeight())}/CONSTANT::TILE_SIZE/CONSTANT::WORLD_SIZE;
|
|
|
|
SetDrawTarget(IMAGES[MINIMAP_OUTLINE]->Sprite());
|
|
|
|
Clear(BLANK);
|
|
|
|
DrawRect((game.GetWorldOffset()/worldPixelSize*64),viewingTilesPct*64/game.GetWorldScale());
|
|
|
|
for(auto&u:units){
|
|
|
|
vf2d squareSize=u->GetUnitSize()/vf2d(CONSTANT::WORLD_SIZE);
|
|
|
|
squareSize.x=std::round(std::max(1.f,squareSize.x));
|
|
|
|
squareSize.y=std::round(std::max(1.f,squareSize.y));
|
|
|
|
FillRect(u->GetGhostPos()/worldPixelSize*64-squareSize,squareSize*2,u->IsFriendly()?GREEN:RED);
|
|
|
|
}
|
|
|
|
IMAGES[MINIMAP_OUTLINE]->Decal()->Update();
|
|
|
|
SetDrawTarget(nullptr);
|
|
|
|
DrawDecal(minimapTL,IMAGES[MINIMAP_OUTLINE]->Decal());
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::HandlePanAndZoom(float fElapsedTime){
|
|
|
|
float speedScale=std::min(1.f,game.GetWorldScale().x);
|
|
|
|
if(GetKey(A).bHeld/*||GetMouseX()<=CONSTANT::SCROLL_BOUNDARY*/){
|
|
|
|
game.MoveWorldOffset(vf2d{-256*fElapsedTime,0}/speedScale);
|
|
|
|
}
|
|
|
|
if(GetKey(W).bHeld/*||GetMouseY()<=CONSTANT::SCROLL_BOUNDARY*/){
|
|
|
|
game.MoveWorldOffset(vf2d{0,-256*fElapsedTime}/speedScale);
|
|
|
|
}
|
|
|
|
if(GetKey(S).bHeld/*||GetMouseY()>=ScreenHeight()-CONSTANT::SCROLL_BOUNDARY*/){
|
|
|
|
game.MoveWorldOffset(vf2d{0,256*fElapsedTime}/speedScale);
|
|
|
|
}
|
|
|
|
if(GetKey(D).bHeld/*||GetMouseX()>=ScreenWidth()-CONSTANT::SCROLL_BOUNDARY*/){
|
|
|
|
game.MoveWorldOffset(vf2d{256*fElapsedTime,0}/speedScale);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(GetMouseWheel()>0){
|
|
|
|
if(game.GetWorldScale().x<2){
|
|
|
|
game.ZoomAtScreenPos(1.25,GetMousePos());
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
if(GetMouseWheel()<0){
|
|
|
|
if(game.GetWorldScale().x>0.5){
|
|
|
|
game.ZoomAtScreenPos(0.75,GetMousePos());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::HandleMinimapClick(){
|
|
|
|
if(startingDragPos==CONSTANT::UNSELECTED&&GetMouse(0).bHeld&&GetMouseX()>=ScreenWidth()-64&&GetMouseY()>=ScreenHeight()-64){
|
|
|
|
vf2d minimapTL=GetScreenSize()-vf2d{64,64};
|
|
|
|
game.SetWorldOffset(vf2d(GetMousePos()-minimapTL)/64*CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE-vf2d(GetScreenSize())/game.GetWorldScale()/2.f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::UpdateMatrixTexture(float fElapsedTime){
|
|
|
|
if(matrixTimer==0){
|
|
|
|
activeLetters.emplace_back(vf2d{float(rand()%64),float(64)},util::random(-40)-20,matrixLetters[rand()%matrixLetters.size()]);
|
|
|
|
matrixTimer=util::random(0.125);
|
|
|
|
}
|
|
|
|
if(updatePixelsTimer==0){
|
|
|
|
SetDrawTarget(IMAGES[MATRIX]->Sprite());
|
|
|
|
Sprite*img=IMAGES[MATRIX]->Sprite();
|
|
|
|
for(int y=63;y>=0;y--){
|
|
|
|
for(int x=63;x>=0;x--){
|
|
|
|
Pixel col=img->GetPixel(x,y);
|
|
|
|
if(col.r>0){
|
|
|
|
if(x>0){
|
|
|
|
Pixel leftCol=img->GetPixel(x-1,y);
|
|
|
|
if(leftCol.r<col.r){
|
|
|
|
leftCol=PixelLerp(col,leftCol,0.125);
|
|
|
|
}
|
|
|
|
Draw(x-1,y,leftCol);
|
|
|
|
}
|
|
|
|
if(x<img->width-1){
|
|
|
|
Pixel rightCol=img->GetPixel(x+1,y);
|
|
|
|
if(rightCol.r<col.r){
|
|
|
|
rightCol=PixelLerp(col,rightCol,0.125);
|
|
|
|
}
|
|
|
|
Draw(x+1,y,rightCol);
|
|
|
|
}
|
|
|
|
col/=8;
|
|
|
|
Draw(x,y,col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(int y=0;y<64;y++){
|
|
|
|
Draw({0,y},img->GetPixel(1,y));
|
|
|
|
}
|
|
|
|
SetDrawTarget(nullptr);
|
|
|
|
updatePixelsTimer=0.1;
|
|
|
|
}
|
|
|
|
if(activeLetters.size()>0){
|
|
|
|
SetDrawTarget(IMAGES[MATRIX]->Sprite());
|
|
|
|
for(Letter&letter:activeLetters){
|
|
|
|
letter.pos.y+=letter.spd*fElapsedTime;
|
|
|
|
DrawString(letter.pos,std::string(1,letter.c));
|
|
|
|
}
|
|
|
|
SetDrawTarget(nullptr);
|
|
|
|
IMAGES[MATRIX]->Decal()->Update();
|
|
|
|
}
|
|
|
|
matrixTimer=std::max(0.f,matrixTimer-fElapsedTime);
|
|
|
|
updatePixelsTimer=std::max(0.f,updatePixelsTimer-fElapsedTime);
|
|
|
|
std::erase_if(activeLetters,[](Letter&letter){return letter.pos.y<-32;});
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::RenderCollectionPoints(CollectionPoint*cp){
|
|
|
|
geom2d::rect<float>cpRect=geom2d::rect<float>({cp->pos-cp->img.Sprite()->Size()/2,cp->img.Sprite()->Size()});
|
|
|
|
geom2d::rect<float>viewRegion=geom2d::rect<float>({game.GetWorldTL(),game.GetWorldVisibleArea()});
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
game.DrawRotatedDecal(cp->pos,cp->img.Decal(),cp->rot,cp->img.Sprite()->Size()/2,{1,1},col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VirusAttack::OnUserUpdate(float fElapsedTime){
|
|
|
|
UpdateMatrixTexture(fElapsedTime);
|
|
|
|
HandleDraggingSelection();
|
|
|
|
HandleRightClickMove();
|
|
|
|
HandlePanAndZoom(fElapsedTime);
|
|
|
|
HandleMinimapClick();
|
|
|
|
AL.vecPos=game.GetWorldOffset()+GetScreenSize()/2;
|
|
|
|
AL.OnUserUpdate(fElapsedTime);
|
|
|
|
|
|
|
|
for(auto&tile:TileManager::visibleTiles){
|
|
|
|
tile.second-=fElapsedTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::erase_if(TileManager::visibleTiles,[](std::pair<vf2d,float> key){return key.second<=0;});
|
|
|
|
|
|
|
|
for(auto&u:units){
|
|
|
|
std::weak_ptr<Unit>closestUnit;
|
|
|
|
float closestDist=999999;
|
|
|
|
for(auto&u2:units){
|
|
|
|
IdentifyClosestTarget(closestUnit,closestDist,u,u2);
|
|
|
|
CollisionChecking(u,u2);
|
|
|
|
}
|
|
|
|
if(u->IsFriendly()){
|
|
|
|
for(int y=-1;y<2;y++){
|
|
|
|
for(int x=-1;x<2;x++){
|
|
|
|
TileManager::visibleTiles[u->GetPos()/24/4+vi2d(x,y)]=5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u->AttemptAttack(u,closestUnit,units);
|
|
|
|
u->_Update(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::erase_if(units,[&](std::shared_ptr<Unit>u){
|
|
|
|
if(u->GetHealth()==0){
|
|
|
|
deathAnimations.emplace_back(std::make_unique<DeathAnimation>(this,u->GetPos(),u->GetImage(),*IMAGES[MATRIX],u->IsFriendly()));
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
game.DrawPartialDecal({0,0},CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE,IMAGES[TILE]->Decal(),{0,0},CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE,DARK_GREEN);
|
|
|
|
|
|
|
|
for(auto&u:units){
|
|
|
|
u->DrawRangeIndicator(this,game,IMAGES);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(auto&u:units){
|
|
|
|
u->Draw(game,IMAGES);
|
|
|
|
}
|
|
|
|
for(auto&deadUnit:deathAnimations){
|
|
|
|
deadUnit->Update(fElapsedTime);
|
|
|
|
deadUnit->Draw(game,this);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::erase_if(deathAnimations,[](auto&u){return u->IsDone();});
|
|
|
|
|
|
|
|
for(auto&collectionPoint:collectionPoints){
|
|
|
|
collectionPoint->Update(this,*IMAGES[MATRIX]);
|
|
|
|
RenderCollectionPoints(collectionPoint.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
for(auto&u:units){
|
|
|
|
u->DrawHud(game,IMAGES);
|
|
|
|
}
|
|
|
|
|
|
|
|
DrawSelectionRectangle();
|
|
|
|
RenderFogOfWar();
|
|
|
|
|
|
|
|
DrawMinimap();
|
|
|
|
|
|
|
|
std::sort(units.begin(),units.end(),[&](auto&u1,auto&u2){
|
|
|
|
float dist1=geom2d::line<float>(u1->GetGhostPos(),GetWorldMousePos()).length();
|
|
|
|
float dist2=geom2d::line<float>(u2->GetGhostPos(),GetWorldMousePos()).length();
|
|
|
|
return dist1>dist2;});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::RenderFogOfWar(){
|
|
|
|
for(int y=game.GetTopLeftTile().y/96-1;y<=game.GetBottomRightTile().y/96+1;y++){
|
|
|
|
for(int x=game.GetTopLeftTile().x/96-1;x<=game.GetBottomRightTile().x/96+1;x++){
|
|
|
|
if(TileManager::visibleTiles.count(vi2d{x,y})==0){
|
|
|
|
if(x>=0&&y>=0&&x<=CONSTANT::WORLD_SIZE.x*CONSTANT::TILE_SIZE.x&&y<=CONSTANT::WORLD_SIZE.y*CONSTANT::TILE_SIZE.y){
|
|
|
|
game.FillRectDecal(vf2d{float(x),float(y)}*96,{96,96},{0,0,0,128});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VirusAttack::CollectionPoint::CollectionPoint(PixelGameEngine*pge,vf2d pos,float rot,Renderable&collectionPointImg,MemoryType type)
|
|
|
|
:pos(pos),rot(rot),type(type),originalCollectionPointImg(collectionPointImg.Sprite()),randomOffset({util::random(128),util::random(128)}){
|
|
|
|
img.Create(collectionPointImg.Sprite()->width,collectionPointImg.Sprite()->height);
|
|
|
|
pge->SetDrawTarget(img.Sprite());
|
|
|
|
pge->Clear(BLANK);
|
|
|
|
pge->DrawSprite({0,0},collectionPointImg.Sprite());
|
|
|
|
pge->SetDrawTarget(nullptr);
|
|
|
|
img.Decal()->Update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VirusAttack::CollectionPoint::Update(PixelGameEngine*pge,Renderable&matrixImg){
|
|
|
|
pge->SetDrawTarget(img.Sprite());
|
|
|
|
for(int y=0;y<img.Sprite()->height;y++){
|
|
|
|
for(int x=0;x<img.Sprite()->width;x++){
|
|
|
|
Pixel col=originalCollectionPointImg->GetPixel(x,y);
|
|
|
|
if(col==WHITE){
|
|
|
|
pge->Draw(x,y,matrixImg.Sprite()->GetPixel(int(x+randomOffset.x),int(y+randomOffset.y)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
img.Decal()->Update();
|
|
|
|
pge->SetDrawTarget(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
VirusAttack app;
|
|
|
|
if (app.Construct(426, 320, 4, 4))
|
|
|
|
app.Start();
|
|
|
|
return 0;
|
|
|
|
}
|