Attempt #7?!
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.
Meteos/main.cpp

594 lines
19 KiB

#define OLC_PGE_APPLICATION
#include "pixelGameEngine.h"
#include <random>
#include "gameDefines.h"
#include <assert.h>
Meteos*game;
struct BlockMatchingInfo{
int col;
int ind;
int c=-1;
};
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);
gameBoard=Board({10,14},0.04f,1.2f,-1.f,1.7f,2.0f,1.0f,{3,3,1,2,3,0,0,0,0,0},SPRITES["blocks_test.png"]);
return true;
}
bool Meteos::OnUserUpdate(float fElapsedTime)
{
accumulatedTime+=fElapsedTime;
if (accumulatedTime>=1/60.0f) {
updateGame(1/60.0f);
accumulatedTime=0;
}
drawGame(fElapsedTime);
return true;
}
void Meteos::updateGame(float fElapsedTime){
lastBlockSpawn+=fElapsedTime;
if (lastBlockSpawn>=gameBoard.spawnRate){
lastBlockSpawn-=gameBoard.spawnRate;
gameBoard.spawnBlock(randBlockPos(gen));
}
for (int i=0;i<gameBoard.getBlockClumps().size();i++){
BlockClump&c=gameBoard.getBlockClumps()[i];
if (c.launchTime>0) {
c.launchTime-=fElapsedTime;
} else {
c.vspeed+=gameBoard.gravity;
}
if (c.vspeed>gameBoard.maxGravity){
c.vspeed=gameBoard.maxGravity;
}
for (int j=0;j<gameBoard.getBlockClumps().size();j++) {
if (i==j) continue;
BlockClump&c2=gameBoard.getBlockClumps()[j];
for (int k=0;k<c2.getBlocks().size();k++) {
Block&b2=c2.getBlocks()[k];
for (int l=0;l<c.getBlocks().size();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) {
if (c2.getBlockPosition(b2).y>c.getBlockPosition(b3).y) {
c.y-=12-(c2.getBlockPosition(b2).y-c.getBlockPosition(b3).y);
} else {
c2.y-=12-(c.getBlockPosition(b3).y-c2.getBlockPosition(b2).y);
}
float influence=(float)c.getBlocks().size()/(c.getBlocks().size()+c2.getBlocks().size());
int blockCount=c.getBlocks().size();
//Copy every block from one clump to the other
for (int m=0;m<c2.getBlocks().size();m++) {
Block&b4=c2.getBlocks()[m];
c.addBlock(b4.pos.x/12,(c2.getBlockPosition(b4).y-c.y)/12,b4.col);
}
if (blockCount+c2.getBlocks().size()!=c.getBlocks().size()) {
std::cout<<"Block size is: "<<c.getBlocks().size()<<" but expected "<<blockCount+c2.getBlocks().size()<<std::endl;
assert(false);
}
if (c.vspeed>0) {
c.vspeed/=4;
}
if (c2.vspeed>0) {
c2.vspeed/=4;
}
c.vspeed=c.vspeed*influence+c2.vspeed*(1-influence);
c.sortBlocks();
gameBoard.removeClump(j--);
goto nextClumpCollisionCheck;
}
}
}
}
nextClumpCollisionCheck:;
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
int col=b.pos.x/12;
for (int k=0;k<gameBoard.getBlocks(col).size();k++){
Block&b2=gameBoard.getBlocks(col)[k];
if (c.getBlockPosition(b).y+12>=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:;
}
for (BlockClump&c:gameBoard.getBlockClumps()){
std::vector<int>matchedBlockIDs;
for (Block&b:c.getBlocks()) {
b.addedToLaunchList=false;
}
for (int i=0;i<c.getBlocks().size();i++) {
Block&b=c.getBlocks()[i];
std::vector<int>tempMatchIDsX;
std::vector<int>tempMatchIDsY;
float targetX=b.pos.x;
float targetY=b.pos.y;
bool found=false;
tempMatchIDsX.push_back(i);
tempMatchIDsY.push_back(i);
rightCheck:
float checkX=targetX+12;
float checkY=targetY;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkX+=12;
tempMatchIDsX.push_back(j);
break;
}
}
}while(found);
leftCheck:
checkX=targetX-12;
checkY=targetY;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkX-=12;
tempMatchIDsX.push_back(j);
break;
}
}
}while(found);
upCheck:
checkX=targetX;
checkY=targetY-12;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkY-=12;
tempMatchIDsY.push_back(j);
break;
}
}
}while(found);
downCheck:
checkX=targetX;
checkY=targetY+12;
do{
found=false;
for (int j=0;j<c.getBlocks().size();j++){
Block&b2=c.getBlocks()[j];
if (i==j)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkY+=12;
tempMatchIDsY.push_back(j);
break;
}
}
}while(found);
if (tempMatchIDsX.size()>2||tempMatchIDsY.size()>2) {
if (tempMatchIDsX.size()>2) {
for (int i:tempMatchIDsX) {
Block&bb=c.getBlocks()[i];
if (!bb.addedToLaunchList) {
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(i);
}
}
}
if (tempMatchIDsY.size()>2) {
for (int i:tempMatchIDsY) {
Block&bb=c.getBlocks()[i];
if (!bb.addedToLaunchList) {
bb.addedToLaunchList=true;
matchedBlockIDs.push_back(i);
}
}
}
}
}
for (int i:matchedBlockIDs) {
Block&b=c.getBlocks()[i];
b.col=BlockColor::LAUNCHED;
c.vspeed=gameBoard.launchSpd;
c.launchTime=gameBoard.launchTime;
}
}
std::vector<BlockMatchingInfo>matchedBlockIDs; //Col followed by index
for (int i=0;i<gameBoard.boardSize.x;i++){
for (Block&b:gameBoard.getBlocks(i)) {
b.addedToLaunchList=false;
}
for (int j=0;j<gameBoard.getBlocks(i).size();j++) {
Block&b=gameBoard.getBlocks(i)[j];
std::vector<BlockMatchingInfo>tempMatchIDsX; //Col followed by index
std::vector<BlockMatchingInfo>tempMatchIDsY; //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+checkX<gameBoard.boardSize.x) {
for (int k=0;k<gameBoard.getBlocks(i+checkX).size();k++){
Block&b2=gameBoard.getBlocks(i+checkX)[k];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&b2.pos.y==checkY) {
found=true;
tempMatchIDsX.push_back({(int)(i+checkX),k});
checkX++;
goto outercheck2;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&c.getBlockPosition(b2).y==checkY){
found=true;
tempMatchIDsX.push_back({-1,l,k});
checkX++;
goto outercheck2;
}
}
}
}
outercheck2:;
}
}while(found);
leftBoardCheck:
checkX=-1;
checkY=targetY;
do{
found=false;
if (i+checkX>=0) {
for (int k=0;k<gameBoard.getBlocks(i+checkX).size();k++){
Block&b2=gameBoard.getBlocks(i+checkX)[k];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&b2.pos.y==checkY) {
found=true;
tempMatchIDsX.push_back({(int)(i+checkX),k});
checkX--;
goto outercheck3;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==b.pos.x+checkX*12&&c.getBlockPosition(b2).y==checkY){
found=true;
tempMatchIDsX.push_back({-1,l,k});
checkX--;
goto outercheck3;
}
}
}
}
outercheck3:;
}
}while(found);
upBoardCheck:
checkX=targetX;
checkY=targetY-12;
do{
found=false;
for (int k=0;k<gameBoard.getBlocks(i).size();k++){
Block&b2=gameBoard.getBlocks(i)[k];
if (j==k)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkY-=12;
tempMatchIDsY.push_back({i,k});
goto outercheck4;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&c.getBlockPosition(b2).x==checkX&&c.getBlockPosition(b2).y==checkY){
found=true;
checkY-=12;
tempMatchIDsY.push_back({-1,l,k});
goto outercheck4;
}
}
}
}
outercheck4:;
}while(found);
downBoardCheck:
checkX=targetX;
checkY=targetY+12;
do{
found=false;
for (int k=0;k<gameBoard.getBlocks(i).size();k++){
Block&b2=gameBoard.getBlocks(i)[k];
if (j==k)continue;
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&b2.pos.x==checkX&&b2.pos.y==checkY) {
found=true;
checkY+=12;
tempMatchIDsY.push_back({i,k});
goto outercheck1;
}
}
for (int k=0;k<gameBoard.getBlockClumps().size();k++){
BlockClump&c=gameBoard.getBlockClumps()[k];
if (c.landTime>0) {
for (int l=0;l<c.getBlocks().size();l++){
Block&b2=c.getBlocks()[l];
if (b.col==b2.col&&b2.col!=BlockColor::LAUNCHED&&c.getBlockPosition(b2).x==checkX&&c.getBlockPosition(b2).y==checkY){
found=true;
checkY+=12;
tempMatchIDsY.push_back({-1,l,k});
goto outercheck1;
}
}
}
}
outercheck1:;
}while(found);
if (tempMatchIDsX.size()>2||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;
int 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).y;
c.y=baseBlockPos-1;
firstBlock=false;
}
b.col=BlockColor::LAUNCHED;
} else {
Block&b=gameBoard.getBlocks(info.col)[info.ind];
if (firstBlock) {
baseBlockPos=b.pos.y;
c.y=baseBlockPos-1;
firstBlock=false;
}
b.col=BlockColor::LAUNCHED;
}
}
for (BlockMatchingInfo&info:matchedBlockIDs) {
if (info.c!=-1){
Block&b=gameBoard.getBlockClumps()[info.c].getBlocks()[info.ind];
for (Block&b2:gameBoard.getBlockClumps()[info.c].getBlocks()){
if (!b2.markedForRemoval&&gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y<=gameBoard.getBlockClumps()[info.c].getBlockPosition(b).y){
c.addBlock(b.pos.x/12,(gameBoard.getBlockClumps()[info.c].getBlockPosition(b2).y-baseBlockPos)/12,b2.col);
b2.markedForRemoval=true;
}
}
} else {
Block&b=gameBoard.getBlocks(info.col)[info.ind];
for (Block&b2:gameBoard.getBlocks(b.pos.x/12)) {
if (!b2.markedForRemoval&&b2.pos.y<=b.pos.y) {
c.addBlock(b.pos.x/12,(b2.pos.y-baseBlockPos)/12,b2.col);
b2.markedForRemoval=true;
}
}
}
}
gameBoard.addClump(c);
gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].vspeed=gameBoard.launchSpd;
gameBoard.getBlockClumps()[gameBoard.getBlockClumps().size()-1].launchTime=gameBoard.launchTime;
}
for (int i=0;i<gameBoard.getBlockClumps().size();i++){ //Resolve BlockClump movements.
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
b.addedToLaunchList=false;
if (c.vspeed<0&&c.getBlockPosition(b).y<0||b.markedForRemoval){
c.removeBlock(j--);
break;
}
}
c.y+=c.vspeed;
if (c.getBlocks().size()<=0) {
gameBoard.removeClump(i--);
continue;
}
}
for (int i=0;i<gameBoard.boardSize.x;i++){
for (int y=0;y<gameBoard.getBlocks(i).size();y++){
Block&b=gameBoard.getBlocks(i)[y];
if (b.markedForRemoval){
gameBoard.removeBlock(i,y--);
continue;
}
b.addedToLaunchList=false;
}
}
//Invalidate the selected block if something is strange about it.
if (gameBoard.selectedBlock.col!=-1){
if (gameBoard.selectedBlock.c!=-1){
if (!(gameBoard.selectedBlock.c<gameBoard.getBlockClumps().size()&&gameBoard.selectedBlock.ind<gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks().size()&&gameBoard.getBlockClumps()[gameBoard.selectedBlock.c].getBlocks()[gameBoard.selectedBlock.ind].pos.x/12==gameBoard.selectedBlock.col)){
gameBoard.selectedBlock={-1};
goto invalidatedExit;
}
} else {
if (!(gameBoard.selectedBlock.ind<gameBoard.getBlocks(gameBoard.selectedBlock.col).size())){
gameBoard.selectedBlock={-1};
goto invalidatedExit;
}
}
}
invalidatedExit:
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&&mouseCol<gameBoard.boardSize.x) {
for (int y=0;y<gameBoard.getBlocks(mouseCol).size();y++){
Block&b=gameBoard.getBlocks(mouseCol)[y];
if (b.pos.y/12==mouseRow){
SelectedBlockData newData={mouseCol,y,-1};
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){
//Swap the two!
BlockColor tempCol=b1.col;
b1.col=b2.col;
b2.col=tempCol;
}
}
gameBoard.selectedBlock=newData;
goto found;
}
}
for (int i=0;i<gameBoard.getBlockClumps().size();i++){
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
if (b.pos.x/12==mouseCol&&c.getBlockPosition(b).y<=mouseY&&c.getBlockPosition(b).y+12>=mouseY){
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){
//Swap the two!
BlockColor tempCol=b1.col;
b1.col=b2.col;
b2.col=tempCol;
}
}
gameBoard.selectedBlock=newData;
goto found;
}
}
}
found:;
}
}
if (GetMouse(0).bReleased){
gameBoard.selectedBlock={-1};
}
}
void Meteos::drawGame(float fElapsedTime){
Clear(Pixel(32,32,255));
for (int x=-1;x<=gameBoard.boardSize.x;x++){
for (int y=0;y<=gameBoard.boardSize.y;y++){
if (x==-1||x==10||y==14){
FillRectDecal({(float)(gameBoard.drawOffset.x+x*12),(float)(gameBoard.drawOffset.y+y*12)},{12,12},Pixel(0,0,0,255));
} else {
DrawRectDecal({(float)(gameBoard.drawOffset.x+x*12),(float)(gameBoard.drawOffset.y+y*12)},{12,12},Pixel(255,255,255,64));
}
}
}
for (int i=0;i<gameBoard.getBlockClumps().size();i++){
BlockClump&c=gameBoard.getBlockClumps()[i];
for (int j=0;j<c.getBlocks().size();j++){
Block&b=c.getBlocks()[j];
DrawPartialDecal(c.getBlockPosition(b)+gameBoard.drawOffset,gameBoard.tileset,{(float)(int)b.col*12,0},{12,12},{1,1},gameBoard.selectedBlock.col!=-1&&gameBoard.selectedBlock.ind==j&&gameBoard.selectedBlock.c==i?GREY:WHITE);
}
}
for (int i=0;i<gameBoard.boardSize.x;i++){
for (int y=0;y<gameBoard.getBlocks(i).size();y++){
Block&b=gameBoard.getBlocks(i)[y];
DrawPartialDecal(b.pos+gameBoard.drawOffset,gameBoard.tileset,{(float)(int)b.col*12,0},{12,12},{1,1},gameBoard.selectedBlock.col!=-1&&gameBoard.selectedBlock.c==-1&&gameBoard.selectedBlock.col==i&&gameBoard.selectedBlock.ind==y?GREY:WHITE);
}
}
}
int main()
{
Meteos instance;
if (instance.Construct(256, 240, 4, 4))
instance.Start();
return 0;
}