forked from farnam_jhn/breakoutpp
added files
This commit is contained in:
@@ -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;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user