Files
breakout/Final_Project.cpp
T
2026-04-13 20:57:37 +03:30

1637 lines
46 KiB
C++

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <fstream>
#include <string>
#include <ctime>
#include <cstdio>
#include <windows.h>
#include <mmsystem.h>
#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 ; i<countUsers-1 ; i++) {
users[i] = users[i+1];
}
countUsers--;
updateUsersInfo();
string fileName = getSaveFileName(users[currentUser].userName);
remove(fileName.c_str());
drawBoard(42, 10);
setCursorPosition(startX + boardLength/2 - 9 , startY + 4);
cout<<"Account deleted!✅";
Sleep(1000);
}
void settingMenu() {
int currentOption = 0;
int previousOption;
drawSettingMenu(currentOption);
while(true) {
char input = getch();
switch (input) {
case 'w': case 'W' :
previousOption = currentOption;
if(currentOption>0) 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"<<settingMenuOptions[i]<<"\033[0m"<<"✅";
else if(i==2 && !soundActive) cout<<"\033[38;5;198m"<<settingMenuOptions[i]<<"\033[0m"<<"❌";
else if(i!=2)cout<<"\033[38;5;198m"<<settingMenuOptions[i]<<"\033[0m";
}
else {
if(i==2 && soundActive) cout<<settingMenuOptions[i]<<"✅";
else if(i==2 && !soundActive) cout<<settingMenuOptions[i]<<"❌";
else if(i!=2) cout<<settingMenuOptions[i];
}
}
}
void updateSettingMenu(int previousOption, int currentOption) {
setCursorPosition(startX + boardLength/2 - settingMenuOptions[previousOption].size()/2, startY + 2 + (previousOption*3));
if(previousOption==2 && soundActive) cout<<settingMenuOptions[previousOption]<<"✅";
else if(previousOption==2 && !soundActive) cout<<settingMenuOptions[previousOption]<<"❌";
else if(previousOption != 2)cout<<settingMenuOptions[previousOption];
setCursorPosition(startX + boardLength/2 - settingMenuOptions[currentOption].size()/2, startY + 2 + (currentOption*3));
if(currentOption==2 && soundActive) cout<<"\033[38;5;198m"<<settingMenuOptions[currentOption]<<"\033[0m"<<"✅";
else if(currentOption==2 && !soundActive) cout<<"\033[38;5;198m"<<settingMenuOptions[currentOption]<<"\033[0m"<<"❌";
else if(currentOption!=2) cout<<"\033[38;5;198m"<<settingMenuOptions[currentOption]<<"\033[0m";
}
void ballShapeMenu() {
int currentOption = 0;
int previousOption;
drawBallShapeMenu(currentOption);
while(true) {
char input = getch();
switch (input) {
case 'w': case 'W' :
previousOption = currentOption;
if(currentOption>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"<<ballShapeOptions[i]<<"\033[38;5;198m>\033[0m"<<"✅";
}
else if(i==currentBall) {
cout<<"\033[38;5;198m<\033[0m"<<ballShapeOptions[i]<<"\033[38;5;198m>\033[0m";
}
else {
cout<<ballShapeOptions[i];
}
}
}
void updateBallShapeMenu(int previousOption, int currentOption) {
// پاک کردن <>از کزینه قبلی منو
setCursorPosition(startX + boardLength/2 - ballShapeOptions[previousOption].size()/2 - 1, startY + 3 + (previousOption*2));
if(previousOption==currentBall) cout<<" "<<ballShapeOptions[previousOption]<<"✅";
else cout<<" "<<ballShapeOptions[previousOption]<<" ";
setCursorPosition(startX + boardLength/2 - ballShapeOptions[currentOption].size()/2 - 1, startY + 3 + (currentOption*2));
if(currentOption==currentBall) cout<<"\033[38;5;198m<\033[0m"<<ballShapeOptions[currentOption]<<"\033[38;5;198m>\033[0m" <<"✅";
else cout<<"\033[38;5;198m<\033[0m"<<ballShapeOptions[currentOption]<<"\033[38;5;198m>\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 ; i<countGame-1 ; i++) {
for(int j=0 ; j<countGame-1-i ; j++) {
if(game[j].score < game[j+1].score) {
swap(game[j], game[j+1]);
}
}
}
ofstream file("gameHistory.txt");
if(!file.is_open()) {
return;
}
for(int i=0 ; i<countGame ; i++) {
file<<game[i].userName<<endl;
file<<game[i].date<<endl;
file<<game[i].remainedHearts<<endl;
file<<game[i].score<<endl;
file<<game[i].result<<endl;
file<<game[i].totalTime<<endl;
}
file.close();
}
void updateUsersInfo() {
ofstream file("users.txt");
if(file.is_open()) {
for(int i=0 ; i<countUsers ; i++) {
file<<users[i].userName<<endl;
file<<users[i].password<<endl;
file<<users[i].highScore<<endl;
}
file.close();
}
}
void gameHistory() {
if(countGame==0) {
drawBoard(42, 10);
setCursorPosition(startX + boardLength/2 - 14, startY + 4);
cout<<"No game has been finished!❌";
Sleep(2000);
return;
}
drawBoard(70, 26);
for(int i=0 ; i<countGame ; i++) {
if(game[i].date=="") continue; //یعنی بازی تمام نشده است
setCursorPosition(startX+2, startY+1+((i%4)*6));
cout<<"Game "<<i+1<<":";
setCursorPosition(startX+2, startY+2+((i%4)*6));
if(game[i].result) {
cout<<game[i].userName<<" won the game!🎉";
}
else {
cout<<game[i].userName<<" lost the game!💔";
}
setCursorPosition(startX+2, startY+3+((i%4)*6));
cout<<"Score : "<<game[i].score;
setCursorPosition(startX+2, startY+5+((i%4)*6));
cout<<"End date and time : "<<game[i].date;
setCursorPosition(startX+2, startY+4+((i%4)*6));
cout<<"Remained hearts : "<<game[i].remainedHearts;
setCursorPosition(startX+1, startY+6+((i%4)*6));
for(int i=0 ; i<boardLength-2 ; i++) {
cout<<"\033[35m═\033[m";
}
if((i%4==3 ) || (i==countGame-1)) { //اگر اخر صفحه یا در حال نمایش اخرین بازی باشیم
setCursorPosition(startX+2, startY+25);
if(i<countGame-1 && i<=3) { // اگر صفحه ی بعد وجود داشت و صفحه قبل وجود نداشت
cout<<"Press \u2192(next page) or Q(menu)";
}
else if(i<countGame-1 && i>3) { //اگر صفحه قبل و بعد وجود داشت
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 && i<countGame-1) { //برای رفتن به صفحه بعد
drawBoard(70, 26);
break;
}
else if(input==75 && i>3) { //برای رفتن به صفحه قبل
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"<<registerMenuOption[i]<<"\033[0m";
}
else {
cout<<registerMenuOption[i];
}
}
}
void updateRegisterMenu(int previousOption, int currentOption) {
setCursorPosition(startX + boardLength/2 - registerMenuOption[previousOption].size()/2, startY + 3 + (previousOption*3));
cout<<registerMenuOption[previousOption];
setCursorPosition(startX + boardLength/2 - registerMenuOption[currentOption].size()/2, startY + 3 + (currentOption*3));
cout<<"\033[38;5;198m"<<registerMenuOption[currentOption]<<"\033[0m";
}
void drawEndGameMenu(int currentOption) {
drawBoard(42, 7);
for(int i=0 ; i<2 ; i++) {
setCursorPosition(startX + boardLength/2 - endGameMenuOptions[i].size()/2, startY + 2 + (i*2));
if(i==currentOption) {
cout<<"\033[38;5;198m"<<endGameMenuOptions[i]<<"\033[0m";
}
else {
cout<<endGameMenuOptions[i];
}
}
}
void endGameMenu() {
int currentOption = 0;
int previousOption;
while(true) {
char input = getch();
switch (input) {
case 'w': case 'W' :
previousOption = currentOption;
if(currentOption>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<<endGameMenuOptions[previousOption];
setCursorPosition(startX + boardLength/2 - endGameMenuOptions[currentOption].size()/2, startY + 2 + (currentOption*2));
cout<<"\033[38;5;198m"<<endGameMenuOptions[currentOption]<<"\033[0m";
}
void creatAccount() {
string tempName;
drawBoard(42, 10);
setCursorPosition(startX + 3, startY + 2);
cout<<"Enter your username : ";
cin>>tempName;
for(int i=0 ; i<countUsers ; i++) {
if(tempName==users[i].userName) {
drawBoard(42, 10);
setCursorPosition(startX + boardLength/2 - 13, startY + 5);
loggedIn = false;
cout<<"Username is alredy taken❌";
Sleep(1500);
return;
}
}
users[countUsers].userName = tempName;
setCursorPosition(startX + 3, startY + 4);
cout<<"Enter your password : ";
cin>>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 ; i<countUsers ; i++) {
if(users[i].userName==username && users[i].password==password) {
currentUser=i;
loggedIn = true;
drawBoard(42, 10);
setCursorPosition(startX + boardLength/2 - 10, startY + boardWidth/2 - 1);
cout<<"Login successful!✅";
setCursorPosition(startX + boardLength/2 - 11, startY + boardWidth/2);
cout<<"Welcome back, "<<username<<"!";
Sleep(2000);
return;
}
}
if(!loggedIn) {
drawBoard(42, 10);
setCursorPosition(startX + boardLength/2 - 10, startY + boardWidth/2 - 1);
cout<<"Account not found!❌";
Sleep(2000);
}
}
void mainMenu() {
int currentOption = 0;
int previousOption;
drawMainMenu(currentOption);
while(true) {
char input = getch();
switch (input) {
case 'w': case 'W' :
previousOption = currentOption;
if(currentOption>0) 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!❌"<<endl;
Sleep(1000);
}
drawMainMenu(currentOption);
break;
case 2: //help
drawHelp();
drawMainMenu(currentOption);
break;
case 3: //game history
gameHistory();
drawMainMenu(currentOption);
break;
case 4: //setting
settingMenu();
drawMainMenu(currentOption);
break;
case 5: //exit
exit(0);
}
}
}
}
void updateMainMenu(int previousOption, int currentOption) {
setCursorPosition(startX + boardLength/2 - mainMenuOption[previousOption].size()/2, startY + 2 + (previousOption*3));
cout<<mainMenuOption[previousOption];
setCursorPosition(startX + boardLength/2 - mainMenuOption[currentOption].size()/2, startY + 2 + (currentOption*3));
cout<<"\033[38;5;198m"<<mainMenuOption[currentOption]<<"\033[0m";
}
void drawBoard(int length, int width) {
boardLength = length;
boardWidth = width;
getTerminalSize();
// محاسبه موقعیت شروع صفحه
startX = terLength/2 - boardLength/2;
startY = terWidth/2 - boardWidth/2;
system("cls");
// رسم گوشه ها
setCursorPosition(startX, startY);
cout<<"\033[35m╔";
setCursorPosition(startX+boardLength-1, startY);
cout<<"╗";
setCursorPosition(startX, startY+boardWidth-1);
cout<<"╚";
setCursorPosition(startX+boardLength-1, startY+boardWidth-1);
cout<<"╝";
// رسم دیوار های بالا و پایین
for(int i=startX+1 ; i<startX+boardLength-1 ; i++) {
setCursorPosition(i, startY);
cout<<"═";
setCursorPosition(i, startY+boardWidth-1);
cout<<"═";
}
// رسم دیوار های چپ و راست
for(int j=startY+1 ; j<startY+boardWidth-1 ; j++) {
setCursorPosition(startX, j);
cout<<"\033[35m║\033[0m";
setCursorPosition(startX+boardLength-1, j);
cout<<"\033[35m║\033[0m";
}
hideCursor();
}
void drawMainMenu(int currentOption) {
drawBoard(42, 20);
for(int i=0 ; i<6 ; i++) {
setCursorPosition(startX + boardLength/2 - mainMenuOption[i].size()/2, startY+2+(i*3));
if(i==currentOption) {
cout<<"\033[38;5;198m"<<mainMenuOption[i]<<"\033[0m";
}
else {
cout<<mainMenuOption[i];
}
}
}
void getTerminalSize(){
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hOut, &csbi);
terLength = csbi.srWindow.Right - csbi.srWindow.Left + 1; // عرض پنجره
terWidth = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; // ارتفاع پنجره
}
void setCursorPosition(int x, int y) {
static const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
cout.flush();
COORD coord = { (SHORT)x, (SHORT)y };
SetConsoleCursorPosition(hOut, coord);
}
void hideCursor() {
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO info;
info.dwSize = 100;
info.bVisible = FALSE;
SetConsoleCursorInfo(consoleHandle, &info);
}
void setupGame() {
paddle.length = (ballWidth==2) ? 10 : 9;
drawBoard(42, 25);
game[countGame].score = 0;
ball.vy = -1;
ball.speedx = 1;
ball.speedy = 1;
activeGame = false;
remainedHearts = 3;
//موقعیت اولیه راکت
paddle.x = startX + boardLength/2 - paddle.length/2;
paddle.y = startY + boardWidth - 3;
//موقعیت اولیه توپ
ball.x = paddle.x + paddle.length / 2 - (ballWidth - 1);
ball.y = paddle.y - 1;
//مکان قبلی توپ و راکت در ابتدا مکان فعلی در نظر گرفته میشود
paddle.oldx=paddle.x;
ball.oldx=ball.x;
ball.oldy=ball.y;
// زنده بودن اجر ها در ابتدای بازی
for(int i=0 ; i<6 ; i++){
for(int j=0 ; j<10 ; j++){
blockAlive[i][j]=true;
}
}
gameStartTime=time(0);
totalPauseSecond=0;
timerStarted=true;
gamePaused=false;
}
void drawGameScreen() {
drawBoard(42, 25);
//رسم موقعیت راکت
setCursorPosition(paddle.x, paddle.y);
for(int i=0 ; i<paddle.length ; i++) {
cout<<"\033[0m▀";
}
//رسم موقعیت توپ
setCursorPosition(ball.x, ball.y);
cout<<"\033[0m"<<ballShapeOptions[currentBall];
// // رسم اجر ها
for(int i=0 ; i<6 ; i++){
setCursorPosition(startX+1, startY+1+i);
for(int j=0 ; j<10 ; j++) {
if(blockAlive[i][j]) cout<<blocks[i][j];
else cout<<" ";
}
}
setCursorPosition(startX + boardLength/2 - 3, startY - 2);
for(int i=0 ; i<remainedHearts ; i++) {
cout<<"❤ ";
}
for(int i=0 ; i<3-remainedHearts ; i++) {
cout<<"💔 ";
}
int length = 25;
int width = 10;
int x = startX + boardLength + 5;
int y = startY + boardWidth/2 - width/2;
// رسم جدول اطلاعات در کنار جدول بازی
// رسم گوشه ها
setCursorPosition(x, y);
cout<<"\033[35m╔";
setCursorPosition(x + length -1, y);
cout<<"╗";
setCursorPosition(x, y + width - 1);
cout<<"╚";
setCursorPosition(x + length - 1, y + width-1);
cout<<"╝";
// رسم دیوار های بالا و پایین
for(int i = x + 1 ; i < x + length - 1 ; i++) {
setCursorPosition(i, y);
cout<<"═";
setCursorPosition(i, y + width - 1);
cout<<"═";
}
// رسم دیوار های چپ و راست
for(int j = y + 1 ; j < y + width - 1 ; j++) {
setCursorPosition(x, j);
cout<<"\033[35m║\033[0m";
setCursorPosition(x + length - 1, j);
cout<<"\033[35m║\033[0m";
}
setCursorPosition(x + 2, y + 1);
cout<<"High score : "<<users[currentUser].highScore;
setCursorPosition(x + 2, y + 3);
cout<<"Score : "<<game[countGame].score;
setCursorPosition(x + 2, y + 5);
cout<<"remained blocks : "<<remainedBlocks();
hideCursor();
}
void handleInput() {
if(kbhit()) {
char move = getch();
switch (move) {
case 'a': case 'A' :
paddle.oldx = paddle.x;
if(paddle.x - 3 >= 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"<<ballShapeOptions[currentBall];
}
if(paddle.x != paddle.oldx) {
if(paddle.x>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 ; i<paddle.length ; i++) {
cout<<"\033[0m▀";
}
}
//پاک کردن جان های قبلی
setCursorPosition(startX + boardLength/2 -2, startY - 2);
cout<<" ";
//رسم دوباره جان ها
setCursorPosition(startX + boardLength/2 - 3, startY - 2);
for(int i=0 ; i<remainedHearts ; i++) {
cout<<"❤ ";
}
for(int i=0 ; i<3-remainedHearts ; i++) {
cout<<"💔 ";
}
int length = 25;
int width = 10;
int x = startX + boardLength + 5;
int y = startY + boardWidth/2 - width/2;
setCursorPosition(x + 2, y + 1);
cout<<"High score : "<<users[currentUser].highScore;
setCursorPosition(x + 2, y + 3);
cout<<"Score : "<<game[countGame].score;
setCursorPosition(x + 2, y + 5);
cout<<"remained blocks : "<<remainedBlocks();
setCursorPosition(startX + 6, startY + boardWidth);
cout<<users[currentUser].userName;
setCursorPosition(startX + 25, startY + boardWidth);
showGameTime();
hideCursor();
}
void showGameResult(bool result) {
time_t endtime=time(0);
int totalTime= difftime(endtime,gameStartTime) - totalPauseSecond;
string endTime = ctime(&endtime);
endTime.erase(endTime.size()-1); // پاک کردن \n اخر تابع
drawEndGameMenu(0);
setCursorPosition(startX + boardLength/2 - 5, startY - 4);
if(result) {
if(soundActive) PlaySound(TEXT("sounds\\victory.wav"), NULL, SND_FILENAME | SND_ASYNC);
cout<<" Victory🎉";
}
else {
if(soundActive) PlaySound(TEXT("sounds\\gameOver.wav"), NULL, SND_FILENAME | SND_ASYNC);
cout<<"Game over!";
}
setCursorPosition(startX + boardLength/2 - 4, startY - 6);
for(int i=0 ; i<remainedHearts ; i++) {
cout<<"❤ ";
}
for(int i=0 ; i<3 - remainedHearts ; i++) {
cout<<"💔 ";
}
setCursorPosition(startX + 2, startY - 1);
cout<<"Score : "<<game[countGame].score;
setCursorPosition(startX + 29,startY-1);
showGameTime();
endGameMenu();
game[countGame].userName = users[currentUser].userName;
game[countGame].date = endTime;
game[countGame].remainedHearts = remainedHearts;
game[countGame].result = result;
game[countGame].totalTime = totalTime;
countGame++;
sortAndSaveGames();
loadedGame = false;
//پاک کردن بازی سیو شده
ofstream file(getSaveFileName(users[currentUser].userName));
file.close();
}
void pauseMenu() {
if(!gamePaused && timerStarted){
pauseStartTime=time(0);
gamePaused=true;
}
int currentOption = 0;
int previousOption;
drawPauseMenu(currentOption);
while(true) {
char input = getch();
switch (input) {
case 'w': case 'W' :
previousOption = currentOption;
if(currentOption>0) 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"<<pauseMenuOption[i]<<"\033[0m";
}
else {
cout<<pauseMenuOption[i];
}
}
}
void updatePauseMenu(int previousOption, int currentOption) {
setCursorPosition(startX + boardLength/2 - pauseMenuOption[previousOption].size()/2, startY + 3 + (previousOption*4));
cout<<pauseMenuOption[previousOption];
setCursorPosition(startX + boardLength/2 - pauseMenuOption[currentOption].size()/2, startY + 3 + (currentOption*4));
cout<<"\033[38;5;198m"<<pauseMenuOption[currentOption]<<"\033[0m";
}
string getSaveFileName(const string& username){
return "save_" + username + ".txt";
}
bool saveGame(){
ofstream file(getSaveFileName(users[currentUser].userName));
if(! file.is_open()){
return false;
}
file<<users[currentUser].userName<<endl;
int total=0;
if(timerStarted){
total= int(difftime(time(0),gameStartTime)-totalPauseSecond);
if(total<0) total=0;
}
file<<total<<endl;
file<<game[countGame].score<<endl;//امتیاز
file<<remainedHearts<<endl; //جان های باقیمانده
file<<activeGame<<endl; // ایا توپ در حال حرکته
file<<paddle.x<<" "<<paddle.y<<" "<<paddle.oldx<<" "<<paddle.length<<endl; // موقعیت راکت
file<<ball.x<<" "<<ball.y<<" "<<ball.oldx<<" "<<ball.oldy<<" "<<ball.vx<<" "<<ball.vy<<" "<<ball.speedx<<" "<<ball.speedy<<endl; //موقعیت توپ
// وضعبت اجر ها
for(int i=0 ; i<6 ; i++){
for(int j=0 ; j<10 ; j++){
file<<blockAlive[i][j]<<" ";
}
}
file.close();
return true;
}
bool loadGame(){
string savePath = getSaveFileName(users[currentUser].userName);
ifstream file(savePath);
if(!file.is_open()){
return false;
}
string saveUser;
file>> 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<<min<<":";
if(sec<10) cout<<"0";
cout<<sec;
}