You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
VirusAttack/olcCodeJam2023Entry/VirusAttack.cpp

236 lines
6.8 KiB

#define OLC_PGE_APPLICATION
#define OLC_SOUNDWAVE
#define OLC_PGEX_TRANSFORMEDVIEW
#include "olcUTIL_Geometry2D.h"
#include "VirusAttack.h"
VirusAttack::VirusAttack()
{
// Name your application
sAppName = "olcCodeJam 2023 Entry";
}
bool VirusAttack::OnUserCreate(){
game.Initialise(GetScreenSize());
CONSTANT::VIRUS_IMG1.Load("assets/unit.png");
CONSTANT::SELECTION_CIRCLE.Load("assets/selection_circle.png");
TILE.Load("assets/tile.png",nullptr,false,false);
MINIMAP_HUD.Load("assets/minimap_hud.png");
OUTLINE.Load("assets/outline.png");
MINIMAP_OUTLINE.Create(64,64);
units.push_back(std::make_unique<BasicUnit>(vf2d{32,32},CONSTANT::VIRUS_IMG1,true));
for(int i=0;i<10;i++){
if(rand()%2==0){
units.push_back(std::make_unique<BasicUnit>(vf2d{float(rand()%ScreenWidth()),float(rand()%ScreenHeight())},CONSTANT::VIRUS_IMG1,true));
} else {
units.push_back(std::make_unique<BasicUnit2>(vf2d{float(rand()%ScreenWidth()),float(rand()%ScreenHeight())},CONSTANT::VIRUS_IMG1,false));
}
}
return true;
}
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);
for(auto&u:units){
if(u->IsFriendly()){
if(geom2d::overlaps(selectionRegion,u->GetPos())){
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).bPressed){
bool selectedTarget=false;
for(auto&u:units){
if(!u->IsFriendly()){
geom2d::rect<float> unitRegion(u->GetPos()-u->GetUnitSize()/2,u->GetUnitSize());
if(geom2d::overlaps(unitRegion,GetWorldMousePos())){
for(auto&u2:units){
if(u2->IsFriendly()&&u2->IsSelected()){
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();
u->SetPos(u->GetPos()-dir*dist/2);
u2->SetPos(u2->GetPos()+dir*dist/2);
}
}
void VirusAttack::IdentifyClosestTarget(Unit*&closestUnit,float&closestDist,std::shared_ptr<Unit>u,std::shared_ptr<Unit>u2){
if(u->IsFriendly()!=u2->IsFriendly()){
geom2d::line<float>unitLine(u->GetPos(),u2->GetPos());
if(unitLine.length()<closestDist){
closestUnit=u2.get();
closestDist=unitLine.length();
}
}
}
void VirusAttack::DrawMinimap(){
DrawDecal(GetScreenSize()-MINIMAP_HUD.Sprite()->Size(),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(MINIMAP_OUTLINE.Sprite());
for(int y=0;y<64;y++){
for(int x=0;x<64;x++){
Draw(x,y,BLANK);
}
}
DrawRect((game.GetWorldOffset()/worldPixelSize*64),viewingTilesPct*64/game.GetWorldScale());
for(auto&u:units){
FillRect(u->GetPos()/worldPixelSize*64,vf2d{2,2}*u->GetUnitSize()/24,u->IsFriendly()?GREEN:RED);
}
MINIMAP_OUTLINE.Decal()->Update();
SetDrawTarget(nullptr);
DrawDecal(minimapTL,MINIMAP_OUTLINE.Decal());
}
void VirusAttack::HandlePanAndZoom(float fElapsedTime){
float speedScale=std::min(1.f,game.GetWorldScale().x);
if(GetKey(A).bHeld){
game.MoveWorldOffset(vf2d{-256*fElapsedTime,0}/speedScale);
}
if(GetKey(W).bHeld){
game.MoveWorldOffset(vf2d{0,-256*fElapsedTime}/speedScale);
}
if(GetKey(S).bHeld){
game.MoveWorldOffset(vf2d{0,256*fElapsedTime}/speedScale);
}
if(GetKey(D).bHeld){
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);
}
}
bool VirusAttack::OnUserUpdate(float fElapsedTime){
HandleDraggingSelection();
HandleRightClickMove();
HandlePanAndZoom(fElapsedTime);
HandleMinimapClick();
for(auto&tile:visibleTiles){
tile.second-=fElapsedTime;
}
std::erase_if(visibleTiles,[](std::pair<vf2d,float> key){return key.second<=0;});
for(auto&u:units){
Unit*closestUnit=nullptr;
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++){
visibleTiles[u->GetPos()/24/4+vi2d(x,y)]=5;
}
}
}
u->AttemptAttack(closestUnit);
u->Update(fElapsedTime);
}
game.DrawPartialDecal({0,0},CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE,TILE.Decal(),{0,0},CONSTANT::WORLD_SIZE*CONSTANT::TILE_SIZE,DARK_GREEN);
for(auto&u:units){
u->Draw(game);
}
for(auto&u:units){
u->DrawHud(game);
}
DrawSelectionRectangle();
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(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});
}
}
}
}
DrawMinimap();
return true;
}
int main()
{
VirusAttack app;
if (app.Construct(426, 320, 4, 4))
app.Start();
return 0;
}