Initial commit on develop branch
This commit is contained in:
+436
@@ -0,0 +1,436 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream> // برای کار با فایل
|
||||||
|
#include <conio.h> // برای دریافت ورودی کیبورد
|
||||||
|
#include <chrono> // برای مدیریت زمان
|
||||||
|
#include <cstdlib> // توابع استاندارد
|
||||||
|
#include <ctime> // برای دریافت تاریخ و زمان
|
||||||
|
#include <string> // برای مدیریت رشتهها
|
||||||
|
#include <windows.h>// برای کنترل مکاننما و حذف پرش تصویر
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// تنظیمات کلی بازی
|
||||||
|
const int WIDTH = 40; // عرض صفحه بازی
|
||||||
|
const int HEIGHT = 20; // ارتفاع صفحه بازی
|
||||||
|
|
||||||
|
// توابع کمکی برای گرافیک (جلوگیری از پرش تصویر)
|
||||||
|
|
||||||
|
// انتقال مکاننما به مختصات (x, y) بدون پاک کردن کل صفحه
|
||||||
|
void gotoxy(int x, int y)
|
||||||
|
{
|
||||||
|
COORD coord;
|
||||||
|
coord.X = x;
|
||||||
|
coord.Y = y;
|
||||||
|
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
// مخفی کردن نشانگر چشمکزن موس برای زیبایی
|
||||||
|
void HideCursor()
|
||||||
|
{
|
||||||
|
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
CONSOLE_CURSOR_INFO info;
|
||||||
|
info.dwSize = 100;
|
||||||
|
info.bVisible = FALSE;
|
||||||
|
SetConsoleCursorInfo(consoleHandle, &info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد وقفه زمانی دقیق
|
||||||
|
void waitFor(int milliseconds)
|
||||||
|
{
|
||||||
|
auto start = chrono::high_resolution_clock::now();
|
||||||
|
while (chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start).count() < milliseconds)
|
||||||
|
{
|
||||||
|
// حلقه انتظار (Busy wait)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// کلاس توپ (Ball)
|
||||||
|
class Ball
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x, y; // مختصات
|
||||||
|
float dx, dy; // جهت حرکت
|
||||||
|
bool moving; // وضعیت حرکت
|
||||||
|
|
||||||
|
Ball(float startX, float startY) : x(startX), y(startY), dx(0.5f), dy(-1.0f), moving(false) {}
|
||||||
|
|
||||||
|
// حرکت توپ بر اساس سرعت فعلی
|
||||||
|
void move()
|
||||||
|
{
|
||||||
|
if (moving)
|
||||||
|
{
|
||||||
|
x += dx;
|
||||||
|
y += dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// بازنشانی توپ به مکان اولیه (بعد از باختن جان)
|
||||||
|
void reset(float startX, float startY)
|
||||||
|
{
|
||||||
|
x = startX;
|
||||||
|
y = startY;
|
||||||
|
// جهت پرتاب تصادفی چپ یا راست
|
||||||
|
dx = (rand() % 2 == 0 ? 0.5f : -0.5f);
|
||||||
|
dy = -1.0f;
|
||||||
|
moving = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// کلاس راکت (Paddle)
|
||||||
|
class Paddle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float x;
|
||||||
|
int y;
|
||||||
|
int width;
|
||||||
|
|
||||||
|
Paddle(int startX, int startY) : x(startX), y(startY), width(7) {}
|
||||||
|
|
||||||
|
// حرکت به چپ با بررسی مرزها
|
||||||
|
void moveLeft()
|
||||||
|
{
|
||||||
|
x -= 2;
|
||||||
|
if (x < 1) x = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// حرکت به راست با بررسی مرزها
|
||||||
|
void moveRight()
|
||||||
|
{
|
||||||
|
x += 2;
|
||||||
|
if (x + width > WIDTH - 1) x = WIDTH - 1 - width;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// کلاس آجر (Brick)
|
||||||
|
class Brick
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int x, y;
|
||||||
|
bool active; // آیا آجر هنوز وجود دارد؟
|
||||||
|
int points; // امتیاز آجر
|
||||||
|
|
||||||
|
Brick(int bx, int by) : x(bx), y(by), active(true), points(10) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// کلاس اصلی بازی (Game Engine)
|
||||||
|
class Game
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool gameOver;
|
||||||
|
bool victory;
|
||||||
|
int score;
|
||||||
|
int lives;
|
||||||
|
string playerName;
|
||||||
|
|
||||||
|
Ball* ball;
|
||||||
|
Paddle* paddle;
|
||||||
|
vector<Brick> bricks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Game(string name)
|
||||||
|
{
|
||||||
|
playerName = name;
|
||||||
|
gameOver = false;
|
||||||
|
victory = false;
|
||||||
|
score = 0;
|
||||||
|
lives = 3;
|
||||||
|
|
||||||
|
// ایجاد اشیاء بازی
|
||||||
|
paddle = new Paddle(WIDTH / 2 - 3, HEIGHT - 2);
|
||||||
|
ball = new Ball(WIDTH / 2, HEIGHT - 3);
|
||||||
|
|
||||||
|
// چیدمان آجرها
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (int j = 2; j < WIDTH - 2; j += 4)
|
||||||
|
{
|
||||||
|
bricks.push_back(Brick(j, i + 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Game()
|
||||||
|
{
|
||||||
|
delete ball;
|
||||||
|
delete paddle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// رسم محیط بازی (بدون پرش تصویر)
|
||||||
|
void draw()
|
||||||
|
{
|
||||||
|
gotoxy(0, 0); // پرش به ابتدای صفحه به جای پاک کردن کل آن
|
||||||
|
|
||||||
|
string buffer = ""; // بافر برای ذخیره کل تصویر و چاپ یکجا
|
||||||
|
|
||||||
|
// هدر بازی
|
||||||
|
buffer += "PLAYER: " + playerName + " | SCORE: " + to_string(score) + " | LIVES: " + to_string(lives) + "\n";
|
||||||
|
for (int i = 0; i < WIDTH + 2; i++) buffer += "#";
|
||||||
|
buffer += "\n";
|
||||||
|
|
||||||
|
// رسم محتوا
|
||||||
|
for (int i = 0; i < HEIGHT; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < WIDTH; j++)
|
||||||
|
{
|
||||||
|
if (j == 0) buffer += "#"; // دیوار چپ
|
||||||
|
|
||||||
|
bool drawn = false;
|
||||||
|
// رسم توپ
|
||||||
|
if ((int)ball->x == j && (int)ball->y == i)
|
||||||
|
{
|
||||||
|
buffer += "O";
|
||||||
|
drawn = true;
|
||||||
|
}
|
||||||
|
// رسم راکت
|
||||||
|
else if (i == paddle->y && j >= (int)paddle->x && j < (int)paddle->x + paddle->width)
|
||||||
|
{
|
||||||
|
buffer += "=";
|
||||||
|
drawn = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// رسم آجرها
|
||||||
|
for (auto& b : bricks) {
|
||||||
|
if (b.active && b.x == j && b.y == i)
|
||||||
|
{
|
||||||
|
buffer += "[]";
|
||||||
|
drawn = true;
|
||||||
|
j++; // پرش از روی کاراکتر دوم آجر
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!drawn) buffer += " "; // فضای خالی
|
||||||
|
if (j == WIDTH - 1) buffer += "#"; // دیوار راست
|
||||||
|
}
|
||||||
|
buffer += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < WIDTH + 2; i++) buffer += "#";
|
||||||
|
buffer += "\n";
|
||||||
|
|
||||||
|
// راهنما پایین صفحه
|
||||||
|
if(!ball->moving)
|
||||||
|
buffer += "\nPress 'SPACE' to start. 'a'/'d' to Move. 'q' Quit ";
|
||||||
|
else
|
||||||
|
buffer += "\n ";
|
||||||
|
|
||||||
|
cout << buffer; // چاپ نهایی بافر
|
||||||
|
}
|
||||||
|
|
||||||
|
// دریافت ورودی از کاربر
|
||||||
|
void input()
|
||||||
|
{
|
||||||
|
if (_kbhit())
|
||||||
|
{
|
||||||
|
char current = _getch();
|
||||||
|
if (current == 'a' || current == 'A') paddle->moveLeft();
|
||||||
|
if (current == 'd' || current == 'D') paddle->moveRight();
|
||||||
|
if (current == 'q' || current == 'Q') gameOver = true;
|
||||||
|
if (current == ' ') ball->moving = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// منطق بازی (فیزیک و برخوردها)
|
||||||
|
void logic()
|
||||||
|
{
|
||||||
|
if (!ball->moving)
|
||||||
|
{
|
||||||
|
// چسبیدن توپ به راکت قبل از پرتاب
|
||||||
|
ball->x = paddle->x + paddle->width / 2;
|
||||||
|
ball->y = paddle->y - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ball->move();
|
||||||
|
|
||||||
|
// برخورد با دیوارهای چپ و راست
|
||||||
|
if (ball->x <= 1 || ball->x >= WIDTH - 1) ball->dx = -ball->dx;
|
||||||
|
// برخورد با سقف
|
||||||
|
if (ball->y <= 0) ball->dy = -ball->dy;
|
||||||
|
|
||||||
|
// برخورد با راکت
|
||||||
|
if (ball->y >= paddle->y - 1 && ball->y <= paddle->y && ball->x >= paddle->x && ball->x <= paddle->x + paddle->width)
|
||||||
|
{
|
||||||
|
ball->dy = -ball->dy;
|
||||||
|
ball->y = paddle->y - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// افتادن توپ (باختن جان)
|
||||||
|
if (ball->y >= HEIGHT)
|
||||||
|
{
|
||||||
|
lives--;
|
||||||
|
ball->reset(paddle->x + paddle->width / 2, paddle->y - 1);
|
||||||
|
if (lives <= 0) gameOver = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// برخورد با آجرها
|
||||||
|
bool allDestroyed = true;
|
||||||
|
for (auto& b : bricks)
|
||||||
|
{
|
||||||
|
if (b.active)
|
||||||
|
{
|
||||||
|
allDestroyed = false;
|
||||||
|
if ((int)ball->x >= b.x && (int)ball->x < b.x + 2 && (int)ball->y == b.y)
|
||||||
|
{
|
||||||
|
b.active = false;
|
||||||
|
ball->dy = -ball->dy;
|
||||||
|
score += b.points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// شرط پیروزی
|
||||||
|
if (allDestroyed)
|
||||||
|
{
|
||||||
|
victory = true;
|
||||||
|
gameOver = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ذخیره تاریخچه بازی در فایل
|
||||||
|
void saveHistory()
|
||||||
|
{
|
||||||
|
ofstream outFile("game_history.txt", ios::app); // برای اضافه کردن به ته فایل
|
||||||
|
if (outFile.is_open())
|
||||||
|
{
|
||||||
|
// دریافت زمان فعلی
|
||||||
|
time_t now = time(0);
|
||||||
|
char* dt = ctime(&now);
|
||||||
|
// حذف کاراکتر خط جدید از انتهای رشته زمان
|
||||||
|
string timeStr = dt;
|
||||||
|
if (!timeStr.empty() && timeStr.back() == '\n') timeStr.pop_back();
|
||||||
|
|
||||||
|
outFile << "Name: " << playerName << " | Score: " << score << " | Date: " << timeStr << endl;
|
||||||
|
outFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// حلقه اصلی اجرای بازی
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
system("cls"); // پاکسازی اولیه
|
||||||
|
HideCursor();
|
||||||
|
|
||||||
|
while (!gameOver)
|
||||||
|
{
|
||||||
|
draw();
|
||||||
|
input();
|
||||||
|
logic();
|
||||||
|
waitFor(60); // کنترل سرعت بازی
|
||||||
|
}
|
||||||
|
|
||||||
|
// ذخیره امتیاز در پایان بازی
|
||||||
|
saveHistory();
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
if (victory)
|
||||||
|
{
|
||||||
|
cout << "\n\n\t****************************\n";
|
||||||
|
cout << "\t* YOU WON! *\n";
|
||||||
|
cout << "\t* Score saved to history *\n";
|
||||||
|
cout << "\t****************************\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << "\n\n\t----------------------------\n";
|
||||||
|
cout << "\t! GAME OVER !\n";
|
||||||
|
cout << "\t! Score saved to history !\n";
|
||||||
|
cout << "\t----------------------------\n";
|
||||||
|
}
|
||||||
|
cout << "\nPress any key to exit...";
|
||||||
|
_getch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// توابع منو
|
||||||
|
|
||||||
|
void showHelp()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
cout << "========================================\n";
|
||||||
|
cout << " GAME HELP \n";
|
||||||
|
cout << "========================================\n";
|
||||||
|
cout << " Controls:\n";
|
||||||
|
cout << " 'a' / 'd' : Move Paddle Left/Right\n";
|
||||||
|
cout << " 'SPACE' : Launch Ball\n";
|
||||||
|
cout << " 'q' : Quit Game\n\n";
|
||||||
|
cout << " Rules:\n";
|
||||||
|
cout << " Break all bricks to win.\n";
|
||||||
|
cout << " Don't let the ball fall.\n";
|
||||||
|
cout << "\nPress any key to return...";
|
||||||
|
_getch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showHistory()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
cout << "========================================\n";
|
||||||
|
cout << " GAME HISTORY \n";
|
||||||
|
cout << "========================================\n";
|
||||||
|
|
||||||
|
ifstream inFile("game_history.txt");
|
||||||
|
string line;
|
||||||
|
if (inFile.is_open())
|
||||||
|
{
|
||||||
|
while (getline(inFile, line))
|
||||||
|
{
|
||||||
|
cout << line << endl;
|
||||||
|
}
|
||||||
|
inFile.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << "No history found yet.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "\n========================================\n";
|
||||||
|
cout << "Press any key to return...";
|
||||||
|
_getch();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
srand(static_cast<unsigned int>(time(0))); // تنظیم اولیه اعداد تصادفی
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
cout << "========================================\n";
|
||||||
|
cout << " BREAKOUT - MAIN MENU \n";
|
||||||
|
cout << "========================================\n";
|
||||||
|
cout << " 1. New Game\n";
|
||||||
|
cout << " 2. Game History\n";
|
||||||
|
cout << " 3. Help\n";
|
||||||
|
cout << " 4. Exit\n";
|
||||||
|
cout << "========================================\n";
|
||||||
|
cout << " Select Option: ";
|
||||||
|
|
||||||
|
char choice = _getch();
|
||||||
|
|
||||||
|
if (choice == '1')
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
string pName;
|
||||||
|
cout << "\nEnter Player Name: ";
|
||||||
|
cin >> pName;
|
||||||
|
Game breakout(pName);
|
||||||
|
breakout.run();
|
||||||
|
}
|
||||||
|
else if (choice == '2')
|
||||||
|
{
|
||||||
|
showHistory();
|
||||||
|
}
|
||||||
|
else if (choice == '3')
|
||||||
|
{
|
||||||
|
showHelp();
|
||||||
|
}
|
||||||
|
else if (choice == '4')
|
||||||
|
{
|
||||||
|
cout << "\nGoodbye!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user