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.
236 lines
6.8 KiB
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;
|
|
} |