Character movement

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:

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
unsigned int gamespeed = 100;
unsigned int 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
Last edited on
First of all, http://cplusplus.com/articles/G13hAqkS/

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//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;
Thanks a lot hamsterman :) Now I get it :D

It's still not perfect though,

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.
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
unsigned int gamespeed = 100;
unsigned int 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;}
            else if ( 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
Last edited on
Ok, haha, I solved this myself :)

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):
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
unsigned int gamespeed = 100;
unsigned int 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;}
            if (GetAsyncKeyState(VK_DOWN) != 0)  {new_y += 1;}
            if (GetAsyncKeyState(VK_LEFT) != 0)  {new_x -= 1;}
            if (GetAsyncKeyState(VK_RIGHT) != 0) {new_x += 1;}

                switch ((*Map)[new_y][new_x])
                {
                    case ' ': //Moves the player
                    (*Map)[current_y][current_x] = ' ';
                    current_x = new_x; current_y = new_y;
                    (*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] = ' ';
                    current_x = new_x; current_y = new_y;
                    (*Map)[new_y][new_x] = '@';
                    break;

                    case '+': //Potion - same as trap but adds 20 health instead
                    if ( HP <= MaxHP -20) {HP += 20;}
                    else if ( HP >= MaxHP -20) {HP = MaxHP;}
                    (*Map)[current_y][current_x] = ' ';
                    current_x = new_x; current_y = new_y;
                    (*Map)[new_y][new_x] = '@';
                    break;

                    case '!': //Exit - moves the player to the next map
                    stage += 1; break;
                }
        }
    }
    }
Sleep(gamespeed); //Pauses slightly to reduce flicker
}

Last edited on
Topic archived. No new replies allowed.