I don't have time to really analyze the code right now, but all you should have to do is create a while loop with some escape condition. Your escape condition seems kind of convoluted (I'm c++ programmer not c btw) just at a glance. Make it something simple like if player reaches finishing position then set finished variable to true. I know that is what you're essentially trying to do, but maybe make a separate function just to separate things a bit for your saving function and loading function. I actually did a similar program to this one a long time ago that you're welcome to look at. It's in C++, but maybe can help with some things still.
I notice the area you seem to lock up is with that usrinput goto tag. I don't use goto tags and I'm not sure if that is common for c programs to do, but I don't think it is. Maybe take that out and allow your while loop to just flow.
Here is my program if you want to look at it:
/*
I modified my maze game to use a finite state machine where the rooms are states and
when a new state is entered information will be displayed on the screen. Transition is the way to get back
to another state by leaving the room and the state name is the room that you are currently in. Most of the new
finite state machine code is near the top.
*/
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <string>
#include <stdio.h>
#include <time.h>
#include <fstream>
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
//states
#define initialRoom 0
#define northRoom 1
#define southRoom 2
#define westRoom 3
#define eastRoom 4
#define EXIT 5
void gotoxy(short x, short y)
{
HANDLE hConsoleOutput;
COORD Cursor_Pos = {x, y};
hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hConsoleOutput, Cursor_Pos);
}
void setcolor(unsigned short color)
{
HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hcon,color);
}
using namespace std;
string playerName;
int selection;
int score = 0;
int row;
int col;
int x = 15;
int y = 10;
int exitFlag = 0;
int finished = 0;
const int MAZE_WIDTH = 30;
const int MAZE_HEIGHT = 20;
clock_t counter;
int seconds = 0;
int minutes;
int smPebble;
int lgPebble;
time_t start, end;
int menuTime;
char maze[MAZE_HEIGHT][MAZE_WIDTH] =
{
{'|','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ',' ',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ','O',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ','o',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ','o',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|','=','=','=','o','=','=','=','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=',' ',' ',' ',' ',' ',' ',' ',' ',' ','=','=','=','=','=','=','=','=','=','|'},
{'|','E','|',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ','|'},
{'|','X','|',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ','|'},
{'|',' ','|',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ','|'},
{'|',' ',' ',' ',' ',' ','O','o','o','o','o',' ',' ',' ',' ',' ',' ',' ',' ',' ','o','o','o','o','O',' ',' ',' ',' ','|'},
{'|','I','|',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ','|'},
{'|','T','|',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ',' ','|',' ',' ',' ',' ',' ',' ',' ',' ','|'},
{'|','=','=','=','=','=','=','=','=','=','=',' ',' ',' ',' ',' ',' ',' ',' ',' ','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|','=','=','=','o','=','=','=','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ','o',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ','o',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ','O',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','|',' ',' ',' ',' ',' ',' ',' ','|','=','=','=','=','=','=','=','=','=','|'},
{'|','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','=','|'}
};
//New state class
class State
{
public:
State();
int state;
string transition;
string stateName;
void InitialRoom();
void NorthRoom();
void SouthRoom();
void WestRoom();
void EastRoom();
void FinalRoom();
};
State player;
//constructor
State::State()
{
transition = "North, South, East, West";
stateName = "Initial Room";
}
//room state change functions
void State::InitialRoom()
{
transition = "North, South, East, West";
stateName = "Initial Room";
}
void State::NorthRoom()
{
transition = "South ";
stateName = "North Room ";
}
void State::SouthRoom()
{
transition = "North ";
stateName = "South Room ";
}
void State::WestRoom()
{
transition = "East, West ";
stateName = "West Room ";
}
void State::EastRoom()
{
transition = "West ";
stateName = "East Room ";
}
//exit game when final room is reached
void State::FinalRoom()
{
finished = 1;
}
//check nodes and set state accordingly
void CheckStates()
{
if ((x == 15 && y == 6) || (x == 15 && y == 13) || (x == 11 && y == 10) || (x == 19 && y == 10))
{
player.state = initialRoom;
}
if (x == 15 && y == 5)
{
player.state = northRoom;
}
if (x == 15 && y == 14)
{
player.state = southRoom;
}
if (x == 10 && y == 10)
{
player.state = westRoom;
}
if (x == 20 && y == 10)
{
player.state = eastRoom;
}
if (x == 1 && y == 10)
{
player.state = EXIT;
}
}
//call functions depending on state entered
void ChangeStates()
{
switch(player.state)
{
case initialRoom:
player.InitialRoom();
break;
case northRoom:
player.NorthRoom();
break;
case southRoom:
player.SouthRoom();
break;
case westRoom:
player.WestRoom();
break;
case eastRoom:
player.EastRoom();
break;
case EXIT:
player.FinalRoom();
break;
}
}
void DisplayStateInfo()
{
gotoxy(44, 3);
setcolor(8);
cout << player.transition;
gotoxy(39, 5);
setcolor(8);
cout << player.stateName;
}
//---------------------------------------------------------
// Function: DrawMaze()
// Purpose: Draws the character array to create the maze and colors it
//---------------------------------------------------------
void DrawMaze()
{
system("cls");
for (row = 0; row < MAZE_HEIGHT; row++)
{
for (col = 0; col < MAZE_WIDTH; col++)
{
if (maze[row][col] == '=' || maze[row][col] == '|')
setcolor(8);
else if (maze[row][col] == 'o')
setcolor(13);
else if (maze[row][col] == 'O')
setcolor(14);
else if (maze[row][col] == 'F')
setcolor(12);
cout << maze[row][col];
}
cout << "\n";
}//end for
}//end DrawMaze()
//---------------------------------------------------------
// Function: CheckKeys()
// Purpose: Checks for user keyboard input and handles it
//---------------------------------------------------------
void CheckKeys()
{
//move up
if (KEY_DOWN(VK_UP))
{
y = y - 1;//move position
if (maze[y][x] == ' ' || maze[y][x] == 'o' || maze[y][x] == 'O')//check to see if new position is traversable
{
Sleep(200);//delay so only one coord is moved
gotoxy(x, y + 1);//erase character as it is moved
cout << " ";
}
else if (maze[y][x] == '=' || maze[y][x] == '|')//if new position is a wall then reset position
{
y = y + 1;
}
}
//move down
else if (KEY_DOWN(VK_DOWN))
{
y = y + 1;
if (maze[y][x] == ' ' || maze[y][x] == 'o' || maze[y][x] == 'O')
{
Sleep(200);
gotoxy(x, y - 1);
cout << " ";
}
else if (maze[y][x] == '=' || maze[y][x] == '|')
{
y = y - 1;
}
}
//move left
else if (KEY_DOWN(VK_LEFT))
{
x = x - 1;
if (maze[y][x] == ' ' || maze[y][x] == 'o' || maze[y][x] == 'O')
{
Sleep(200);
gotoxy(x + 1, y);
cout << " ";
}
else if (maze[y][x] == '=' || maze[y][x] == '|')
{
x = x + 1;
}
}
//move right
else if (KEY_DOWN(VK_RIGHT))
{
x = x + 1;
if (maze[y][x] == ' ' || maze[y][x] == 'o' || maze[y][x] == 'O')
{
Sleep(200);
gotoxy(x - 1, y);
cout << " ";
}
else if (maze[y][x] == '=' || maze[y][x] == '|')
{
x = x - 1;
}
}
//escape = quit
else if (KEY_DOWN(VK_ESCAPE))
{
exitFlag = 1;//exit game
Sleep(200);
}
}//end CheckKeys()
//---------------------------------------------------------
// Function: DisplayMenus()
// Purpose: Displays menu and handles menu branching
//---------------------------------------------------------
void DisplayMenus()
{
system("cls");
cout << "Make Your Selection, " << playerName << ": \n\n";
cout << "1 - Start Game\n";
cout << "2 - Instructions\n";
cout << "3 - About\n";
cout << "4 - Quit\n\n";
cout << "Selection: ";
cin >> selection;
switch(selection)
{
case 1:
DrawMaze();
break;
case 2:
system("cls");
cout << "The objective of the game is to traverse the maze while picking up items to \nincrease your score, but hurry up time is ticking.";
cout << "\n\nGame Items:";
setcolor(12);
cout << "\n\nX - YOU, The Player";
setcolor(13);
cout << "\no - Adds 100 points to your score";
setcolor(14);
cout << "\nO - Adds 1000 points to your score";
setcolor(8);
cout << "\n= - Wall type 1 (cannot be passed through)";
cout << "\n| - Wall type 2 (cannot be passed through)";
setcolor(12);
cout << "\nF - Finish Line";
setcolor(3);
cout << "\n\nGame Controls:";
cout << "\n\nArrow Keys - Move left, right, up, down";
cout << "\nEscape - Exit Game\n\n";
cout << "1 - Return to Main Menu\n\n";
cout << "Selection: ";
cin >> selection;
if (selection == 1)
{
DisplayMenus();
}
break;
case 3:
system("cls");
cout << "Written by: BN \n\n";
cout << "Objective: A MAZE GAME MADE FROM C++\n\n";
cout << "1 - Return to Main Menu\n\n";
cout << "Selection: ";
cin >> selection;
if (selection == 1)
{
DisplayMenus();
}
break;
case 4:
exitFlag = 1;
break;
default:
DisplayMenus();
break;
}//end switch
}//end DisplayMenus()
//---------------------------------------------------------
// Function: ScoreKeeper()
// Purpose: Adds to the score when items are encountered
// in-game and displays the score to the screen
//---------------------------------------------------------
void ScoreKeeper()
{
if (maze[y][x] == 'o')
{
maze[y][x] = ' ';
score = score + 100;
smPebble = smPebble + 1;
}
if (maze[y][x] == 'O')
{
maze[y][x] = ' ';
score = score + 1000;
lgPebble = lgPebble + 1;
}
gotoxy(39, 7);
setcolor(8);
cout << score;
}//end ScoreKeeper()
//---------------------------------------------------------
// Function: SaveScore()
// Purpose: Allows the player to save their score to a file
//---------------------------------------------------------
void SaveScore()
{
ofstream scoreFile;
scoreFile.open ("score.txt", ios::app);
scoreFile << playerName << "'s score card:";
scoreFile << "\nNumber of small pebbles recovered: " << smPebble;
scoreFile << "\nNumber of large pebbles recovered: " << lgPebble;
scoreFile << "\nBase score: " << score;
scoreFile << "\nSeconds elapsed: " << seconds;
scoreFile << "\nFinal score: " << score/seconds;
scoreFile << "\n\n";
scoreFile.close();
}//end SaveScore()
//---------------------------------------------------------
// Function: BeatGame()
// Purpose: This code executes when the player reaches
// the end of the maze. Gives the player the
// option to save their score before quitting.
//---------------------------------------------------------
void BeatGame()
{
system("cls");
setcolor(3);
cout << "You've beat the game, CONGRATULATIONS!";
cout << "\n\n\tScore Summary: ";
cout << "\n\n\tNumber of small pebbles recovered: " << smPebble;
cout << "\n\n\tNumber of large pebbles recovered: " << lgPebble;
cout << "\n\n\tBase score: " << score;
cout << "\n\n\tSeconds elapsed: " << seconds;
cout << "\n\n\tFinal score: " << score/seconds;
cout << "\n\n1 - Save score to a file and quit";
cout << "\n\n2 - Quit without saving score";
cout << "\n\nSelection: ";
cin >> selection;
switch (selection)
{
case 1:
SaveScore();
exitFlag = 1;
break;
case 2:
exitFlag = 1;
break;
default:
BeatGame();
}//end switch
}//end BeatGame()
//---------------------------------------------------------
// Function: DisplayTimer()
// Purpose: Times and displays the time to the screen.
// Seconds taken is also used in score calculation.
//---------------------------------------------------------
void DisplayTimer()
{
seconds = (clock()/1000) - menuTime + 1;
gotoxy(39, 9);
setcolor(8);
cout << seconds;
}//end DisplayTimer()
//---------------------------------------------------------
// Main Module
// The game starts here
//---------------------------------------------------------
int main()
{
time(&start);
system("cls");
setcolor(3);
cout << "Welcome to MAZE GAME!\n\n";
cout << "Please, Introduce yourself\n\n";
cout << "What name would you like to go by? ";
cin >> playerName;
DisplayMenus();
gotoxy(32, 1);
cout << playerName << "'s Maze";
gotoxy(32, 3);
cout << "Transition: ";
gotoxy(32, 5);
cout << "State: ";
gotoxy(32, 7);
cout << "Score:";
gotoxy(32, 9);
cout << "Time:";
time(&end);
menuTime = difftime(end, start);/*get menu run time so I can subtract from the game run time so my timer is accurate
since it starts when the program starts*/
//game loop
while (exitFlag == 0)
{
CheckKeys();
ScoreKeeper();
DisplayTimer();
DisplayStateInfo();
CheckStates();
ChangeStates();
gotoxy(x, y);//Draw character as coords change
setcolor(12);
cout << "X";
/*
if (maze[y][x] == 'F')
{
finished = 1;//reached finished line so finished is true
}
*/
if (finished == 1)//if finish line is reached exit game loop by going to the end of the game screen
{
BeatGame();
}
}//end while
}//end main