#define OLC_PGE_APPLICATION #include "pixelGameEngine.h" #include #include "gameDefines.h" #include Meteos*game; struct BlockMatchingInfo{ int col; int ind; int c=-1; bool changeToLaunched=true; }; bool Meteos::OnUserCreate() { game=this; SPRITES["blocks_test.png"].Load("assets/blocks_test.png"); std::random_device rd; //Will be used to obtain a seed for the random number engine gen=std::mt19937(rd()); //Standard mersenne_twister_engine seeded with rd() randBlockPos=std::uniform_int_distribution<>(0, 9); coinFlip=std::uniform_int_distribution<>(0, 1); comboOverlayOffset=std::uniform_int_distribution<>(-16,16); gameBoard=Board({10,14},0.02f,0.04f,1.2f,0.04f,0.4f,{-1.f,-1.5f,-2.f,-2.5f,-4.f},1.7f,2.0f,0.2f,{3,3,1,2,3,0,0,0,0,0}, 60*10,SPRITES["blocks_test.png"]); return true; } bool Meteos::OnUserUpdate(float fElapsedTime) { if (gameCanRun){ accumulatedTime+=fElapsedTime; if (accumulatedTime>=1/60.0f) { updateGame(1/60.0f); frameTime++; accumulatedTime=0; } handleInput(); } drawGame(fElapsedTime,!gameCanRun); return true; } void Meteos::handleInput(){ if (GetMouse(0).bHeld){ int mouseX=(GetMouseX()-gameBoard.drawOffset.x); int mouseY=(GetMouseY()-gameBoard.drawOffset.y); int mouseCol=mouseX/12; int mouseRow=mouseY/12; if (mouseCol>=0&&mouseColmouseY){ SelectedBlockData newData={mouseCol,j,i}; if (gameBoard.selectedBlock.col!=-1&&mouseCol==gameBoard.selectedBlock.col){ //See if these two can be swapped. Block&b1=gameBoard.getBlock(gameBoard.selectedBlock); Block&b2=gameBoard.getBlock(newData); int y1=(gameBoard.selectedBlock.c!=-1)?gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlockPosition(gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks()[gameBoard.selectedBlock.ind]).y:gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind].pos.y; int y2=(newData.c!=-1)?gameBoard.getBlockClumps()[newData.c].getBlockPosition(gameBoard.getBlockClumps()[newData.c].getBlocks()[newData.ind]).y:gameBoard.getBlocks(newData.col)[newData.ind].pos.y; if (b1.pos.x==b2.pos.x&&std::abs(y1-y2)<=12&&&b1!=&b2){ //Swap the two! BlockColor tempCol=b1.col; b1.col=b2.col; b2.col=tempCol; } } gameBoard.selectedBlock=newData; goto found; } } } } found: if (gameBoard.selectedBlock.c==-1&&gameBoard.selectedBlock.col!=-1&&mouseRowgameBoard.getBlocks(gameBoard.selectedBlock.col).size()&&gameBoard.getBlocks(gameBoard.selectedBlock.col)[gameBoard.selectedBlock.ind].pos.y>12){ for (int i=0;i=gameBoard.spawnRate){ lastBlockSpawn-=gameBoard.spawnRate; gameBoard.spawnBlock(randBlockPos(gen)); } } void Meteos::handleBlockGravity(float fElapsedTime){ for (int i=gameBoard.getBlockClumps().size()-1;i>=0;i--){ BlockClump&c=gameBoard.getBlockClumps()[i]; if (c.launchTime>0) { c.launchTime-=fElapsedTime; } else if (c.combo>0) { c.vspeed+=gameBoard.comboGravity; if (c.vspeed>gameBoard.comboMaxGravity){ c.vspeed=gameBoard.comboMaxGravity; } } else { c.vspeed+=gameBoard.gravity; if (c.vspeed>gameBoard.maxGravity){ c.vspeed=gameBoard.maxGravity; } } if (c.flinged&&c.y<12*3){ c.flinged=false; c.launchTime=0; } for (int j=gameBoard.getBlockClumps().size()-1;j>=0;j--) { if (i==j) continue; BlockClump&c2=gameBoard.getBlockClumps()[j]; for (int k=c2.getBlocks().size()-1;k>=0;k--) { Block&b2=c2.getBlocks()[k]; for (int l=c.getBlocks().size()-1;l>=0;l--) { Block&b3=c.getBlocks()[l]; if (c2.getBlockPosition(b2).x==c.getBlockPosition(b3).x&& c2.getBlockPosition(b2).y+12>=c.getBlockPosition(b3).y&& c2.getBlockPosition(b2).y<=c.getBlockPosition(b3).y+12) { c.y=(int)c.y; c2.y=(int)c2.y; if (c2.getBlockPosition(b2).y>c.getBlockPosition(b3).y) { c.y-=12-(c2.getBlockPosition(b2).y-c.getBlockPosition(b3).y); c.y-=fmod(c.y-c2.y,12); if (fmod(c2.y-c.y,12)!=0){ std::cout<<"Difference is not divisible by 12!! Value:"<=j){ i--; } gameBoard.removeClump(j); goto nextClumpCollisionCheck; } } } } nextClumpCollisionCheck:; for (int j=0;j=b2.pos.y&&c.getBlockPosition(b).y<=b2.pos.y+12){ c.y-=c.getBlockPosition(b).y+12-b2.pos.y; c.vspeed=0; if (c.landTime>=gameBoard.landTime) { gameBoard.convertClump(i); } else { c.landTime+=fElapsedTime; } goto nextClump; } } if (c.getBlockPosition(b).y>=gameBoard.yBottom) { c.y-=c.getBlockPosition(b).y-gameBoard.yBottom; c.vspeed=0; if (c.landTime>=gameBoard.landTime) { gameBoard.convertClump(i); } else { c.landTime+=fElapsedTime; } goto nextClump; } } c.landTime=0; nextClump:; } } void Meteos::matchFlyingBlockClumps(){ for (int g=0;gmatchedBlockIDs; for (Block&b:c.getBlocks()) { b.addedToLaunchList=false; } for (int i=0;itempMatchIDsX; std::vectortempMatchIDsY; float targetX=b.pos.x; float targetY=b.pos.y; bool found=false; tempMatchIDsX.push_back({(int)b.pos.x/12,i,g}); tempMatchIDsY.push_back({(int)b.pos.x/12,i,g}); rightCheck: float checkX=targetX+12; float checkY=targetY; do{ found=false; for (int j=0;j0){ for (int h=0;h0){ for (int j=0;j0){ for (int h=0;h0){ for (int j=0;j0){ for (int h=0;h0){ for (int j=0;j0){ for (int h=0;h0){ for (int j=0;j2||tempMatchIDsY.size()>2) { if (tempMatchIDsX.size()>2) { for (BlockMatchingInfo i:tempMatchIDsX) { if (i.c!=g){ for (int j=0;j2) { for (BlockMatchingInfo i:tempMatchIDsY) { if (i.c!=g){ for (int j=0;j0){ c.vspeed=gameBoard.launchSpd[std::min(c.combo,(int)gameBoard.launchSpd.size()-1)]/(1+(c.getBlocks().size()*gameBoard.blockWeight)); c.launchTime=gameBoard.launchTime; c.combo++; score+=MATCH_SCORE*c.combo; displayTargetScore+=MATCH_SCORE*c.combo; vi2d randomOffset={comboOverlayOffset(gen),comboOverlayOffset(gen)}; comboDisplayList.push_back({c.getBlockPosition(gameBoard.getBlockClumps()[matchedBlockIDs[0].c].getBlocks()[matchedBlockIDs[0].ind])+randomOffset,c.combo}); //std::cout<<"Combo value is "<matchedBlockIDs; //Col followed by index for (int i=0;itempMatchIDsX; //Col followed by index std::vectortempMatchIDsY; //Col followed by index float targetX=b.pos.x; float targetY=b.pos.y; bool found=false; tempMatchIDsX.push_back({i,j}); tempMatchIDsY.push_back({i,j}); rightBoardCheck: float checkX=1; float checkY=targetY; do{ found=false; if (i+checkX0) { for (int l=0;l=0) { for (int k=0;k0) { for (int l=0;l0) { for (int l=0;l0) { for (int l=0;l2||tempMatchIDsY.size()>2) { if (tempMatchIDsX.size()>2) { for (BlockMatchingInfo&info:tempMatchIDsX) { if (info.c!=-1) { BlockClump&c=gameBoard.getBlockClumps()[info.c]; Block&bb=c.getBlocks()[info.ind]; if (!bb.addedToLaunchList){ bb.addedToLaunchList=true; matchedBlockIDs.push_back(info); } } else { Block&bb=gameBoard.getBlocks(info.col)[info.ind]; if (!bb.addedToLaunchList){ bb.addedToLaunchList=true; matchedBlockIDs.push_back(info); } } } } if (tempMatchIDsY.size()>2) { for (BlockMatchingInfo&info:tempMatchIDsY) { if (info.c!=-1) { BlockClump&c=gameBoard.getBlockClumps()[info.c]; Block&bb=c.getBlocks()[info.ind]; if (!bb.addedToLaunchList){ bb.addedToLaunchList=true; matchedBlockIDs.push_back(info); } } else { Block&bb=gameBoard.getBlocks(info.col)[info.ind]; if (!bb.addedToLaunchList){ bb.addedToLaunchList=true; matchedBlockIDs.push_back(info); } } } } } } } if (matchedBlockIDs.size()>0) { BlockClump c; bool firstBlock=true; vf2d baseBlockPos; for (BlockMatchingInfo&info:matchedBlockIDs) { if (info.c!=-1){ Block&b=gameBoard.getBlockClumps()[info.c].getBlocks()[info.ind]; if (firstBlock) { baseBlockPos=gameBoard.getBlockClumps()[info.c].getBlockPosition(b); c.y=baseBlockPos.y-1; firstBlock=false; } b.col=BlockColor::LAUNCHED; } else { Block&b=gameBoard.getBlocks(info.col)[info.ind]; if (firstBlock) { baseBlockPos=b.pos; c.y=baseBlockPos.y-1; firstBlock=false; } b.col=BlockColor::LAUNCHED; } } for (BlockMatchingInfo&info:matchedBlockIDs) { if (info.c!=-1){ if (gameBoard.getBlockClumps()[info.c].getBlocks().size()>0){ if (c.combo=0;i--) { Block&b2=gameBoard.getBlockClumps()[info.c].getBlocks()[i]; if ((int)fmod(std::abs(std::round(gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y)-std::round(baseBlockPos.y)),12)!=0){ std::cout<<"Difference is not equal to 0! Value:"<<(int)fmod(std::abs(std::round(gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y)-std::round(baseBlockPos.y)),12)<<" "<=0;i--){ Block&b2=gameBoard.getBlocks(info.col)[i]; if (b2.pos.y<=yPos){ if ((int)fmod((int)b2.pos.y-(int)baseBlockPos.y,12)!=0){ std::cout<<"Difference is not equal to 0! Value:"<<(int)fmod((int)b2.pos.y-(int)baseBlockPos.y,12)<<" "<=0;i--){ //Resolve BlockClump movements. BlockClump&c=gameBoard.getBlockClumps()[i]; for (int j=c.getBlocks().size()-1;j>=0;j--){ Block&b=c.getBlocks()[j]; b.addedToLaunchList=false; if (c.vspeed<0&&c.getBlockPosition(b).y<0||b.markedForRemoval){ if (c.vspeed<0&&c.getBlockPosition(b).y<0){ accumulatedScore+=BASE_SCORE*c.combo; score+=BASE_SCORE*c.combo; blocksInAttackQueue++; lastBlockLaunched=0.0f; if (blocksInAttackQueue%10==0){ accumulatedScore+=BONUS_ATTACK_SCORE; score+=BONUS_ATTACK_SCORE; } } //std::cout<<"Removed block @"<=gameBoard.boardSize.y){ gameBoard.warningFlashingLevel[i]+=fElapsedTime; gameBoard.warningLevel++; noWarning=false; } else { gameBoard.warningFlashingLevel[i]=0; } for (int y=gameBoard.getBlocks(i).size()-1;y>=0;y--){ Block&b=gameBoard.getBlocks(i)[y]; b.addedToLaunchList=false; if (b.markedForRemoval){ gameBoard.removeBlock(i,y); continue; } } } if (noWarning){ gameBoard.warningLevel=0; } else if (gameBoard.warningLevel>=gameBoard.maxWarningLevel){ //Planet crashes! For now we just clear all blocks and clumps on the board. while (gameBoard.getBlockClumps().size()>0){ gameBoard.removeClump(0); } for (int i=0;i0){ gameBoard.removeBlock(i,0); } } gameBoard.warningLevel=0; } } void Meteos::validateSelectedBlock(){ //Invalidate the selected block if something is strange about it. if (gameBoard.selectedBlock.col!=-1){ if (gameBoard.selectedBlock.c!=-1){ if (!(gameBoard.selectedBlock.c=0;i--){ ComboOverlay&c=comboDisplayList[i]; c.lifetime++; c.pos.y-=0.1; if (c.lifetime>60){ comboDisplayList.erase(comboDisplayList.begin()+i); } } } void Meteos::updateGame(float fElapsedTime){ spawnBlocks(fElapsedTime); handleBlockGravity(fElapsedTime); matchBlocks(); cleanupBlocks(); handleWarningLevels(fElapsedTime); validateSelectedBlock(); handleComboAnimations(); if (blocksInAttackQueue){ lastBlockLaunched+=fElapsedTime; if (lastBlockLaunched>=blockLaunchWaitPeriod){ blocksInAttackQueue=0; accumulatedScore=0; displayTargetScore=score; } } lastScoreDisplayUpdate+=fElapsedTime; if (lastScoreDisplayUpdate>=SCORE_DISPLAY_UPDATE_RATE){ if (displayScore!=displayTargetScore){ int tempScore=displayTargetScore; int tempDisplayScore=displayScore; std::vectortargetScoreDigits; std::vectordisplayScoreDigits; while (tempScore>0){ int digit=tempScore%10; tempScore/=10; targetScoreDigits.insert(targetScoreDigits.begin(),digit); } while (tempDisplayScore>0){ int digit=tempDisplayScore%10; tempDisplayScore/=10; displayScoreDigits.insert(displayScoreDigits.begin(),digit); } //std::cout<0){ FillRectDecal({gameBoard.drawOffset.x+i*12,gameBoard.drawOffset.y},{12,(float)gameBoard.boardSize.y*12},Pixel(255,64,64,std::abs(sin(gameBoard.warningFlashingLevel[i]*M_PI))*128)); } } for (int i=0;i=3)?Pixel{207,103,0}:Pixel{255,255,255,180},{0.8,0.6}); } DrawStringDecal(gameBoard.drawOffset+vi2d{-8,-24}+vi2d{1,1},std::to_string(displayScore),BLACK,{2,2}); DrawStringDecal(gameBoard.drawOffset+vi2d{-8,-24},std::to_string(displayScore),WHITE,{2,2}); if (accumulatedScore>0){ DrawStringDecal(gameBoard.drawOffset+vi2d{0,-8}+vi2d{1,1},"+"+std::to_string(accumulatedScore),BLACK,{0.75,0.75}); DrawStringDecal(gameBoard.drawOffset+vi2d{0,-8},"+"+std::to_string(accumulatedScore),frameTime%5>2?Pixel{224, 184, 148}:WHITE,{0.75,0.75}); GradientFillRectDecal(gameBoard.drawOffset+vi2d{gameBoard.boardSize.x*12+16,0}, {32,32}, BLACK, VERY_DARK_GREEN, VERY_DARK_GREEN, BLACK); DrawRectDecal(gameBoard.drawOffset+vi2d{gameBoard.boardSize.x*12+16,0}, {32,32}, DARK_YELLOW); std::string attackQueueDisplay=""; if (blocksInAttackQueue<100){ attackQueueDisplay+='0'; } if (blocksInAttackQueue<10){ attackQueueDisplay+='0'; } attackQueueDisplay+=std::to_string(blocksInAttackQueue); Pixel attackQueueDisplayStringColor={66, 125, 92}; if(blocksInAttackQueue<80){ for (int y=0;y<=blocksInAttackQueue/10;y++){ for (int x=0;x<10;x++){ int amt=y*10+x; if (blocksInAttackQueue>=amt){ if(blocksInAttackQueue<40){ attackQueueDisplayStringColor={66, 120, 245}; DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor); } else { attackQueueDisplayStringColor={66, 245, 164}; DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor); } } } } } else if (blocksInAttackQueue<160){ for (int y=0;y<=blocksInAttackQueue/20;y++){ for (int x=0;x<10;x++){ int amt=y*20+x*2; if (blocksInAttackQueue>=amt){ if(blocksInAttackQueue<140){ attackQueueDisplayStringColor={237, 128, 107}; DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor); } else { attackQueueDisplayStringColor=YELLOW; DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor); } } } } } else { for (int y=0;y<=blocksInAttackQueue/40;y++){ for (int x=0;x<10;x++){ int amt=y*40+x*4; if (blocksInAttackQueue>=amt){ if(blocksInAttackQueue<320){ attackQueueDisplayStringColor=YELLOW; DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor); } else { attackQueueDisplayStringColor={176, 38, 255}; DrawRectDecal(gameBoard.drawOffset+vf2d{gameBoard.boardSize.x*12+16+26.f,27.6}-vf2d{x*2.4f,y*2.4f},{2.4,2.4},attackQueueDisplayStringColor); } } } } } DrawStringDecal(gameBoard.drawOffset-vf2d{GetTextSize(attackQueueDisplay).x*0.85f/2,0}+vi2d{gameBoard.boardSize.x*12+16+16,3},attackQueueDisplay,attackQueueDisplayStringColor,{0.85,1}); } } int main() { Meteos instance; if (instance.Construct(256, 240, 4, 4)) instance.Start(); return 0; }