#include #include #include #include #include #include #include #include #include #pragma comment(lib, "winmm.lib") using namespace std; struct paddleInfo { int x, y; int oldx; int length; }; struct ballInfo { int x, y; int oldx, oldy; int vx , vy; int speedx, speedy; }; struct userInfo { string userName; string password; int highScore; }; struct gameInfo { int score; string userName; string date = ""; int totalTime; int remainedHearts; bool result; }; paddleInfo paddle; ballInfo ball; gameInfo game[1000]; userInfo users[1000]; string mainMenuOption[6] = {"New Game", "Load Game", "Help", "Game History", "Setting", "Exit"}; string pauseMenuOption[4] = {"Continue", "Restart", "Save the game", "Quit"}; string registerMenuOption[2] = {"Login to your account", "Creat account"}; string endGameMenuOptions[2] = {"Play again", "Quit"}; string settingMenuOptions[6] = {"Ball shape", "Clear game history", "Active sound", "Log out", "Delete aacount", "Quit"}; string ballShapeOptions[8] = {"●","🟣","🔵","🟠","🌏","🥎","🏀","Quit"}; int currentUser; int currentBall = 0; int countGame=0; int countUsers=0; bool activeGame = false; int boardWidth, boardLength; int terLength, terWidth; int startX, startY; int remainedHearts = 3; bool blockAlive[6][10]; int ballWidth = (ballShapeOptions[currentBall]=="●") ? 1 : 2; bool gamePaused = false; bool endGame = false; bool quitGame = false; bool loadedGame=false; bool loggedIn = false; bool soundActive = true; time_t gameStartTime; //زمان شروع بازی time_t pauseStartTime; // pause زمان شزوع time_t gameEndTime; int totalPauseSecond=0; bool timerStarted=false; string blocks[6][10] = { {"\033[95m████","\033[35m████","\033[94m████","\033[96m████","\033[95m████","\033[35m████","\033[94m████","\033[95m████","\033[35m████","\033[94m████\033[0m"}, {"\033[96m████","\033[95m████","\033[35m████","\033[94m████","\033[96m████","\033[95m████","\033[96m████","\033[35m████","\033[94m████","\033[35m████\033[0m"}, {"\033[35m████","\033[94m████","\033[96m████","\033[95m████","\033[35m████","\033[94m████","\033[35m████","\033[95m████","\033[35m████","\033[94m████\033[0m"}, {"\033[94m████","\033[96m████","\033[95m████","\033[35m████","\033[94m████","\033[96m████","\033[95m████","\033[94m████","\033[95m████","\033[96m████\033[0m"}, {"\033[95m████","\033[35m████","\033[94m████","\033[96m████","\033[95m████","\033[35m████","\033[94m████","\033[95m████","\033[35m████","\033[94m████\033[0m"}, {"\033[96m████","\033[95m████","\033[35m████","\033[94m████","\033[96m████","\033[95m████","\033[96m████","\033[35m████","\033[94m████","\033[35m████\033[0m"}}; void setCursorPosition(int x, int y); void hideCursor(); void loadGameHistory(); void sortAndSaveGames(); void gameHistory(); void clearGameHistory(); void loadUsers(); void updateUsersInfo(); void login(); void creatAccount(); void deleteAccount(); void mainMenu(); void drawMainMenu(int currentOption); void updateMainMenu(int previousOption, int currentOption); void pauseMenu(); void drawPauseMenu(int currentOption); void updatePauseMenu(int previousOption, int currentOption); void registerMenu(); void drawRegisterMenu(int currentOption); void updateRegisterMenu(int previousOption, int currentOption); void settingMenu(); void drawSettingMenu(int currentOption); void updateSettingMenu(int previousOption, int currentOption); void ballShapeMenu(); void drawBallShapeMenu(int currentOption); void updateBallShapeMenu(int previousOption, int currentOption); void endGameMenu(); void drawEndGameMenu (int currentOption); void updateEndGameMenu(int previousOption, int currentOption); void setupGame(); void handleInput(); void gameLoop(); void drawGameScreen(); void updateGameScreen(); void updateBallLocation(); void blockDistruction(int &nextX,int &nextY); int remainedBlocks(); void showGameResult(bool result); string getSaveFileName(const string& username); bool saveGame(); bool loadGame(); void drawHelp(); void drawBoard(int length, int width); void getTerminalSize(); void showGameTime(); int main() { SetConsoleOutputCP(CP_UTF8); loadGameHistory(); loadUsers(); mainMenu(); } void clearGameHistory() { countGame=0; //پاک کردن تاریخچه بازی ofstream file("gameHistory.txt"); file.close(); } void deleteAccount() { drawBoard(58, 10); setCursorPosition(startX + 2 , startY + 4); cout<<"Are you sure you want to delete your account? (y/n) "; char input; while(true) { input = getch(); if(input=='y' || input=='Y') break; else if(input=='n' || input=='N') return; } for(int i=currentUser ; i0) currentOption--; updateSettingMenu(previousOption, currentOption); break; case 's' : case 'S' : previousOption = currentOption; if(currentOption<5) currentOption++; updateSettingMenu(previousOption, currentOption); break; case 13 : switch (currentOption) { case 0: //shop ballShapeMenu(); drawSettingMenu(currentOption); break; case 1: //clear game history clearGameHistory(); drawBoard(42, 10); setCursorPosition(startX + boardLength/2 - 11 , startY + 4); cout<<"Game history cleared!✅"; Sleep(1000); drawSettingMenu(currentOption); break; case 2: //sound soundActive = !soundActive; drawSettingMenu(currentOption); break; case 3: //log out loggedIn=false; drawBoard(42, 10); setCursorPosition(startX + boardLength/2 - 11 , startY + 4); cout<<"You're logged out!✅"; Sleep(1000); drawSettingMenu(currentOption); break; case 4: //delete account if(!loggedIn) login(); if(loggedIn) deleteAccount(); drawSettingMenu(currentOption); break; case 5: //quit return; } } } } void drawSettingMenu(int currentOption) { drawBoard(42, 20); for(int i=0 ; i<6 ; i++) { setCursorPosition(startX + boardLength/2 - settingMenuOptions[i].size()/2, startY + 2 + (i*3)); if(i==currentOption) { if(i==2 && soundActive) cout<<"\033[38;5;198m"<0) currentOption--; updateBallShapeMenu(previousOption, currentOption); break; case 's' : case 'S' : previousOption = currentOption; if(currentOption<7) currentOption++; updateBallShapeMenu(previousOption, currentOption); break; case 13 : switch (currentOption) { case 0: currentBall=0; drawBallShapeMenu(currentOption); break; case 1: currentBall=1; ballWidth = 2; drawBallShapeMenu(currentOption); break; case 2: currentBall=2; ballWidth = 2; drawBallShapeMenu(currentOption); break; case 3: currentBall=3; ballWidth = 2; drawBallShapeMenu(currentOption); break; case 4: currentBall=4; ballWidth = 2; drawBallShapeMenu(currentOption); break; case 5: currentBall=5; ballWidth = 2; drawBallShapeMenu(currentOption); break; case 6: currentBall=6; ballWidth = 2; drawBallShapeMenu(currentOption); break; case 7: //quit return; } } } } void drawBallShapeMenu(int currentOption) { drawBoard(42, 20); for(int i=0 ; i<8 ; i++) { setCursorPosition(startX + boardLength/2 - ballShapeOptions[i].size()/2, startY+3+(i*2)); if(i==currentOption && i==currentBall) { //توپ انتخاب شده و توپی که کرسر روی ان قرار دارد setCursorPosition(startX + boardLength/2 - ballShapeOptions[i].size()/2 - 1, startY+3+(i*2)); cout<<"\033[38;5;198m<\033[0m"<\033[0m"<<"✅"; } else if(i==currentBall) { cout<<"\033[38;5;198m<\033[0m"<\033[0m"; } else { cout<از کزینه قبلی منو setCursorPosition(startX + boardLength/2 - ballShapeOptions[previousOption].size()/2 - 1, startY + 3 + (previousOption*2)); if(previousOption==currentBall) cout<<" "<\033[0m" <<"✅"; else cout<<"\033[38;5;198m<\033[0m"<\033[0m"; } void loadGameHistory() { ifstream file("gameHistory.txt"); if(!file.is_open()) { return; } string line; gameInfo temp; while(getline(file, line) ) { temp.userName = line; getline(file, line); temp.date = line; getline(file, line); temp.remainedHearts = stoi(line); getline(file, line); temp.score = stoi(line); getline(file, line); temp.result = stoi(line); getline(file, line); temp.totalTime = stoi(line); game[countGame] = temp; countGame++; } file.close(); } void sortAndSaveGames() { for(int i=0 ; i3) { //اگر صفحه قبل و بعد وجود داشت cout<<"Press \u2192(next page) or \u2190(last page) or Q(menu)"; } else if(i==countGame-1 && i>3) { //صفحه قبل وجود داشته باشد اما بعد وجود نداشته باشد cout<<"Press \u2190(last page) or Q(menu)"; } else cout<<"Press Q to go to menu"; //فقط یک صفحه داریم while(true) { char input = getch(); if(input=='Q' || input=='q') return; else if (input==77 && i3) { //برای رفتن به صفحه قبل i=i-5-(i%4); drawBoard(70, 26); break; } } } } } void loadUsers() { ifstream file("users.txt"); if(!file.is_open()) { return; } string line; userInfo temp; while(getline(file, line) ) { temp.userName = line; getline(file, line); temp.password = line; getline(file, line); temp.highScore = stoi(line); users[countUsers] = temp; countUsers++; } file.close(); } void registerMenu() { int currentOption = 0; int previousOption; drawRegisterMenu(currentOption); while(true) { char input = getch(); switch (input) { case 'w': case 'W' : previousOption = currentOption; if(currentOption>0) currentOption--; updateRegisterMenu(previousOption, currentOption); break; case 's' : case 'S' : previousOption = currentOption; if(currentOption<1) currentOption++; updateRegisterMenu(previousOption, currentOption); break; case 13 : switch (currentOption) { case 0: //login login(); return; case 1: //create acoount creatAccount(); return; } } } } void drawRegisterMenu(int currentOption) { drawBoard(42, 10); for(int i=0 ; i<2 ; i++) { setCursorPosition(startX + boardLength/2 - registerMenuOption[i].size()/2, startY + 3 + (i*3)); if(i==currentOption) { cout<<"\033[38;5;198m"<0) currentOption--; updateEndGameMenu(previousOption, currentOption); break; case 's' : case 'S' : previousOption = currentOption; if(currentOption<1) currentOption++; updateEndGameMenu(previousOption, currentOption); break; case 13 : switch (currentOption) { case 0: //play again setupGame(); gameLoop(); return; case 1: //quit return; } } } } void updateEndGameMenu(int previousOption, int currentOption) { setCursorPosition(startX + boardLength/2 - endGameMenuOptions[previousOption].size()/2, startY + 2 + (previousOption*2)); cout<>tempName; for(int i=0 ; i>users[countUsers].password; users[countUsers].highScore = 0; //رکورد اولیه setCursorPosition(startX + boardLength/2 - 10, startY + 5); cout<<"Account created!✅"; Sleep(1500); currentUser = countUsers; loggedIn = true; countUsers++; updateUsersInfo(); } void login() { string username, password; drawBoard(42, 10); setCursorPosition(startX + 3, startY + 3); cout<<"Enter your username : "; cin>>username; setCursorPosition(startX + 3, startY + 5); cout<<"Enter your password : "; cin>>password; loggedIn = false; for(int i=0 ; i0) currentOption--; updateMainMenu(previousOption, currentOption); break; case 's' : case 'S' : previousOption = currentOption; if(currentOption<5) currentOption++; updateMainMenu(previousOption, currentOption); break; case 13 : switch (currentOption) { case 0: //new game quitGame=false; if(!loggedIn) registerMenu(); if(loggedIn) { gameLoop(); } drawMainMenu(currentOption); break; case 1: //load game quitGame=false; if(!loggedIn) login(); if(loggedIn && loadGame()) { gameLoop(); } else if (loggedIn && !loadGame()){ drawBoard(42, 10); setCursorPosition(startX + boardLength/2 - 8 , startY + 4); cout<<"NO SAVED GAME!❌"<= startX + 1) { paddle.x -= 3; } else paddle.x = startX + 1; if(!activeGame) { ball.oldx = ball.x; ball.oldy = ball.y; ball.x = paddle.x + paddle.length/2 - (ballWidth - 1); } break; case 'd' : case 'D' : paddle.oldx = paddle.x; if(paddle.x + paddle.length + 3 <= startX + boardLength - 1) { paddle.x += 3; } else paddle.x = (startX + boardLength - 1) - paddle.length; if(!activeGame) { ball.oldx = ball.x; ball.oldy = ball.y; ball.x = paddle.x + paddle.length/2 - (ballWidth - 1); } break; case ' ' : // برای شروع بازی space if(!activeGame) { activeGame = true; ball.vy = -1; // تعیین جهت اولیه توپ با توجه به موقعیت راکت در شروع بازی if(ball.x >= startX + boardLength/2) ball.vx = 1; else if(ball.x < startX + boardLength/2) ball.vx = -1; } break; case 'p' : case 'P' : // برنامه pause برای pauseMenu(); return; } } } void blockDistruction(int &nextX , int &nextY) { int ballLeft = nextX; int ballRight = nextX + ballWidth - 1; for(int i=0 ; i<6 ; i++) { for(int j=0 ; j<10 ; j++) { if(!blockAlive[i][j]) continue; // مختصات شروع اجرها int blockY = startY + 1 + (i); int blockX = startX + 1 + (j*4); int left = blockX; // سمت چپ بلوک int right = blockX + 3 - (ballWidth - 1); //سمت راست بلوک bool hitInside = (ballRight >= left && ballLeft<= right && nextY == blockY); if (!hitInside) continue; bool fromTop = ball.vy > 0; //حرکت از بالا به پایین bool fromBottom = ball.vy < 0; // حرکت از پایین به بالا bool fromLeft = ball.vx > 0; // حرکت از چپ به راست bool fromRight = ball.vx < 0; //حرکت از راست به چپ bool topBlock = (i>0 && blockAlive[i-1][j]); //سالم بودن اجر بالا bool bottomBlock = (i<5 && blockAlive[i+1][j]); //سالم بودن اجر پایین bool leftBlock = (j>0 && blockAlive[i][j-1]); //سالم بودن اجر چپ bool rightBlock = (j<9 && blockAlive[i][j+1]); // سالم بودن اجر راست // حرکت های مورب و برخورد با گوشه if (fromTop && fromRight && topBlock && rightBlock) { ball.vx *= -1; ball.vy *= -1; } else if (fromTop && fromLeft && topBlock && leftBlock) { ball.vx *= -1; ball.vy *= -1; } else if (fromBottom && fromRight && bottomBlock && rightBlock) { ball.vx *= -1; ball.vy *= -1; } else if (fromBottom && fromLeft && bottomBlock && leftBlock) { ball.vx *= -1; ball.vy *= -1; } else { bool cameFromSide = (ball.x + 1 < left && ballRight >= left) || (ball.x > right && ballLeft <= right); if(cameFromSide) ball.vx *= -1; //برخورد از چپ یا راست else ball.vy *= -1; //برخورد از بالا یا پایین } setCursorPosition(blockX,blockY); cout<<" "; blockAlive[i][j] = false; if(soundActive) PlaySound(TEXT("sounds\\breakingBlock.wav"), NULL, SND_FILENAME | SND_ASYNC); game[countGame].score += 10; if(game[countGame].score > users[currentUser].highScore) { users[currentUser].highScore = game[countGame].score; updateUsersInfo(); } return; } } } void updateBallLocation() { int ballRight = ball.x; int ballLeft = ball.x + ballWidth - 1; //موقعیت بعدی توپ int nextX = ball.x + (ball.vx * ball.speedx); int nextY = ball.y + (ball.vy * ball.speedy); //برخورد توپ با دیوار سمت چپ if (nextX <= startX + 1) { ball.vx *= -1; nextX = startX + 1; } //برخورد توپ با دیوار سمت راست else if (nextX>= startX + boardLength - 2 - (ballWidth - 1)) { ball.vx *= -1; nextX = startX + boardLength - 2 - (ballWidth-1); } //برخورد توپ با سقف if (nextY <= startY + 1) { ball.vy *= -1; nextY = startY + 1; } blockDistruction(nextX,nextY); //افتادن توپ if (nextY == paddle.y + 2) { if(soundActive) PlaySound(TEXT("sounds\\Fall.wav"), NULL, SND_FILENAME | SND_ASYNC); activeGame = false; remainedHearts--; nextX = paddle.x + paddle.length/2; nextY = paddle.y - 1; ball.speedx = 1; } ball.oldx = ball.x; ball.oldy = ball.y; ball.x = nextX; ball.y = nextY; //برخورد توپ با راکت if(ball.y==paddle.y-1 && ballLeft >= paddle.x && ballRight <= paddle.x + paddle.length && activeGame) { ball.vy = -1; int hit = (ball.x + ballWidth - 1) - paddle.x; if (hit <= 2) ball.vx = -2; else if (hit <= 3) ball.vx = -1; else if (hit >= 6) ball.vx = 2; else if (hit >= 5) ball.vx = 1; else ball.vx = 0; //hit=4 } } int remainedBlocks() { int count = 0; for(int i=0 ; i<6 ; i++){ for(int j=0 ; j<10 ; j++){ if(blockAlive[i][j]) count++; } } return count; } void gameLoop() { drawBoard(42, 25); if(!loadedGame) setupGame(); loadedGame=false; drawGameScreen(); int frameCounter=0; while(true) { handleInput(); if(gamePaused) { drawBoard(42, 25); drawGameScreen(); gamePaused=false; } if(quitGame) return; if(activeGame && frameCounter%6==0) { updateBallLocation(); } if(remainedBlocks()==0) { showGameResult(true); return; } if(remainedHearts==0) { showGameResult(false); return; } frameCounter++; updateGameScreen(); Sleep(10); } } void updateGameScreen() { if(ball.x != ball.oldx || activeGame) { //پاک کردن جای قبلی توپ setCursorPosition(ball.oldx, ball.oldy); cout<<" "; //رسم دوباره توپ setCursorPosition(ball.x, ball.y); cout<<"\033[0m"<paddle.oldx) {//راکت یه سمت راست حرکت کرده است for(int i = paddle.oldx ; i < paddle.x ; i++) { setCursorPosition(i, paddle.y); cout<<" "; } } else {//راکت یه سمت چپ حرکت کرده است for(int i = paddle.x + paddle.length; i < paddle.oldx + paddle.length; i++) { setCursorPosition(i, paddle.y); cout<<" "; } } //رسم دوباره راکت setCursorPosition(paddle.x, paddle.y); for(int i=0 ; i0) currentOption--; updatePauseMenu(previousOption, currentOption); break; case 's' : case 'S' : previousOption = currentOption; if(currentOption<3) currentOption++; updatePauseMenu(previousOption, currentOption); break; case 13 : switch (currentOption) { case 0: //continue totalPauseSecond+=difftime(time(0),pauseStartTime); return; case 1: //restart setupGame(); drawGameScreen(); return; case 2: //save drawBoard(42, 10); if(saveGame()){ setCursorPosition(startX + boardLength/2 -4 , startY + 4); cout<<"SAVED✅"; Sleep(1000); } else{ setCursorPosition(startX + boardLength/2 - 9, startY + 5); cout<<"SAVE FAILED❌"; Sleep(1000); } drawPauseMenu(currentOption); break; case 3: //quit quitGame = true; return; } } } } void drawPauseMenu(int currentOption) { drawBoard(42, 20); for(int i=0 ; i<4 ; i++) { setCursorPosition(startX + boardLength/2 - pauseMenuOption[i].size()/2, startY + 3 + (i*4)); if(i==currentOption) { cout<<"\033[38;5;198m"<> saveUser; if(saveUser != users[currentUser].userName){ file.close(); return false; } int total; file>>total; file>>game[countGame].score; file>>remainedHearts; file>>activeGame; file>>paddle.x>>paddle.y>>paddle.oldx>>paddle.length; file>>ball.x>>ball.y>>ball.oldx>>ball.oldy>>ball.vx>>ball.vy>>ball.speedx>>ball.speedy; for(int i=0 ; i<6 ; i++){ for(int j=0;j<10;j++){ file>>blockAlive[i][j]; } } file.close(); gameStartTime=time(0)-total; totalPauseSecond=0; timerStarted=true; loadedGame=true; return true; } void drawHelp(){ drawBoard(70, 26); int x = startX + 2; int y = startY + 1; setCursorPosition(x, y); cout << "HOW TO PLAY BREAKOUT"; y++; setCursorPosition(x, y++); cout << "You control a paddle at the bottom of the screen."; setCursorPosition(x, y++); cout << "A ball bounces around and breaks the blocks above."; y++; setCursorPosition(x, y++); cout << "GOAL:"; setCursorPosition(x, y++); cout << "- Destroy all blocks without losing the ball."; y++; setCursorPosition(x, y++); cout << "CONTROLS:"; setCursorPosition(x, y++); cout << "A : Move paddle left"; setCursorPosition(x, y++); cout << "D : Move paddle right"; setCursorPosition(x, y++); cout << "SPACE : Start the ball"; setCursorPosition(x, y++); cout << "P : Pause the game"; y++; setCursorPosition(x, y++); cout << "RULES:"; setCursorPosition(x, y++); cout << "- If the ball falls, you lose one heart."; setCursorPosition(x, y++); cout << "- You start with 3 hearts."; y++; setCursorPosition(x, y++); cout << "WIN / LOSE:"; setCursorPosition(x, y++); cout << "- Break all blocks to win."; setCursorPosition(x, y++); cout << "- Lose all hearts to lose."; y += 2; setCursorPosition(x, y++); cout << "Press any key to return to menu..."; getch(); } void showGameTime(){ if(!timerStarted) return; time_t now=time(0); int playedSeconds; if(gamePaused) playedSeconds=difftime(pauseStartTime,gameStartTime)-totalPauseSecond; else playedSeconds=difftime(now,gameStartTime)-totalPauseSecond; if(playedSeconds<0) playedSeconds=0; int min= playedSeconds / 60; int sec= playedSeconds % 60; cout<<"Time: "; if(min<10) cout<<"0"; cout<