added files
CMake Build / build (ubuntu-latest) (push) Has been cancelled
@@ -0,0 +1,25 @@
|
|||||||
|
name: CMake Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main, master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main, master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build --config Release
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Linker files
|
||||||
|
*.ilk
|
||||||
|
|
||||||
|
# Debugger Files
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# debug information files
|
||||||
|
*.dwo
|
||||||
|
|
||||||
|
includes/temp.cpp
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(breakoutpp)
|
||||||
|
|
||||||
|
file(GLOB SOURCES
|
||||||
|
main.cpp
|
||||||
|
includes/*.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(breakoutpp ${SOURCES})
|
||||||
|
target_include_directories(breakoutpp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/includes)
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Breakout++
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
An implementation of the game "Athari breakout" in cpp
|
||||||
|
|
||||||
|
this is me and my friend [Matin](https://github.com/Matin-Ardestani) freshman year first semester project.
|
||||||
|
|
||||||
|
### How to play
|
||||||
|
|
||||||
|
there is a help menu that describes how you should play the game and how it works but basically :
|
||||||
|
|
||||||
|
you can move your paddle with "a" and "d" to catch the ball
|
||||||
|
you can press "p" to pause the game.
|
||||||
|
|
||||||
|
### Build Instruction
|
||||||
|
|
||||||
|
to build using cmake :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/farnam-jhn/breakoutpp.git
|
||||||
|
cd breakout
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
mkdir src
|
||||||
|
touch src/history.txt
|
||||||
|
cmake ..
|
||||||
|
cmake --build .
|
||||||
|
./breakoutpp
|
||||||
|
```
|
||||||
|
or you can use normal gcc compiler :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/farnam-jhn/breakoutpp.git
|
||||||
|
cd breakout
|
||||||
|
g++ -o breakoutpp main.cpp includes/*.cpp
|
||||||
|
./breakoutpp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Note
|
||||||
|
|
||||||
|
currently only supports unix-like operating systems (e.g Linux, macOS, BSD)
|
||||||
|
you can compile and play the game in windows using [WSL](https://learn.microsoft.com/en-us/windows/wsl/)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
you should cout this in order to get colored output on terminal:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\033[<COLORCODE>m<YOUR TEXT>\033[0m
|
||||||
|
|
||||||
|
|
||||||
|
color codes :
|
||||||
|
30-37: Foreground colors (30=black, 31=red, 32=green, 33=yellow, 34=blue, 35=magenta, 36=cyan, 37=white)
|
||||||
|
|
||||||
|
40-47: Background colors (same color order as foreground)
|
||||||
|
|
||||||
|
0: Reset to default
|
||||||
|
|
||||||
|
1: Bold/bright
|
||||||
|
|
||||||
|
4: Underline
|
||||||
|
|
||||||
|
in order to use color + bold/underline you should use ; coloumn
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
std::cout << "\033[31mThis is red text\033[0m" << std::endl;
|
||||||
|
std::cout << "\033[32mThis is green text\033[0m" << std::endl;
|
||||||
|
std::cout << "\033[1;34mThis is bold blue text\033[0m" << std::endl;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Headers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Structures
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Functions prototype
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Main function
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Functions
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
// Headers
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
#include <atomic>
|
||||||
|
#include "getchar.h"
|
||||||
|
#include "setcursor.h"
|
||||||
|
#include "structs.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Global varialbes
|
||||||
|
|
||||||
|
extern string board[30][80];
|
||||||
|
extern string hud[30][20];
|
||||||
|
extern int board_width;
|
||||||
|
extern int board_lenght;
|
||||||
|
extern int bricks_idx[36], bricks_idy[36];
|
||||||
|
extern int hudLength;
|
||||||
|
extern int hudWidth;
|
||||||
|
extern int bricksCount;
|
||||||
|
extern std::atomic<bool> running;
|
||||||
|
extern std::atomic<bool> paused;
|
||||||
|
|
||||||
|
extern string ballChar ;
|
||||||
|
extern string block ;
|
||||||
|
extern string blockRed ;
|
||||||
|
extern string blockGreen;
|
||||||
|
extern string blockBlue ;
|
||||||
|
extern string blockYellow ;
|
||||||
|
extern string trCorner ;
|
||||||
|
extern string tlCorner ;
|
||||||
|
extern string brCorner ;
|
||||||
|
extern string blCorner ;
|
||||||
|
extern string paddeleLine ;
|
||||||
|
extern string horizontalLine ;
|
||||||
|
extern string verticalLine ;
|
||||||
|
extern Player player;
|
||||||
|
|
||||||
|
// Function Prototypes
|
||||||
|
|
||||||
|
void hudCalculation();
|
||||||
|
string bCountInString();
|
||||||
|
string scoreInString();
|
||||||
|
bool isBrick(int, int);
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
void drawBoard(){
|
||||||
|
|
||||||
|
hudCalculation();
|
||||||
|
gotoxy(0, 0);
|
||||||
|
string currentChar;
|
||||||
|
cout << endl << endl;
|
||||||
|
for(int i = 0; i < board_width; i++){
|
||||||
|
cout << " ";
|
||||||
|
for(int j = 0; j < board_lenght + hudLength ; j++){
|
||||||
|
if (j < hudLength){
|
||||||
|
cout << hud[i][j];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int boardCol = j - hudLength;
|
||||||
|
currentChar = board[i][boardCol];
|
||||||
|
if (currentChar == horizontalLine ||
|
||||||
|
currentChar == verticalLine ||
|
||||||
|
currentChar == tlCorner ||
|
||||||
|
currentChar == trCorner ||
|
||||||
|
currentChar == blCorner ||
|
||||||
|
currentChar == brCorner ||
|
||||||
|
currentChar == ballChar){
|
||||||
|
cout << currentChar;
|
||||||
|
}
|
||||||
|
else if (isBrick(i, boardCol)) {
|
||||||
|
|
||||||
|
int nameSeed1 = (int)player.name[0];
|
||||||
|
int nameSeed2 = (int)player.name[1];
|
||||||
|
|
||||||
|
std::mt19937 gen(i * nameSeed1 + j * nameSeed2); // generates a random based on seed (a combination of i and j with player's name)
|
||||||
|
|
||||||
|
std::vector<std::string> colors = {blockRed, blockBlue, blockGreen, blockYellow, block}; // Creates a dynamic array containing the colored blocks characters
|
||||||
|
std::shuffle(colors.begin(), colors.end(), gen); // shuffles the colors dynamic array
|
||||||
|
|
||||||
|
for(int k = 0; k < 5; k++) {
|
||||||
|
std::cout << colors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
j += 4;
|
||||||
|
}
|
||||||
|
else if (currentChar == paddeleLine){
|
||||||
|
for (int k = 0 ; k < 10 ; k++){
|
||||||
|
cout << paddeleLine;
|
||||||
|
}
|
||||||
|
j += 9;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cout << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checking if a certain location contains a brick or not
|
||||||
|
|
||||||
|
bool isBrick(int x, int y){
|
||||||
|
for(int i = 0, j = 0; i < 36; i++, j++){
|
||||||
|
if(bricks_idx[i] == x){
|
||||||
|
if(bricks_idy[i] == y){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head up display
|
||||||
|
|
||||||
|
void hudCalculation(){
|
||||||
|
|
||||||
|
// setting up borders
|
||||||
|
for(int i = 1; i < hudLength - 1; i++){
|
||||||
|
hud[0][i] = horizontalLine; // top
|
||||||
|
hud[hudWidth - 1][i] = horizontalLine; // bottom
|
||||||
|
}
|
||||||
|
for(int i = 1; i < hudWidth - 1; i++){
|
||||||
|
hud[i][0] = verticalLine; // right
|
||||||
|
hud[i][hudLength - 1] = verticalLine; // left
|
||||||
|
}
|
||||||
|
// setting up corners
|
||||||
|
|
||||||
|
hud[0][0] = tlCorner;
|
||||||
|
hud[0][hudLength - 1] = trCorner;
|
||||||
|
hud[hudWidth - 1][0] = blCorner;
|
||||||
|
hud[hudWidth - 1][hudLength - 1] = brCorner;
|
||||||
|
|
||||||
|
for (int i = 1; i < hudWidth - 1; i++){
|
||||||
|
for (int j = 1; j < hudLength - 1; j++){
|
||||||
|
hud[i][j] = " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string score = " Score : " + scoreInString();
|
||||||
|
for (int i = 0; i < 15; i++){
|
||||||
|
hud[2][i + 2] = score[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
string health = " Health : " + to_string(player.health);
|
||||||
|
|
||||||
|
for (int i = 0 ; i < 11 ; i++){
|
||||||
|
hud[4][i + 2] = health[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
string bricksLine = " Bricks : " + bCountInString();
|
||||||
|
|
||||||
|
for (int i = 0 ; i < 12 ; i++){
|
||||||
|
hud[6][i + 2] = bricksLine[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paused) {
|
||||||
|
string pauseText = " PAUSED ";
|
||||||
|
for (int i = 0; i < 8; i++){
|
||||||
|
hud[8][i + 2] = pauseText[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proccessing input
|
||||||
|
|
||||||
|
int inputProccessing(Paddle &paddle){
|
||||||
|
|
||||||
|
using namespace std::chrono_literals; // for sleep function
|
||||||
|
|
||||||
|
char inputChar = getch();
|
||||||
|
bool moved = false;
|
||||||
|
int temp = paddle.start_loc.x;
|
||||||
|
switch (inputChar) {
|
||||||
|
case 'p':
|
||||||
|
case 'P':
|
||||||
|
paused = !paused;
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case 'a' :
|
||||||
|
case 'A' :
|
||||||
|
if (!paused && paddle.start_loc.x > 1) {
|
||||||
|
paddle.start_loc.x -= 3;
|
||||||
|
|
||||||
|
if (paddle.start_loc.x < 1) {
|
||||||
|
paddle.start_loc.x = 1;
|
||||||
|
}
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'd' :
|
||||||
|
case 'D' :
|
||||||
|
if (!paused && paddle.start_loc.x < board_lenght - 11) {
|
||||||
|
|
||||||
|
paddle.start_loc.x += 3;
|
||||||
|
|
||||||
|
if (paddle.start_loc.x > board_lenght - 11) {
|
||||||
|
paddle.start_loc.x = board_lenght - 11;
|
||||||
|
}
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changing paddle location
|
||||||
|
|
||||||
|
if (!paused && moved){
|
||||||
|
board[board_width - 2][paddle.start_loc.x] = paddeleLine;
|
||||||
|
board[board_width - 2][temp] = " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
string scoreInString(){
|
||||||
|
string result = to_string(player.score);
|
||||||
|
result.insert(0, 6 - result.length(), '0');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string bCountInString(){
|
||||||
|
string result = to_string(bricksCount);
|
||||||
|
result.insert(0, 2 - result.length(), '0');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef BOARD_H
|
||||||
|
#define BOARD_H
|
||||||
|
#include "getchar.h"
|
||||||
|
#include "structs.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void drawBoard();
|
||||||
|
bool isBrick(int, int);
|
||||||
|
int inputProccessing(Paddle &paddle);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void show_console_cursor(bool show) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
CONSOLE_CURSOR_INFO cci;
|
||||||
|
GetConsoleCursorInfo(handle, &cci);
|
||||||
|
cci.bVisible = show;
|
||||||
|
SetConsoleCursorInfo(handle, &cci);
|
||||||
|
#else
|
||||||
|
std::cout << (show ? "\033[?25h" : "\033[?25l");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void show_console_cursor(bool show);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once // prevents multiple inclusion
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <conio.h> // Windows
|
||||||
|
inline char mygetch() {
|
||||||
|
return _getch(); // Windows getch
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
inline char getch() {
|
||||||
|
char buf = 0;
|
||||||
|
struct termios old = {0};
|
||||||
|
tcgetattr(0, &old);
|
||||||
|
old.c_lflag &= ~ICANON; // disable line buffering
|
||||||
|
old.c_lflag &= ~ECHO; // disable echo
|
||||||
|
tcsetattr(0, TCSANOW, &old);
|
||||||
|
read(0, &buf, 1);
|
||||||
|
old.c_lflag |= ICANON;
|
||||||
|
old.c_lflag |= ECHO;
|
||||||
|
tcsetattr(0, TCSANOW, &old);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <ctime>
|
||||||
|
#include "getchar.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
extern string trCorner ;
|
||||||
|
extern string tlCorner ;
|
||||||
|
extern string brCorner ;
|
||||||
|
extern string blCorner ;
|
||||||
|
extern string paddeleLine ;
|
||||||
|
extern string horizontalLine ;
|
||||||
|
extern string verticalLine ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
history format:
|
||||||
|
PlayerName, Best socre, Best socre time, Last score, Last score time
|
||||||
|
*/
|
||||||
|
|
||||||
|
void saveData(string name, int score){
|
||||||
|
|
||||||
|
ifstream history_reader("src/history.txt");
|
||||||
|
if(!history_reader.is_open()){
|
||||||
|
cout << "ERROR OPENNING HISTORY!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
string date = ctime(&now);
|
||||||
|
date.pop_back(); // delete \n at the end
|
||||||
|
|
||||||
|
string output = "";
|
||||||
|
bool new_player = true;
|
||||||
|
|
||||||
|
string line;
|
||||||
|
|
||||||
|
while(getline(history_reader, line)){
|
||||||
|
|
||||||
|
int splitter[4];
|
||||||
|
splitter[0] = line.find(",");
|
||||||
|
splitter[1] = line.find(",", splitter[0] + 1);
|
||||||
|
splitter[2] = line.find(",", splitter[1] + 1);
|
||||||
|
splitter[3] = line.find(",", splitter[2] + 1);
|
||||||
|
|
||||||
|
string player_name = line.substr(0, splitter[0]);
|
||||||
|
int best_score = stoi(line.substr(splitter[0] + 1, splitter[1] - splitter[0] - 1));
|
||||||
|
string best_score_date = line.substr(splitter[1] + 1, splitter[2] - splitter[1] - 1);
|
||||||
|
int last_score = stoi(line.substr(splitter[2] + 1, splitter[3] - splitter[2] - 1));
|
||||||
|
string last_score_date = line.substr(splitter[3] + 1);
|
||||||
|
|
||||||
|
if(player_name == name){
|
||||||
|
new_player = false;
|
||||||
|
|
||||||
|
if(score >= best_score){
|
||||||
|
best_score = score;
|
||||||
|
best_score_date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_score = score;
|
||||||
|
last_score_date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += player_name + "," +
|
||||||
|
to_string(best_score) + "," +
|
||||||
|
best_score_date + "," +
|
||||||
|
to_string(last_score) + "," +
|
||||||
|
last_score_date + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
history_reader.close();
|
||||||
|
|
||||||
|
if(new_player){
|
||||||
|
output += name + "," +
|
||||||
|
to_string(score) + "," +
|
||||||
|
date + "," +
|
||||||
|
to_string(score) + "," +
|
||||||
|
date + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
ofstream history_write("src/history.txt", ios::trunc);
|
||||||
|
history_write << output;
|
||||||
|
history_write.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showHistory(){
|
||||||
|
ifstream history("src/history.txt");
|
||||||
|
if(!history.is_open()){
|
||||||
|
cout << "ERROR OPENNING HISTORY!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
system("clear");
|
||||||
|
const int tableWidth = 100;
|
||||||
|
// Top border
|
||||||
|
cout << endl << endl;
|
||||||
|
cout << tlCorner;
|
||||||
|
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
|
||||||
|
cout << trCorner << endl;
|
||||||
|
// Title
|
||||||
|
cout << verticalLine
|
||||||
|
<< "\033[33m" // yellow
|
||||||
|
<< setw(tableWidth) << left << " GAME HISTORY"
|
||||||
|
<< "\033[0m" // reset
|
||||||
|
<< verticalLine << endl;
|
||||||
|
// Separator
|
||||||
|
cout << verticalLine;
|
||||||
|
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
|
||||||
|
cout << verticalLine << endl;
|
||||||
|
// Header
|
||||||
|
cout << verticalLine << " "
|
||||||
|
<< "\033[36m" // cyan
|
||||||
|
<< setw(15) << left << "Player"
|
||||||
|
<< setw(12) << "Best Score"
|
||||||
|
<< setw(25) << "Best Date"
|
||||||
|
<< setw(14) << "Last Score"
|
||||||
|
<< setw(32) << "Last Date"
|
||||||
|
<< "\033[0m" // reset
|
||||||
|
<< " " << verticalLine << endl;
|
||||||
|
// Header separator
|
||||||
|
cout << verticalLine;
|
||||||
|
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
|
||||||
|
cout << verticalLine << endl;
|
||||||
|
string line;
|
||||||
|
while(getline(history, line)){
|
||||||
|
|
||||||
|
int splitter[4];
|
||||||
|
splitter[0] = line.find(",");
|
||||||
|
splitter[1] = line.find(",", splitter[0] + 1);
|
||||||
|
splitter[2] = line.find(",", splitter[1] + 1);
|
||||||
|
splitter[3] = line.find(",", splitter[2] + 1);
|
||||||
|
|
||||||
|
string player_name = line.substr(0, splitter[0]);
|
||||||
|
string best_score = line.substr(splitter[0] + 1, splitter[1] - splitter[0] - 1);
|
||||||
|
string best_score_date = line.substr(splitter[1] + 1, splitter[2] - splitter[1] - 1);
|
||||||
|
string last_score = line.substr(splitter[2] + 1, splitter[3] - splitter[2] - 1);
|
||||||
|
string last_score_date = line.substr(splitter[3] + 1);
|
||||||
|
|
||||||
|
cout << verticalLine << " "
|
||||||
|
<< "\033[32m" << setw(15) << left << player_name << "\033[0m" // green - reset
|
||||||
|
<< "\033[35m" << setw(12) << best_score << "\033[0m" // purple - reset
|
||||||
|
<< setw(16) << best_score_date << " "
|
||||||
|
<< "\033[35m" << setw(14) << last_score << "\033[0m" // purple - reset
|
||||||
|
<< setw(32) << last_score_date
|
||||||
|
<< " " << verticalLine << endl;
|
||||||
|
}
|
||||||
|
// Bottom border
|
||||||
|
cout << blCorner;
|
||||||
|
for(int i = 0; i < tableWidth; i++) cout << horizontalLine;
|
||||||
|
cout << brCorner << endl;
|
||||||
|
|
||||||
|
// escape
|
||||||
|
getch();
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <ctime>
|
||||||
|
#include "getchar.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void saveData(string name, int score);
|
||||||
|
void showHistory();
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
#include "structs.h"
|
||||||
|
#include "board.h"
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
extern Ball ball;
|
||||||
|
extern Player player;
|
||||||
|
extern int board_lenght;
|
||||||
|
extern int board_width;
|
||||||
|
extern string board[30][80];
|
||||||
|
extern string ballChar;
|
||||||
|
extern int bricks_idx[36];
|
||||||
|
extern int bricks_idy[36];
|
||||||
|
extern string paddeleLine ;
|
||||||
|
extern Paddle paddle;
|
||||||
|
extern int bricksCount;
|
||||||
|
extern std::atomic<bool> paused;
|
||||||
|
extern Brick bricks[36];
|
||||||
|
|
||||||
|
void ballmover(Ball &ball){
|
||||||
|
|
||||||
|
if (player.health == 0){
|
||||||
|
player.gameover = true;
|
||||||
|
}
|
||||||
|
else if (bricksCount == 0){
|
||||||
|
player.won = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
// Calculate new position
|
||||||
|
int tempNewX = ball.loc.x + ball.v.vX;
|
||||||
|
int tempNewY = ball.loc.y + ball.v.vY;
|
||||||
|
|
||||||
|
// Checking collision for current position
|
||||||
|
for(int i = 0; i < 36; i++){
|
||||||
|
if(bricks_idx[i] != -1 && bricks_idy[i] != -1){
|
||||||
|
int brick_row = bricks_idx[i];
|
||||||
|
int brick_col_start = bricks_idy[i];
|
||||||
|
|
||||||
|
// Check if ball is stuck in a brick
|
||||||
|
if(ball.loc.y == brick_row &&
|
||||||
|
ball.loc.x >= brick_col_start &&
|
||||||
|
ball.loc.x <= brick_col_start + 4){
|
||||||
|
// reverse both velocities
|
||||||
|
ball.v.vX = -ball.v.vX;
|
||||||
|
ball.v.vY = -ball.v.vY;
|
||||||
|
tempNewX = ball.loc.x + ball.v.vX;
|
||||||
|
tempNewY = ball.loc.y + ball.v.vY;
|
||||||
|
// delete brick and add score
|
||||||
|
player.score += bricks[i].score;
|
||||||
|
bricksCount--;
|
||||||
|
bricks_idx[i] = -1;
|
||||||
|
bricks_idy[i] = -1;
|
||||||
|
|
||||||
|
goto skip_normal_collision; // Skip rest of collision checks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking brick collison for new position
|
||||||
|
for(int i = 0; i < 36; i++){
|
||||||
|
if(bricks_idx[i] != -1 && bricks_idy[i] != -1){
|
||||||
|
int brick_row = bricks_idx[i];
|
||||||
|
int brick_col_start = bricks_idy[i];
|
||||||
|
int brick_col_end = brick_col_start + 4;
|
||||||
|
|
||||||
|
// checking if there is a brick there, Works like (isBrick( , )) function
|
||||||
|
if(tempNewY == brick_row &&
|
||||||
|
tempNewX >= brick_col_start &&
|
||||||
|
tempNewX <= brick_col_end){
|
||||||
|
|
||||||
|
bool bounceX = false;
|
||||||
|
bool bounceY = false;
|
||||||
|
|
||||||
|
// X direction
|
||||||
|
if(ball.v.vX > 0 && ball.loc.x < brick_col_start){ // heading right
|
||||||
|
bounceX = true;
|
||||||
|
}
|
||||||
|
else if(ball.v.vX < 0 && ball.loc.x > brick_col_end){ // heading left
|
||||||
|
bounceX = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y direction
|
||||||
|
if(ball.v.vY > 0 && ball.loc.y < brick_row){ // heading down
|
||||||
|
bounceY = true;
|
||||||
|
}
|
||||||
|
else if(ball.v.vY < 0 && ball.loc.y > brick_row){ // heading up
|
||||||
|
bounceY = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bounceX && bounceY){ // Corner hit
|
||||||
|
|
||||||
|
// fixing the special case problem. in this case two bricks collapse at once
|
||||||
|
bool special_case_handled = false; // flag
|
||||||
|
if(i < 23 && i % 12 != 0 && ball.v.vX > 0){
|
||||||
|
if(bricks_idx[i - 1] != -1 && bricks_idx[i + 12] != -1){
|
||||||
|
// delete brick and add score ( two bricks )
|
||||||
|
player.score += (bricks[i - 1].score + bricks[i + 12].score);
|
||||||
|
bricksCount -= 2;
|
||||||
|
bricks_idx[i - 1] = -1;
|
||||||
|
bricks_idy[i - 1] = -1;
|
||||||
|
bricks_idx[i + 12] = -1;
|
||||||
|
bricks_idy[i + 12] = -1;
|
||||||
|
special_case_handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(i < 23 && i % 12 != 11 && ball.v.vX < 0){
|
||||||
|
if(bricks_idx[i + 1] != -1 && bricks_idx[i + 12] != -1){
|
||||||
|
// delete brick and add score ( two bricks )
|
||||||
|
player.score += (bricks[i + 1].score + bricks[i + 12].score);
|
||||||
|
bricksCount -= 2;
|
||||||
|
bricks_idx[i + 1] = -1;
|
||||||
|
bricks_idy[i + 1] = -1;
|
||||||
|
bricks_idx[i + 12] = -1;
|
||||||
|
bricks_idy[i + 12] = -1;
|
||||||
|
special_case_handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!special_case_handled){ // no special case accured
|
||||||
|
// delete brick and add score
|
||||||
|
player.score += bricks[i].score;
|
||||||
|
bricksCount--;
|
||||||
|
bricks_idx[i] = -1;
|
||||||
|
bricks_idy[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ball.v.vX = -ball.v.vX;
|
||||||
|
ball.v.vY = -ball.v.vY;
|
||||||
|
}
|
||||||
|
else if(bounceX){ // Side hit
|
||||||
|
ball.v.vX = -ball.v.vX;
|
||||||
|
// delete brick and add score
|
||||||
|
player.score += bricks[i].score;
|
||||||
|
bricksCount--;
|
||||||
|
bricks_idx[i] = -1;
|
||||||
|
bricks_idy[i] = -1;
|
||||||
|
}
|
||||||
|
else { // Top/bottom hit
|
||||||
|
ball.v.vY = -ball.v.vY;
|
||||||
|
// delete brick and add score
|
||||||
|
player.score += bricks[i].score;
|
||||||
|
bricksCount--;
|
||||||
|
bricks_idx[i] = -1;
|
||||||
|
bricks_idy[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate position after bounce
|
||||||
|
tempNewX = ball.loc.x + ball.v.vX;
|
||||||
|
tempNewY = ball.loc.y + ball.v.vY;
|
||||||
|
|
||||||
|
break; // Only handle one brick per frame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_normal_collision:
|
||||||
|
|
||||||
|
// Wall collision
|
||||||
|
if (tempNewX <= 0 || tempNewX >= board_lenght - 1){
|
||||||
|
ball.v.vX = -ball.v.vX;
|
||||||
|
tempNewX = ball.loc.x + ball.v.vX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tempNewY == board_width - 1){
|
||||||
|
player.health--;
|
||||||
|
ball.v.vY = -ball.v.vY;
|
||||||
|
tempNewY = ball.loc.y + ball.v.vY;
|
||||||
|
}
|
||||||
|
else if (tempNewY <= 0 || tempNewY >= board_width - 1){
|
||||||
|
ball.v.vY = -ball.v.vY;
|
||||||
|
tempNewY = ball.loc.y + ball.v.vY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (tempNewY == board_width - 2) {
|
||||||
|
// Check if the ball's X position is inside the paddle (width 10)
|
||||||
|
if (tempNewX >= paddle.start_loc.x && tempNewX < paddle.start_loc.x + 10) {
|
||||||
|
|
||||||
|
int distanceFromPS = tempNewX - paddle.start_loc.x;
|
||||||
|
|
||||||
|
ball.v.vY = -1; // Force ball to move UP
|
||||||
|
|
||||||
|
int velocityMagnitude[10] = {3,2,2,1,1,1,1,2,2,3}; // an array that gives any x axis distance between the ball and paddle start a velocity
|
||||||
|
|
||||||
|
if (ball.v.vX > 0){
|
||||||
|
ball.v.vX = velocityMagnitude[distanceFromPS];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ball.v.vX = -velocityMagnitude[distanceFromPS];
|
||||||
|
}
|
||||||
|
|
||||||
|
tempNewY = ball.loc.y + ball.v.vY; // Update next Y immediately
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clear old position
|
||||||
|
|
||||||
|
if (ball.loc.x != tempNewX || ball.loc.y != tempNewY) {
|
||||||
|
board[ball.loc.y][ball.loc.x] = " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update position
|
||||||
|
ball.loc.x = tempNewX;
|
||||||
|
ball.loc.y = tempNewY;
|
||||||
|
|
||||||
|
|
||||||
|
// Draw ball at new position
|
||||||
|
board[ball.loc.y][ball.loc.x] = ballChar;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include "structs.h"
|
||||||
|
|
||||||
|
void ballmover(Ball &ball);
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "getchar.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char optionChoosenByUser(){
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "\n\n\033[33m <-------Select option!------->\033[0m" << std::endl
|
||||||
|
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<<" 1. New Game "
|
||||||
|
<<"\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl << std::endl
|
||||||
|
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<<" 2. Help "
|
||||||
|
<<"\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl << std::endl
|
||||||
|
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<<" 3. History "
|
||||||
|
<<"\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl << std::endl
|
||||||
|
<< "\033[34m ╔══════════════╗ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<<" 4. Exit "
|
||||||
|
<<"\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ╚══════════════╝ \033[0m" << std::endl;
|
||||||
|
|
||||||
|
char chosenOpt = getch();
|
||||||
|
return chosenOpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void helpMenu(){
|
||||||
|
system("clear");
|
||||||
|
std::cout << std::endl << std::endl
|
||||||
|
<< "\033[34m ╔══════════════════════════════════════════════════════════════════════╗ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " The game consist of few elements : "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " 1. The ball, 2. Paddel, 3. Blocks "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " The ball starts moving in a line; whenever the ball hits the wall, "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " a block or the paddel it reflects like a beam and whenever it hits "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " a block, the block gets destroyed. "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " The goal is to destroy all of the blocks "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " If your ball fall down and don't touch the paddel you lose a "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " heart; you have 3 hearts, if you lose them all you lose. "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " You can move the paddel using \"A\" & \"D\" to move left & right. "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " Press \"P\" or \"p\" to pause the game. "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " Press any button to exit. "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ║\033[0m"
|
||||||
|
<< " "
|
||||||
|
<< "\033[34m║ \033[0m" << std::endl
|
||||||
|
<< "\033[34m ╚══════════════════════════════════════════════════════════════════════╝ \033[0m" << std::endl;
|
||||||
|
|
||||||
|
getch();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include "getchar.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
char optionChoosenByUser();
|
||||||
|
void helpMenu();
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gotoxy(int x, int y) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
COORD pos = {(SHORT)x, (SHORT)y};
|
||||||
|
SetConsoleCursorPosition(hConsole, pos);
|
||||||
|
#else
|
||||||
|
printf("\033[%d;%dH", y, x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <iostream>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gotoxy(int x, int y);
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Player{
|
||||||
|
int score = 0;
|
||||||
|
std::string name;
|
||||||
|
bool initialInput = false;
|
||||||
|
int health = 3;
|
||||||
|
bool gameover = false;
|
||||||
|
bool won = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Location{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Brick{
|
||||||
|
Location loc;
|
||||||
|
int score;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Paddle{
|
||||||
|
Location start_loc;
|
||||||
|
// int lenght; // possible feature, right now considered 10
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Velocity{
|
||||||
|
int vX;
|
||||||
|
int vY;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ball{
|
||||||
|
Location loc;
|
||||||
|
Velocity v;
|
||||||
|
};
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
// Headers
|
||||||
|
|
||||||
|
#include "includes/menu.h"
|
||||||
|
#include "includes/getchar.h"
|
||||||
|
#include "includes/board.h"
|
||||||
|
#include "includes/cursorhide.h"
|
||||||
|
#include "includes/structs.h"
|
||||||
|
#include "includes/mechanic.h"
|
||||||
|
#include "includes/history.h"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
|
||||||
|
// ----- Global variables -----
|
||||||
|
|
||||||
|
// Game components
|
||||||
|
int board_lenght = 80;
|
||||||
|
int board_width = 30;
|
||||||
|
std::string board[30][80];
|
||||||
|
std::string hud[30][20];
|
||||||
|
int hudLength = 20;
|
||||||
|
int hudWidth = 30;
|
||||||
|
int velocitySpeed[3] = {60,70,80};
|
||||||
|
int bricksCount = 36;
|
||||||
|
Paddle paddle;
|
||||||
|
Ball ball;
|
||||||
|
Player player;
|
||||||
|
|
||||||
|
Brick bricks[36];
|
||||||
|
int bricks_idx[36], bricks_idy[36];
|
||||||
|
|
||||||
|
// Characters
|
||||||
|
|
||||||
|
std::string ballChar = "\033[32m●\033[0m";
|
||||||
|
std::string block = "█";
|
||||||
|
std::string blockRed = "\033[31m█\033[0m";
|
||||||
|
std::string blockGreen= "\033[32m█\033[0m";
|
||||||
|
std::string blockBlue = "\033[34m█\033[0m";
|
||||||
|
std::string blockYellow = "\033[33m█\033[0m";
|
||||||
|
std::string trCorner = "\033[34m╗\033[0m";
|
||||||
|
std::string tlCorner = "\033[34m╔\033[0m";
|
||||||
|
std::string brCorner = "\033[34m╝\033[0m";
|
||||||
|
std::string blCorner = "\033[34m╚\033[0m";
|
||||||
|
std::string paddeleLine = "\033[32m╍\033[0m";
|
||||||
|
std::string horizontalLine = "\033[34m═\033[0m";
|
||||||
|
std::string verticalLine = "\033[34m║\033[0m";
|
||||||
|
|
||||||
|
|
||||||
|
// ----- Functions prototype -----
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
void deallocation();
|
||||||
|
void locatePaddle(int x);
|
||||||
|
void boardRender();
|
||||||
|
void ballMoveTask();
|
||||||
|
void endGame();
|
||||||
|
void inputThread();
|
||||||
|
|
||||||
|
// ----- Main function -----
|
||||||
|
|
||||||
|
std::atomic<bool> running(true); /* used in order to manage the thread
|
||||||
|
and prevent threads racing (racing : a thread reading
|
||||||
|
a variable created by another when it's not fully written) */
|
||||||
|
std::atomic<bool> paused(false);
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
show_console_cursor(false); // hides the cursor
|
||||||
|
|
||||||
|
// Unicode settings
|
||||||
|
|
||||||
|
system("chcp 65001"); // for showing the unicode characters in terminal
|
||||||
|
|
||||||
|
// Menu
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
system("clear");
|
||||||
|
char opt = optionChoosenByUser();
|
||||||
|
switch (opt) {
|
||||||
|
case '1':
|
||||||
|
{ // written in scope to maintain the threads
|
||||||
|
|
||||||
|
setup(); // sets up the board
|
||||||
|
|
||||||
|
running.store(true);
|
||||||
|
|
||||||
|
system("clear");
|
||||||
|
std::cout << "\n\n Enter your name : ";
|
||||||
|
std::cin >> player.name;
|
||||||
|
|
||||||
|
system("clear");
|
||||||
|
|
||||||
|
std::cout << "\n\n PRESS ANY KEY TO START THE GAME. \n";
|
||||||
|
getch();
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
std::thread threadOne(boardRender); // creates a thread for board rendering
|
||||||
|
std::thread threadTwo(ballMoveTask); // created a thread for ball movement
|
||||||
|
std::thread threadThree(inputThread);
|
||||||
|
|
||||||
|
system("clear");
|
||||||
|
|
||||||
|
while (running && !player.gameover && !player.won) {
|
||||||
|
// small sleep for threads to finish their jobs
|
||||||
|
std::this_thread::sleep_for(milliseconds(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
running = false;
|
||||||
|
|
||||||
|
threadOne.join();
|
||||||
|
threadTwo.join();
|
||||||
|
threadThree.detach();
|
||||||
|
|
||||||
|
if (player.gameover || player.won) {
|
||||||
|
system("clear");
|
||||||
|
endGame();
|
||||||
|
std::cout << "\n\n Press enter twice to return to main menu\n";
|
||||||
|
getch();
|
||||||
|
saveData(player.name, player.score);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
helpMenu();
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
showHistory();
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
system("clear");
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << " Press \"c\" to confirm\n";
|
||||||
|
char confirmChar = getch();
|
||||||
|
if (confirmChar == 'c'){
|
||||||
|
system("clear");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
system("clear");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- Functions -----
|
||||||
|
|
||||||
|
void locatePaddle(int x){ // receives starting point x because y stays the same
|
||||||
|
board[board_width - 2][x] = paddeleLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the board when starting new game
|
||||||
|
void setup(){
|
||||||
|
|
||||||
|
/*
|
||||||
|
only the starting char of bricks and the paddle change. because it would be easier to layout them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// clearing board
|
||||||
|
|
||||||
|
for (int i = 0; i < board_width; i++){
|
||||||
|
for (int j = 0; j < board_lenght; j++) {
|
||||||
|
board[i][j] = " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting up variables
|
||||||
|
|
||||||
|
player.gameover = false;
|
||||||
|
player.won = false;
|
||||||
|
player.score = 0;
|
||||||
|
player.health = 3;
|
||||||
|
bricksCount = 36;
|
||||||
|
|
||||||
|
// setting up bricks
|
||||||
|
/*
|
||||||
|
How it works : it goes in a row and when ever it reaches the start of a brick it places that into the bricks_idx and does the same thing for the y.
|
||||||
|
Note : x and y in this function are swapped compared to cartesian system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int counterX = 1, counterY = 10;
|
||||||
|
for(int i = 0; i < 36; i++){ // saving the location of each brick
|
||||||
|
bricks[i].loc.x = counterX;
|
||||||
|
bricks[i].loc.y = counterY;
|
||||||
|
bricks_idx[i] = counterX;
|
||||||
|
bricks_idy[i] = counterY;
|
||||||
|
counterY += 5;
|
||||||
|
if(i == 11 || i == 23){ // 11 is where firsto row of bricks end and 23 is end of the second row
|
||||||
|
counterY = 10;
|
||||||
|
counterX++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting up brick scores
|
||||||
|
/*
|
||||||
|
first row(index 0 - 11) : 1000
|
||||||
|
second row(index 12 - 23) : 500
|
||||||
|
third row(index 24 - 35) : 200
|
||||||
|
*/
|
||||||
|
for(int i = 0; i < 12; i++){
|
||||||
|
bricks[i].score = 1000;
|
||||||
|
}
|
||||||
|
for(int i = 12; i < 24; i++){
|
||||||
|
bricks[i].score = 500;
|
||||||
|
}
|
||||||
|
for(int i = 24; i < 36; i++){
|
||||||
|
bricks[i].score = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting up borders
|
||||||
|
for(int i = 1; i < board_lenght - 1; i++){
|
||||||
|
board[0][i] = horizontalLine; // top
|
||||||
|
board[board_width - 1][i] = horizontalLine; // bottom
|
||||||
|
}
|
||||||
|
for(int i = 1; i < board_width - 1; i++){
|
||||||
|
board[i][0] = verticalLine; // right
|
||||||
|
board[i][board_lenght - 1] = verticalLine; // left
|
||||||
|
}
|
||||||
|
// setting up corners
|
||||||
|
board[0][0] = tlCorner;
|
||||||
|
board[0][board_lenght - 1] = trCorner;
|
||||||
|
board[board_width - 1][0] = blCorner;
|
||||||
|
board[board_width - 1][board_lenght - 1] = brCorner;
|
||||||
|
|
||||||
|
// setting up bricks
|
||||||
|
for(int i = 1; i <= 3; i++){
|
||||||
|
for(int j = 1; j < board_lenght - 1; j++){
|
||||||
|
if(isBrick(i, j)){
|
||||||
|
board[i][j] = block;
|
||||||
|
j += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup paddle
|
||||||
|
paddle.start_loc.x = (board_lenght - 10) / 2 - 1;
|
||||||
|
paddle.start_loc.y = board_width - 2;
|
||||||
|
locatePaddle(paddle.start_loc.x);
|
||||||
|
|
||||||
|
|
||||||
|
// setup ball : locations are chosen such that the ball hits the paddle initially
|
||||||
|
ball.loc.x = 22;
|
||||||
|
ball.loc.y = 15;
|
||||||
|
|
||||||
|
/* Note : the velocity below is not suitable for configuring the speed
|
||||||
|
in order to change the speed, change the value of interval in ballMoveTask
|
||||||
|
changing the velocity below would affect the ball collision angle.*/
|
||||||
|
|
||||||
|
ball.v.vX = 1;
|
||||||
|
ball.v.vY = 1;
|
||||||
|
|
||||||
|
board[ball.loc.y][ball.loc.x] = ballChar;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Board rendering
|
||||||
|
|
||||||
|
void boardRender() {
|
||||||
|
|
||||||
|
auto interval = milliseconds(16);
|
||||||
|
auto next_time = steady_clock::now();
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
next_time += interval;
|
||||||
|
drawBoard();
|
||||||
|
std::this_thread::sleep_until(next_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input processing thread
|
||||||
|
|
||||||
|
void inputThread() {
|
||||||
|
while (running && !player.gameover && !player.won) {
|
||||||
|
int q = inputProccessing(paddle);
|
||||||
|
if (q == 0) {
|
||||||
|
running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ball rendering
|
||||||
|
|
||||||
|
void ballMoveTask(){
|
||||||
|
|
||||||
|
auto next_time = steady_clock::now();
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
auto interval = milliseconds(velocitySpeed[abs(ball.v.vX) - 1]);
|
||||||
|
next_time += interval;
|
||||||
|
|
||||||
|
if (!paused){
|
||||||
|
ballmover(ball);
|
||||||
|
if (player.gameover || player.won){
|
||||||
|
running = false; // closes the threads
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_until(next_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void endGame(){
|
||||||
|
|
||||||
|
// Reporting
|
||||||
|
|
||||||
|
if (player.gameover){
|
||||||
|
std::cout << "\n\n Game over.\n";
|
||||||
|
}else {
|
||||||
|
std::cout << "\n\n Game finished. \n Congrats! You Won!";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n Your score : ";
|
||||||
|
std::cout << player.score;
|
||||||
|
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 158 KiB |