Space Shooter game

Hello.
I need some help with a game I am making. Its called space shooter. Basically aliens move downwards and our space ship moves vertically in the last row. We can shoot a projectile using space key.
I am using system cls and the screen just glitches too much. I cant use anything that i havent been taught in class. This is my first semester's semester project btw. I havent read classes (can use struct tho), i have read arrays, functions, file handling and thats about it.
Any tips other than about the question above are also highly appreciated.
Thank you!
Last edited on
have you been taught anything to let you move the cursor to any position? That saves clearing the screen flashes and scrolling.
you need a way to do that, but we don't know what you are allowed. Nothing you describe will help.
You could try this to clear the screen:
1
2
3
4
5
void VT100::clear_screen()
{
    cout << ESC << "2J";
    cout << ESC << "3J";
}

our space ship moves vertically in the last row

Don't you mean it moves horizontally back and forth across the bottom row?

@Barry087

Here's a small program I just threw together that lets you control a ship with the up and down arrow keys. Use space bar to fire a missile. I didn't make it so that the ship could still move while the missile is on screen but ..

Anyway, here it is..
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
// Move Ship.cpp : main project file.

#include <iostream>
#include <string>
#include <conio.h>
#include <Windows.h>

using namespace std;

#define UP 72
#define DOWN 80
#define SPACE 32
#define ESC 27

void Move_Ship(int move);
void gotoXY(int x, int y);
void gotoXY(int x, int y, string text);
void WaitKey();

HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
COORD CursorPosition;

int main()
{
	int move = 16;

	gotoXY(23,35, "Use the UP\\DOWN arrow keys to move the ship. Space bar to fire. ESC to quit");
	Move_Ship(move);
}

void Move_Ship(int move)
{
	int ch, x;

	gotoXY(116, move, "<");
	do
	{
		ch = _getch();
		
		switch(ch) //Replace zero space with space to the left right up or down.
		{

		case UP:
			if(move - 1 > 0) // To keep it from going off the top
			{
				gotoXY(116, move, " ");
				move--;
				gotoXY(116, move, "<");
			}
			break;
		case DOWN:
			if(move + 1 < 35) // Same except off the bottom
			{
				gotoXY(116, move, " ");
				move++;
				gotoXY(116, move, "<");
			}
			break;
		case SPACE: // Fire the missile
			for(x=115;x > 1;x--)
			{
				gotoXY(x,move,"=");
				Sleep(50);
				gotoXY(x,move," ");
				Sleep(50);
			}
			break;
		}
	}while(ch!=ESC); // Quits the program
}

void gotoXY(int x, int y) // Positions the cursor
{
	CursorPosition.X = x;
	CursorPosition.Y = y;
	SetConsoleCursorPosition(console, CursorPosition);
}

void gotoXY(int x, int y, string text) // Same but lets you print text at the location 
{
	CursorPosition.X = x;
	CursorPosition.Y = y;
	SetConsoleCursorPosition(console, CursorPosition);
	cout << text;
}
Last edited on
I don't think they gonna allow him to use those tools, though. OP, the above is using language extensions from a 3rd party library to do what I said (position the cursor and write where you need to without flash). Its very nice, if you can use it. Also consider beating professors who restrict you from using anything at your disposal with a foam pool noodle until they comply.
@Jonnin

using language extensions from a 3rd party library


No they are not. The commands are in Windows.h library. I wrote the gotoXY() functions to make it easier to issue the commands. I'm using MS Express 2012
No they are not. The commands are in Windows.h library

... ^^^ as much as M$ wishes otherwise, they are not in charge of C++. They are a third party, in terms of C++, and windows.h is not a c++ standard header, its a tool provided by microsoft in visual studio.
:)
To be a 'first' party, it would be like <iostream> and available in g++ ...
you may be able to argue second party. I forget what that actually means, Ill go look it up.. (Edit, nope, that apparently would mean microsoft worked for one of us!)
Last edited on
@whitenite1
Thought it might be good practice for me too, so I added an option for horizontal spaceship control. I also looked up how to make the blinking cursor disappear & at first it did not work & now seems to work...maybe something to do with cin>>, see if it works for you.

I think Barry is trying to make a Space Invaders ASCII clone & ship needs horizontal control.

ASCII 32 is space & 27 is escape, but are the cursor keys something that windows sends through the console, are these the virtual keys I read briefly about? Is there a complete listing of these keyboard codes?

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
// Move Ship.cpp : main project file. V2
// Cursor position can be represented as (x,y) and the origin is (0,0) at the top-left.

#include <iostream>
#include <string>
#include <conio.h>
#include <Windows.h>

using namespace std;

#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define SPACE 32
#define ESC 27

void Move_Ship(int move);
void Move_Ship_Horizontally(int moveX);	//Moves ship horizontally instead of vertically
void gotoXY(int x, int y);
void gotoXY(int x, int y, string text);
void WaitKey();
void ShowConsoleCursor(bool showFlag);	//Makes the cursor invisible for smoother graphics

HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
COORD CursorPosition;

int main()
{
	cout << "Enter <1> to control ship vertically or\n";
	cout << "Enter <2> to control ship horizontally.\n";
	char userInput;
	cin >> userInput;
	
	gotoXY(0,0,"                                        ");	//Clear previous text
	gotoXY(0,1,"                                        ");	//Clear previous text
	gotoXY(0,2," ");											//Clear previous text
	
	if (userInput == '1')
	{
		int move = 16;
		gotoXY(23,35, "Use the UP\\DOWN arrow keys to move the ship. Space bar to fire. ESC to quit");
		ShowConsoleCursor(false);
		Move_Ship(move);
	}
	else
	{
		int moveX = 35;
		gotoXY(23,35, "Use the Left\\Right arrow keys to move the ship. Space bar to fire. ESC to quit");
		ShowConsoleCursor(false);
		Move_Ship_Horizontally(moveX);
	}
}

void Move_Ship(int move)
{
	int ch, x;

	gotoXY(116, move, "<");
	do
	{
		ch = _getch();
		
		switch(ch) //Replace zero space with space to the left right up or down.
		{

		case UP:
			if(move - 1 > 0) // To keep it from going off the top
			{
				gotoXY(116, move, " ");
				move--;
				gotoXY(116, move, "<");
			}
			break;
		case DOWN:
			if(move + 1 < 35) // Same except off the bottom
			{
				gotoXY(116, move, " ");
				move++;
				gotoXY(116, move, "<");
			}
			break;
		case SPACE: // Fire the missile
			for(x=115;x > 1;x--)
			{
				gotoXY(x,move,"=");
				Sleep(5);
				gotoXY(x,move," ");
				Sleep(5);
			}
			break;
		}
	}while(ch!=ESC); // Quits the program
}

void Move_Ship_Horizontally(int moveX)
{
	
	const int MAX_X = 70;
	int ch, y = 40;
	gotoXY(moveX, y, "^");
	
	do
	{
		ch = _getch();
		
		switch(ch) //Replace zero space with space to the left right up or down.
		{

		case LEFT:
			if( moveX - 1 >= 0) // To keep it from going off the left
			{
				gotoXY(moveX, y, " ");
				--moveX;
				gotoXY(moveX, y, "^");
			}
			break;
			
		case RIGHT:
			if( moveX + 1 <  MAX_X) // To keep it from going off the right
			{
				gotoXY(moveX, y, " ");
				++moveX;
				gotoXY(moveX, y, "^");
			}
			break;
			
		case SPACE: // Fire the missile
			int xBullet = moveX;
			
			for( int i = y - 1; i > -1; --i)		
			{
				gotoXY(xBullet, i, "*");
				Sleep(100);
				gotoXY(xBullet, i, " ");
			}
			break;
		}
	}while(ch!=ESC); // Quits the program
}

void gotoXY(int x, int y) // Positions the cursor
{
	CursorPosition.X = x;
	CursorPosition.Y = y;
	SetConsoleCursorPosition(console, CursorPosition);
}

void gotoXY(int x, int y, string text) // Same but lets you print text at the location 
{
	CursorPosition.X = x;
	CursorPosition.Y = y;
	SetConsoleCursorPosition(console, CursorPosition);
	cout << text;
}

void ShowConsoleCursor(bool showFlag)
{
    CONSOLE_CURSOR_INFO     cursorInfo;

    GetConsoleCursorInfo(console, &cursorInfo);
    cursorInfo.bVisible = showFlag; // set cursor visibility on/off
    SetConsoleCursorInfo(console, &cursorInfo);
}
Last edited on
Found this on stackoverflow, which gives keyboard presses from console

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
#include<conio.h>
using namespace std;
int main()
{
    int KB_code=0;
    while(1)
    {

     if (kbhit())
      {
            KB_code = getch();
            cout<<"KB_code = "<<KB_code<<"\n";
}
    }
return(0);
}
Note for VS you need _getch()

Also for some keys (function, page, home etc) you get 2 chars. If the first code is 0 or 0xe0 then there is a second char.

You may find this of some use:

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
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <iomanip>

// Type defs for virtual keys
#define VIRT_KEY	1		// 0x1
#define VIRT_CTRL	2		// 0x2
#define VIRT_SHIFT	4		// 0x4
#define VIRT_ALT	8		// 0x8
#define VIRT_CAPS	16		// 0x10
#define VIRT_NUM	32		// 0x20
#define VIRT_SCROLL	64		// 0x40

#define VK_PAGEUP	VK_PRIOR
#define VK_PAGEDOWN	VK_NEXT

// Keyboard conversion structure for conio getch()
 struct KEYCON {
	BYTE	type {};
	char	ch {};
};

// Conversion array for conio getch to VK_ defs - 0xe0
const KEYCON keye0[]	{{VIRT_KEY, VK_HOME},						// 0x47
							{VIRT_KEY, VK_UP},						// 0x48
							{VIRT_KEY, VK_PAGEUP},					// 0x49
							{0, 0},									// 0x4a
							{VIRT_KEY, VK_LEFT},					// 0x4b
							{0, 0},									// 0x4c
							{VIRT_KEY, VK_RIGHT},					// 0x4d
							{0, 0},									// 0x4e
							{VIRT_KEY, VK_END},						// 0x4f
							{VIRT_KEY, VK_DOWN},					// 0x50
							{VIRT_KEY, VK_PAGEDOWN},				// 0x51
							{VIRT_KEY, VK_INSERT},					// 0x52
							{VIRT_KEY, VK_DELETE}};					// 0x53

// Conversion array for conio getch to VK_ defs - 0xe0c
const KEYCON keye0c[]	{{VIRT_KEY | VIRT_CTRL, VK_LEFT},			// 0x73
							{VIRT_KEY | VIRT_CTRL, VK_RIGHT},		// 0x74
							{VIRT_KEY | VIRT_CTRL, VK_END},			// 0x75
							{VIRT_KEY | VIRT_CTRL, VK_PAGEDOWN},	// 0x76
							{VIRT_KEY | VIRT_CTRL, VK_HOME},		// 0x77
							{0, 0},									// 0x78
							{0, 0},									// 0x79
							{0, 0},									// 0x7a
							{0, 0},									// 0x7b
							{0, 0},									// 0x7c
							{0, 0},									// 0x7d
							{0, 0},									// 0x7e
							{0, 0},									// 0x7f
							{0, 0},									// 0x80
							{0, 0},									// 0x81
							{0, 0},									// 0x82
							{0, 0},									// 0x83
							{0, 0},									// 0x84
							{VIRT_KEY, VK_F11},						// 0x85
							{VIRT_KEY | VIRT_CTRL, VK_PAGEUP},		// 0x86	Also VK_F12
							{0, 0},									// 0x87
							{0, 0},									// 0x88
							{VIRT_KEY | VIRT_CTRL, VK_F11},			// 0x89
							{0, 0},									// 0x8a
							{0, 0},									// 0x8b
							{0, 0},									// 0x8c
							{VIRT_KEY | VIRT_CTRL, VK_UP},			// 0x8d
							{0, 0},									// 0x8e
							{0, 0},									// 0x8f
							{0, 0},									// 0x90
							{VIRT_KEY | VIRT_CTRL, VK_DOWN},		// 0x91
							{VIRT_KEY | VIRT_CTRL, VK_INSERT},		// 0x92
							{VIRT_KEY | VIRT_CTRL, VK_DELETE}};		// 0x93

// Conversion array for conio getch to VK_ defs - 0x0a
const KEYCON key0a[]   {{VIRT_KEY | VIRT_ALT, VK_HOME},				// 0x90
							{0, 0},									// 0x91
							{0, 0},									// 0x92
							{0, 0},									// 0x93
							{0, 0},									// 0x94
							{0, 0},									// 0x95
							{0, 0},									// 0x96
							{0, 0},									// 0x97
							{VIRT_KEY | VIRT_ALT, VK_UP},			// 0x98
							{VIRT_KEY | VIRT_ALT, VK_PAGEUP},		// 0x99
							{0, 0},									// 0x9a
							{VIRT_KEY | VIRT_ALT, VK_LEFT},			// 0x9b
							{0, 0},									// 0x9c
							{0, 0},									// 0x9d
							{0, 0},									// 0x9e
							{VIRT_KEY | VIRT_ALT, VK_END},			// 0x9f
							{VIRT_KEY | VIRT_ALT, VK_DOWN},			// 0xa0
							{VIRT_KEY | VIRT_ALT, VK_PAGEDOWN},		// 0xa1
							{VIRT_KEY | VIRT_ALT, VK_INSERT},		// 0xa2
							{VIRT_KEY | VIRT_ALT, VK_DELETE}};		// 0xa3

// Conversion array for conio getch to VK_ defs - 0x0f
const KEYCON key0f[]    {{VIRT_KEY, VK_F1},							// 0x3b
							{VIRT_KEY, VK_F2},						// 0x3c
							{VIRT_KEY, VK_F3},						// 0x3d
							{VIRT_KEY, VK_F4},						// 0x3e
							{VIRT_KEY, VK_F5},						// 0x3f
							{VIRT_KEY, VK_F6},						// 0x40
							{VIRT_KEY, VK_F7},						// 0x41
							{VIRT_KEY, VK_F8},						// 0x42
							{VIRT_KEY, VK_F9},						// 0x43
							{VIRT_KEY, VK_F10}};					// 0x44

// Conversion array for conio getch to VK_ defs - 0x0c
const KEYCON key0c[]    {{VIRT_KEY | VIRT_CTRL, VK_F1},				// 0x5e
							{VIRT_KEY | VIRT_CTRL, VK_F2},			// 0x5f
							{VIRT_KEY | VIRT_CTRL, VK_F3},			// 0x60
							{VIRT_KEY | VIRT_CTRL, VK_F4},			// 0x61
							{VIRT_KEY | VIRT_CTRL, VK_F5},			// 0x62
							{VIRT_KEY | VIRT_CTRL, VK_F6},			// 0x63
							{VIRT_KEY | VIRT_CTRL, VK_F7},			// 0x64
							{VIRT_KEY | VIRT_CTRL, VK_F8},			// 0x65
							{VIRT_KEY | VIRT_CTRL, VK_F9},			// 0x66
							{VIRT_KEY | VIRT_CTRL, VK_F10},			// 0x67
							{VIRT_KEY | VIRT_ALT, VK_F1},			// 0x68
							{VIRT_KEY | VIRT_ALT, VK_F2},			// 0x69
							{VIRT_KEY | VIRT_ALT, VK_F3},			// 0x6a
							{VIRT_KEY | VIRT_ALT, VK_F4},			// 0x6b
							{VIRT_KEY | VIRT_ALT, VK_F5},			// 0x6c
							{VIRT_KEY | VIRT_ALT, VK_F6},			// 0x6d
							{VIRT_KEY | VIRT_ALT, VK_F7},			// 0x6e
							{VIRT_KEY | VIRT_ALT, VK_F8},			// 0x6f
							{VIRT_KEY | VIRT_ALT, VK_F9},			// 0x70
							{VIRT_KEY | VIRT_ALT, VK_F10}};			// 0x71

void KeyConv(BYTE& ch, BYTE& type) {
	type = 0;

	if (ch && (ch != 0xe0))
		return;

	// Got special key so get second char
	const auto ch1 = (char)::_getch();

	// char 0xe0
	if (ch)
		if ((ch1 >= 0x47) && (ch1 <= 0x53)) {
			type = keye0[ch1 - 0x47].type;
			ch = keye0[ch1 - 0x47].ch;
		} else
			if ((ch1 >= 0x73) && (ch1 <= 0x93)) {
				type = keye0c[ch1 - 0x73].type;
				ch = keye0c[ch1 - 0x73].ch;
			} else
				ch = 0;
	else
		// char 0
		if ((ch1 >= 0x90) && (ch1 <= 0xa3)) {
			type = key0a[ch1 - 0x90].type;
			ch = key0a[ch1 - 0x90].ch;
		} else
			if ((ch1 >= 0x3b) && (ch1 <= 0x44)) {
				type = key0f[ch1 - 0x3b].type;
				ch = key0f[ch1 - 0x3b].ch;
			} else
				if ((ch1 >= 0x5e) && (ch1 <= 0x71)) {
					type = key0c[ch1 - 0x5e].type;
					ch = key0c[ch1 - 0x5e].ch;
				}

			return;
}

int main() {
	BYTE typ {};
	BYTE ch {(BYTE)_getch()};

	KeyConv(ch, typ);

	std::cout << (int)ch << "  " << std::hex << (int)typ << '\n';
}

Yea, I did see sometimes it would send two sets. I will keep a copy of this, thanks!
@SubZeroWins

I don't think they are the virtual keys being used in the program. Just using the value of the key being pressed. As to the blinking cursor, here is a program that shows how to turn it off and back 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
#include <iostream>
#include <windows.h>

using std::cout;
using std::endl;

void setcursor(bool visible, DWORD size);

int main()
{
	cout << "Cursor on for 10 seconds..." << std::endl;
	cout << "Hello World ";
	for (int x = 0; x<10; x++)
		Sleep(1000);

	cout << endl;

	cout << "Cursor OFF for 10 seconds..." << endl;
	cout << "Hello World ";

	setcursor(0, 0);
	for (int x = 0; x<10; x++)
		Sleep(1000);

	cout << std::endl;
	cout << "Cursor back on..." << endl;
	setcursor(1, 20);
	cout << "Hello World " << endl;

	return 0;
}

void setcursor(bool visible, DWORD size)  // set bool visible to 0 for invisible, // bool visible = 1 for  visible
{
	HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
	if (size == 0)
	{
		size = 20;	// default cursor size Changing to numbers from 1 to 20, decreases cursor width
	}
	CONSOLE_CURSOR_INFO lpCursor;
	lpCursor.bVisible = visible;
	lpCursor.dwSize = size;
	SetConsoleCursorInfo(console, &lpCursor);
}
Topic archived. No new replies allowed.