Snake Console Game Laggy

Hey everybody. Sorry for the long and messy code. I'm still learning :) Anyways, please try running my code and then playing the game. Sometimes the game will lag up and the snake will move really slow, then it will just suddenly go back to normal speed. That's that part I need help with. I can't seem to figure out why it does that. You should focus on the playGame() function because I tested only that function and it still lags so I think something in there is causing the game to lag.

Feel free to suggest any other things I could do to improve my code too. Thanks!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  //Final touches to add: Color change in settings. Maybe add more options to the game

#include<iostream>
#include<iomanip>
#include<Windows.h>
#include<fstream>
#include<conio.h>
#include<time.h>
#include<string>
#include<cstdlib>

using namespace std;

int rows = 20, columns = 60, snakelength, fruity, fruitx, snakex[1656], snakey[1656], score, numberscores[11][2], intemp, menuchoice = 0, pause, *r = &rows, *c = &columns, fieldsize = 1, lag = 20; //Current direction goes along with char arrays for snake body parts. 
char map[24][70], currentdirection[1656], tempdirection1, tempdirection2, direction, menukey; //map(row, column)
string scores[11][2], temp, username, size[3] = { "Small", "Medium", "BIG" };//Scores for high score board || used for sorting scores || CIN name || map size
int  intStats[3] = { 1, 100, 0 }, statselected = 0;//Stat upgrade points. Length gain, score gain, powerup points
string gameStats[3] = {"Length Gain(Max 3):", "Score Gain per Fruit(Max 1000):", "Powerup Points"};//For upgrade menu
bool isGameOver;
void clearScreen();
void drawMap(); //Draws the board
void setupGame(); //Initiates stats
void headPos(); //Moves head
void playGame(); //Plays the game
void moveParts(int); //Moves rest of body parts
void updateGame(); //Updates status of game (fruits, death, score)
void generateFruitPos(); //Generates fruit on map
void endGameScreen(); //Shows end game screen when you lose
void scoreIntoArray(); //Grabs .txt file data and stores into array
void displayHighScores(); //Shows scoreboard
void sortHighScores();//Sorts the high scores
void settings();//Settings menu
void powerupMenu();//Powerup Menu


int main() //Contains Menu
{

	while (true)
	{
		string menu[6] = { "Play       ", "Settings   ", "   High Scores", "Help       ", "About      ", "Exit       " };
		size[0] = "Small";
		size[1] = "Medium";
		size[2] = "BIG";

			clearScreen();
		//Graphics at menu page
		cout << "               ==================================================      " << endl;
		for (int i = 0; i < 10; i++)
		{
			cout << "              ||                                                ||     " << endl;
			if (i == 5)
			{
				cout << "              ||               Welcome to Snake                 ||     " << endl;
				cout << "              ||     Use WASD to move and navigate the menu     ||     " << endl;
				cout << "              ||   Make sure to change settings before playing  ||     " << endl;
			}
		}
		cout << "               ==================================================      \n\n" << endl;

		if (_kbhit())//Grabs any key presses and assigns to direction
		{
			menukey = _getch();

		}

		for (int x = 0; x < 6; x++)
		{
			if (menuchoice == x)
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 3);
				cout << right << setw(46) << menu[x] << endl;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
			}
			else
			{
				cout << right << setw(46) << menu[x] << endl;
			}
		}

		if (menukey == 'w')
		{
			menuchoice -= 1;
			if (menuchoice == -1)
			{
				menuchoice = 5;
			}
			menukey = NULL;
		}
		else if (menukey == 's')
		{
			menuchoice += 1;
			if (menuchoice == 6)
			{
				menuchoice = 0;
			}
			menukey = NULL;
		}
		else if (menukey == VK_RETURN)
		{
			if (menuchoice == 0)
			{
				playGame();
			}
			else if (menuchoice == 1)
			{
				system("cls");
				settings();
				system("pause");
			}
			else if (menuchoice == 2)
			{
				system("cls");
				scoreIntoArray();
				cout << "Place || Name       || High Score || Snake Length" << endl;
				cout << "_________________________________________________" << endl;
				scoreIntoArray(); //Takes top 10 scores in highscores.txt and puts into array. Then arranges them. Inserts new high score here if user made a new high score.
				displayHighScores();
				system("pause");
			}
			else if (menuchoice == 3)
			{
				system("cls");
				cout << "Use W A S D to move" << endl << "Use W S and the ENTER key to navigate the menu" << endl << "Use the settings option in the menu to change difficulty\n\n\n";
				cout << "                              Game Rules\n";
				cout << "------------------------------------------------------------------" << endl;
				cout << "1. If the snake head touches any wall or its own body, you lose.\n" << endl;
				cout << "2. For every 15 fruits eaten, you get one powerup.\n\n";
				cout << "Press the Escape key to enter the powerup screen\nselect what to upgrade by using WASD and ENTER to continue\n" << endl;
				cout << "3. Have fun!\n\n\n";
				system("pause");
				system("cls");
			}
			else if (menuchoice == 4)
			{
				system("cls");
				cout << "Programmer: Dan Tu" << endl;
				system("pause");
			}
			else if (menuchoice == 5)
			{
				exit(0);
			}
			menukey = NULL;
		}
	}
	return 0;
}

//All functions for the Game
void clearScreen()
{
	HANDLE hOut;
	COORD Position;

	hOut = GetStdHandle(STD_OUTPUT_HANDLE);

	Position.X = 0;
	Position.Y = 0;
	SetConsoleCursorPosition(hOut, Position);
}
void setupGame(){
	snakelength = 5;//Default setting
	srand(time(NULL));//Sets random seed
	generateFruitPos();
	score = 0;
	system("cls");
	direction = 'd';
	intStats[0] = 1;
	intStats[1] = 100;
	intStats[2] = 0;

	for (int x = 0; x < snakelength; x++)
	{
		snakey[x] = rows/2;
		snakex[x] = (columns/2) - x;
		currentdirection[x] = 'd';
	}

	//end snake body

	for (int x = 0; x < rows; x++) //FILLS EMPTY ARRAY SPOTS
	{
		for (int y = 0; y < columns; y++)
		{
			map[x][y] = ' ';
		}
	}
	//end filling of array

	for (int x = 0; x < rows; x++) //SETS BORDER
	{
		for (int y = 0; y < columns; y++)
		{
			map[0][y] = '*';
			map[rows - 1][y] = '*';
			map[x][0] = '*';
			map[x][columns - 1] = '*';
			map[fruity][fruitx] = '@';
			for (int i = 0; i < snakelength; i++)
			{
				map[snakey[i]][snakex[i]] = 'o';
			}
		}
	}
	//end border creation


}
void drawMap(){ //draws map and everything in it
	for (int x = 0; x < rows; x++)
	{
		for (int y = 0; y < columns; y++)
		{				
			if (map[x][y] == 'o')
				{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
				cout << map[x][y];
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
				}
			else
				cout << map[x][y];

		}
		cout << endl;
	}
	cout << "Score: " << score << "        Snake Length: " << snakelength << "        Powerups: " << intStats[2];
}
void playGame(){
	isGameOver = false; //1 = true. 0 = false
	setupGame();
	do
	{
		drawMap();


		if (_kbhit())//Grabs any key presses and assigns to direction
		{
				direction = _getch();
		}

		if (direction == VK_ESCAPE)
		{
			powerupMenu();
			direction = NULL;
		}
		
		headPos(); //Changes head position first

		for (int x = 1; x < snakelength; x++) //Then changes body corresponding to head
		{
			map[snakey[x]][snakex[x]] = ' '; //Makes slot empty
			tempdirection2 = tempdirection1; //Puts direction of previous body part in here. Temp1 at x=1 starts off as the direction of the head.
			tempdirection1 = currentdirection[x]; //Tempdirection1 is set in headPos() initially and stores the direction of the current body part. Then stores it in temp2 above
			moveParts(x); //Moves body part
			currentdirection[x] = tempdirection2; //Sets body part direction to the one before it
		}

		for (int x = 0; x < snakelength; x++)
		{
			map[snakey[x]][snakex[x]] = 'o';
		}
		Sleep(lag);
		clearScreen();

	} while (isGameOver == false);

	if (isGameOver == true)
	{
		endGameScreen();
	}
	main();
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
void headPos() //Fixed all problems here. Simply moves the head and sets tempdirection1 to the direction the head was moving before changing it.
{
		if (currentdirection[0] == 'd') //if head is currently moving right
		{
			map[snakey[0]][snakex[0]] = ' ';
			moveParts(0);
			updateGame();
			if (direction == 'w')
			{
				tempdirection1 = 'd';
				currentdirection[0] = 'w';
			}
			else if (direction == 's')
			{
				tempdirection1 = 'd';
				currentdirection[0] = 's';
			}
			else
			{
				tempdirection1 = 'd';
				currentdirection[0] = 'd';
			}
		}
		else if (currentdirection[0] == 'a')
		{
			map[snakey[0]][snakex[0]] = ' ';
			moveParts(0);
			updateGame();
			if (direction == 'w')
			{
				tempdirection1 = 'a';
				currentdirection[0] = 'w';
			}
			else if (direction == 's')
			{
				tempdirection1 = 'a';
				currentdirection[0] = 's';
			}
			else
			{
				tempdirection1 = 'a';
				currentdirection[0] = 'a';
			}
		}
		else if (currentdirection[0] == 'w')
		{
			map[snakey[0]][snakex[0]] = ' ';
			moveParts(0);
			updateGame();
			if (direction == 'd')
			{
				tempdirection1 = 'w';
				currentdirection[0] = 'd';
			}
			else if (direction == 'a')
			{
				tempdirection1 = 'w';
				currentdirection[0] = 'a';
			}
			else
			{
				tempdirection1 = 'w';
				currentdirection[0] = 'w';
			}
		}
		else if (currentdirection[0] == 's')
		{
			map[snakey[0]][snakex[0]] = ' ';
			moveParts(0);
			updateGame();
			if (direction == 'a')
			{
				tempdirection1 = 's';
				currentdirection[0] = 'a';
			}
			else if (direction == 'd')
			{
				tempdirection1 = 's';
				currentdirection[0] = 'd';
			}
			else
			{
				tempdirection1 = 's';
				currentdirection[0] = 's';
			}
		}
	}
void moveParts(int x) //Moves parts according to their direction.
{
	if (currentdirection[x] == 'd')
	{
		snakex[x] += 1;
	}
	if (currentdirection[x] == 'a')
	{
		snakex[x] -= 1;
	}
	if (currentdirection[x] == 'w')
	{
		snakey[x] -= 1;
	}
	if (currentdirection[x] == 's')
	{
		snakey[x] += 1;
	}
}
void updateGame(){ //Checks if new head position touches game ending part. Also checks if touches fruit.
	if (map[snakey[0]][snakex[0]] == '*') //Checks Border
	{
		isGameOver = true;
		Sleep(2000);
	}
	else if (map[snakey[0]][snakex[0]] == 'o')
	{
		isGameOver = true;
		Sleep(2000);
	}
	else if (map[snakey[0]][snakex[0]] == '@') //If head touches fruit
	{
		generateFruitPos();
		score += intStats[1];
		if ((snakelength - 5) % 15 == 0)
		{
			intStats[2] += 1;
		}
		for (int loop = 0; loop < intStats[0]; loop++)
		{
			snakelength += 1;

			if (currentdirection[snakelength - 2] == 'a') // remind that snakelength starts at 0. NOT 1. Therefore we must use snakelength 2 to represent the tail piece after snakelength += lengthgain.
			{
				snakex[snakelength - 1] = snakex[snakelength - 2] + 1;
				snakey[snakelength - 1] = snakey[snakelength - 2];
			}
			else if (currentdirection[snakelength - 2] == 's')
			{
				snakex[snakelength - 1] = snakex[snakelength - 2];
				snakey[snakelength - 1] = snakey[snakelength - 2] - 1;
			}
			else if (currentdirection[snakelength - 2] == 'd')
			{
				snakex[snakelength - 1] = snakex[snakelength - 2] - 1;
				snakey[snakelength - 1] = snakey[snakelength - 2];
			}
			else if (currentdirection[snakelength - 2] == 'w')
			{
				snakex[snakelength - 1] = snakex[snakelength - 2];
				snakey[snakelength - 1] = snakey[snakelength - 2] + 1;
			}
			currentdirection[snakelength - 1] = currentdirection[snakelength - 2];


			if (snakelength == ((rows - 1)*(columns - 1)))
			{
				Sleep(2000);
				system("cls");
				cout << "CONGRATULATIONS!!! YOU HAVE BEAT THE GAME!" << endl << endl;
				system("pause");
				endGameScreen();
			}
		}
	}
	else
		isGameOver = false;
}
void generateFruitPos(){
	fruitx = rand() % (columns - 3) + 1;//Random x
	fruity = rand() % (rows - 3) + 1;//Random Y
	for (int x = 0; x < snakelength; x++) //Checks if spawning on snake part. If it is, then give it a new position
	{
		if (map[fruity][fruitx] == 'o')
		{
			fruitx = rand() % (columns - 3) + 1;
			fruity = rand() % (rows - 3) + 1;
		}
	}
	map[fruity][fruitx] = '@';
}
void endGameScreen(){
	system("cls");
	cout << "             GAME OVER" << endl << endl << endl;
	cout << "Your Score: " << score << "         Your length was: " << snakelength << endl << endl << endl << endl;
	cout << "Please Enter Your Name: ";
	cin >> username;
	scores[10][1] = username; //[10][x] holds no place number. Only name, score, and length.
	numberscores[10][0] = score; //Places score into this array
	numberscores[10][1] = snakelength; //Places snake length into this array
	scoreIntoArray(); //Takes top 10 scores in highscores.txt and puts into array. Then arranges them. Inserts new high score here if user made a new high score.
	sortHighScores();
	if (numberscores[10][1] > numberscores[9][1])//Checks if you made a high score
	{
		cout << "\n\nCongratulations! You have made a new high score!" << endl;
	}
	else
	{
		cout << "\n\nSorry you did not achieve a high score..." << endl;
	}
	ofstream ofHighScores("highscores.txt", ios::in); //Stores the new high scores in the txt file
	while (ofHighScores.is_open())
	{
		for (int x = 0; x < 10; x++)
		{
			ofHighScores << left << setw(6) << scores[x][0] << setw(13) << scores[x][1] << setw(9) << numberscores[x][0] << setw(4) << numberscores[x][1] << endl;
		}
		ofHighScores.close();
	}

	cout << endl;
	cout << "Place || Name       || High Score || Snake Length" << endl;
	cout << "_________________________________________________" << endl;
	displayHighScores();
	system("pause");
	system("cls");
	menukey = NULL;
}
void scoreIntoArray(){ //Takes top 10 scores in highscores.txt and stores in array.
	ifstream ifHighScores("highscores.txt", ios::in);
	if (ifHighScores.is_open())
	{
		for (int x = 0; x < 10; x++)
		{
			ifHighScores >> scores[x][0] >> scores[x][1] >> numberscores[x][0] >> numberscores[x][1];
		}
	}
	ifHighScores.close();
}
void displayHighScores(){
	for (int x = 0; x < 10; x++)
	{
		cout << left << setw(6) << scores[x][0] << "|| " << setw(11) << scores[x][1] << "|| " << setw(11) << numberscores[x][0] << "|| " << numberscores[x][1];
		cout << endl;
	}
}
void sortHighScores(){//Sorts the new scores by snake length
	for (int x = 0; x < 11; x++)
	{
		for (int y = 0; y < 10; y++)
		{
			if (numberscores[x][1] < numberscores[x + 1][1])
			{
				temp = scores[x + 1][1]; // switch names
				scores[x + 1][1] = scores[x][1];
				scores[x][1] = temp;

				intemp = numberscores[x + 1][0]; // switch scores
				numberscores[x + 1][0] = numberscores[x][0];
				numberscores[x][0] = intemp;

				intemp = numberscores[x + 1][1]; // switch snake lengths 
				numberscores[x + 1][1] = numberscores[x][1];
				numberscores[x][1] = intemp;
			}
		}
	}
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

//Powerups
void powerupMenu()
{
	Sleep(2000);
	menukey == NULL;
	system("cls");
	while (true)
	{
		menukey = NULL;
		Sleep(100);
		clearScreen();
		cout << "Powerup Points available: " << intStats[2] << endl << endl << "Add/Subtract points using A and D. \nUse W and S to move up and down. ENTER to finalize and exit\n\n\n Caution!! Stay away from tail when upgrading it!" << endl << endl << endl << endl;

		if (_kbhit())
		{
			menukey = _getch();
		}

		for (int i = 0; i < 2; i++)
		{
			if (statselected == i)
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 3);
				cout << left << setw(35) << gameStats[i] << right << setw(10) << intStats[i] << endl;
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
			}
			else
			{
				cout << left << setw(35) << gameStats[i] << right << setw(10) << intStats[i] << endl;
			}
		}

		if (menukey == 'w')
		{
			statselected -= 1;
			if (statselected == -1)
			{
				statselected = 1;
			}
			menukey = NULL;
		}
		else if (menukey == 's')
		{
			statselected += 1;
			if (statselected == 2)
			{
				statselected = 0;
			}
			menukey = NULL;
		}
		else if (menukey == 'd')
		{
			if (statselected == 0 && intStats[0] < 3 && intStats[2] > 0) //If increasing length gain AND current length gain is not max(3) AND you have points to spend then..
			{
				intStats[0] += 1;//Add one to length gain
				intStats[2] -= 1;//Take one out of powerup points
			}
			else if (statselected == 1 && intStats[1] < 1000 && intStats[2] > 0) //If increasing score gain AND current gain is not max(1000) AND you have points to spend then..
			{
				intStats[1] += 100;//Add 100 to score gain
				intStats[2] -= 1;
			}
			menukey = NULL;
		}
		else if (menukey == 'a')
		{
			if (statselected == 0) //If decreasing length gain then
			{
				intStats[0] -= 1;//Decrease gain
				intStats[2] += 1;//Increase powerup points
				if (intStats[0] == 0)//Length gain cannot be 0
				{
					intStats[0] += 1;
					intStats[2] -= 1;
				}
			}
			else if (statselected == 1)
			{
				intStats[1] -= 100;
				intStats[2] += 1;
				if (intStats[1] == 0)
				{
					intStats[1] += 100;
					intStats[2] -= 1;
				}
			}
			menukey = NULL;
		}
		else if (menukey == VK_RETURN)
		{
			system("pause");
			return;
		}
	}
}

//Menu Functions
void settings(){
	menukey = NULL;
	while (true)
	{
		Sleep(100);
		clearScreen();
		cout << "Settings\nUse W S to move up down and A D to move left right. ENTER to exit\n~~~Bigger size may slow performance~~~\n\n";

		cout << "Field Size:            ";
		for (int i = 0; i < 3; i++) // Prints the menu with highlighted option
		{
			if (fieldsize == i)
			{
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 3);
				cout << size[i] << "     ";
				SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
			}
			else
			{
				cout << size[i] << "     ";
			}
		}
		cout << endl << endl;


		if (_kbhit())//Grabs key
		{
			menukey = _getch();
		}

		if (menukey == 'a')
		{
			fieldsize -= 1;
			if (fieldsize == -1)
			{
				fieldsize = 2;
			}
			menukey = NULL;
		}
		else if (menukey == 'd')
		{
			fieldsize += 1;
			if (fieldsize == 3)
			{
				fieldsize = 0;
			}
			menukey = NULL;
		}
		else if (menukey == VK_RETURN)
		{
			return;
		}
		if (fieldsize == 0)
		{
			*r = 15;
			*c = 30;
			lag = 40;
		}
		else if (fieldsize == 1)
		{
			*r = 20;
			*c = 60;
			lag = 20;
		}
		else if (fieldsize == 2)
		{
			*r = 24;
			*c = 69;
			lag = 00;
		}
	}
}
Topic archived. No new replies allowed.