I know this question has been asked many times in different ways.
How can I move a character around a 2D map?
After some research and a bunch of work I made a function for movement:
unsignedint gamespeed = 100;
unsignedint stage = 1;
void controls()
{
for (int y = 0; y < 40; y++) {
for (int x = 0; x < 40; x++) {
switch ((*Map)[y][x]) {
case'#': //Uses ASCII characters instead of '#' for map borders
(*Map)[y][x] = 178; break;
case'@':
if (GetAsyncKeyState(VK_UP) != 0) //If user presses the UP arrow
{
int y2 = (y -1);
switch ((*Map)[y2][x])
{
case' ': //Moves the player
(*Map)[y][x] = ' ';
y -= 1;
(*Map)[y2][x] = '@';
break;
case'*': //Trap - takes away 10 health and moves the player to it's location
HP -= 10;
(*Map)[y][x] = ' ';
y -= 1;
(*Map)[y2][x] = '@';
break;
case'+': //Potion - same as trap but adds 20 health instead
HP += 20;
(*Map)[y][x] = ' ';
y -= 1;
(*Map)[y2][x] = '@';
break;
case'!': //Exit - moves the player to the next map
stage += 1; break;
}
}
if (GetAsyncKeyState(VK_DOWN) != 0) //If user presses DOWN arrow
{
int y2 = (y +1);
switch ((*Map)[y2][x])
{
case' ':
(*Map)[y][x] = ' ';
y += 1;
(*Map)[y2][x] = '@';
break;
case'*':
HP -= 10;
(*Map)[y][x] = ' ';
y += 1;
(*Map)[y2][x] = '@';
break;
case'+':
HP += 20;
(*Map)[y][x] = ' ';
y += 1;
(*Map)[y2][x] = '@';
break;
case'!':
stage += 1; break;
}
}
if (GetAsyncKeyState(VK_RIGHT) != 0) //If user presses RIGHT arrow
{
int x2 = (x +1);
switch ((*Map)[y][x2])
{
case' ':
(*Map)[y][x] = ' ';
x += 1;
(*Map)[y][x2] = '@';
break;
case'*':
HP -= 10;
(*Map)[y][x] = ' ';
x += 1;
(*Map)[y][x2] = '@';
break;
case'+':
HP += 20;
(*Map)[y][x] = ' ';
x += 1;
(*Map)[y][x2] = '@';
break;
case'!':
stage += 1; break;
}
}
if (GetAsyncKeyState(VK_LEFT) != 0) //If user presses LEFT arrow
{
int x2 = (x -1);
switch ((*Map)[y][x2])
{
case' ':
(*Map)[y][x] = ' ';
x -= 1;
(*Map)[y][x2] = '@';
break;
case'*':
HP -= 10;
(*Map)[y][x] = ' ';
x -= 1;
(*Map)[y][x2] = '@';
break;
case'+':
HP += 20;
(*Map)[y][x] = ' ';
x -= 1;
(*Map)[y][x2] = '@';
break;
case'!':
stage += 1; break;
}
}
break;
}
}
}
Sleep(gamespeed); //Pauses slightly to reduce flicker
}
Maps are stored in a different .cpp file (I believe I don't have to post it, but I'm still new so please tell me if I should)
So this code works, but is complicated, ugly and evil (I have to make a pointer to the first map and change the pointer to the next map every time the user reaches the exit, without the pointer this code is, of course, incompatible).
How can I reduce this code to be less evil/ugly or at least smaller?
Also it would be nice if the user could move around with arrows as well as with WASD
That aside, I don't know why you're iterating over the whole map. Know where your player is (you should probably store that in some variables and not search the whole map every time, but whatever), know where he wants to be (by reading key states) and that is all the information you need to alter the map. You can then decide what to do in one place rather than four.
Thanks for your reply, I'll learn SFML.
I'm still interested in making that code better though,
So what you're saying is I should have int current_y; int current_x;
variables which are modified everytime the user makes a move, but in that code this is what y and x are, y2 and x2 are created to show the new map, then y or x is changed to match the coordinates, right?
Then I think I get your idea,
know where he wants to be (by reading key states) and that is all the information you need to alter the map. You can then decide what to do in one place rather than four.
but I'm not sure how to do it. I'd appreciate an example :)
Right, x, y, x2 and y2 are the things you need. The thing is that you can separate the peace of code where you find them from the peace of code where you update the map using them.
//say x, y are the coordinates of the player
//first compute x2, y2
int x2 = x, y2 = y;
if(GetAsyncKeyState(VK_DOWN) != 0) y2--;
if(...) y2++;
if ...
if ...
//then use them
switch ((*Map)[y2][x2])
{
case' ':
(*Map)[y][x] = ' ';
(*Map)[y2][x2] = '@';
break;
...
...
...
}
//finally update x, y
x = x2;
y = y2;
The code works, but pressing the arrow keys causes the player to jump around the map and if a key is held it will appear next to the first obstacle in that direction.
unsignedint gamespeed = 100;
unsignedint stage = 1;
int current_x , current_y, new_x , new_y;
void controls()
{
for (current_y = 0; current_y < 40; current_y++) {
for (current_x = 0; current_x < 40; current_x++) {
switch ((*Map)[current_y][current_x]) {
case'#': //Uses ASCII characters instead of '#' for map borders
(*Map)[current_y][current_x] = 178; break;
case'@':
new_x = current_x; new_y = current_y;
if (GetAsyncKeyState(VK_UP) != 0) {new_y -= 1; Sleep(gamespeed);}
if (GetAsyncKeyState(VK_DOWN) != 0) {new_y += 1; Sleep(gamespeed);}
if (GetAsyncKeyState(VK_LEFT) != 0) {new_x -= 1; Sleep(gamespeed);}
if (GetAsyncKeyState(VK_RIGHT) != 0) {new_x += 1; Sleep(gamespeed);}
//I added Sleep(gamespeed) which partially helps, but doesn't solve the problem
switch ((*Map)[new_y][new_x])
{
case' ': //Moves the player
(*Map)[current_y][current_x] = ' ';
(*Map)[new_y][new_x] = '@';
break;
case'*': //Trap - takes away 10 health and moves the player to it's location
if (HP > 10 ) { HP -= 10; }
//else (HP <= 10) //game over
(*Map)[current_y][current_x] = ' ';
(*Map)[new_y][new_x] = '@';
break;
case'+': //Potion - same as trap but adds 20 health instead
if ( HP <= MaxHP -20) {HP += 20;}
elseif ( HP >= MaxHP -20) {HP = MaxHP;}
(*Map)[current_y][current_x] = ' ';
(*Map)[new_y][new_x] = '@';
break;
case'!': //Exit - moves the player to the next map
stage += 1; break;
}
}
}
}
current_x = new_x; current_y = new_y;
Sleep(gamespeed); //Pauses slightly to reduce flicker
}
Also, I know you told me not to search the map for the player all of the time, but if I include enemies, I have to search the map for them, so why not search for the player as well, makes life easier :D
The problem was that the line current_x = new_x; current_y = new_y;
was at the end, but current_x and current_y have to be updated everytime the user makes a move - whatever that move is.
So here's the full fixed code (if anybody wants it in the future):