-1

So I want to display an object with certain coordinates on the screen and make it able to move. If for example "u" is pressed it goes up and etc. So I tried using variables X and Y (initialized to 0) and after a "clear screen" deploying the object with a for loop. So check this out:

#include <iostream>
#include <conio.h>
#include <cstdlib>
#include <vector>
#include <iomanip>
using namespace std;
char input;
char player = 1;
char keyup = 0x48, keydown = 0x50, keyright = 0x4d, keyleft = 0x4b;
int x = 0, y = 0;
void position()
{
    for (int start = 0; start <= y; start++)
    {
        cout << "\n";
    }
    for (int start = 0; start <= x; start++)
    {
        cout << " ";
    }
    cout << player;
}
void moveup()
{
    x - 1;
    system("cls");
    position();
}
void movedown()
{
    y + 1;
    system("cls");
    position();
}
void moveright()
{
    x + 1;
    system("cls");
    position();
}
void moveleft()
{
    y - 1;
    system("cls");
    position();
}
int main()
{
    while (1)
    {
        position();
        cin >> input;
        if (input == keyup) moveup();
        if (input == keydown) movedown();
        if (input == keyright) moveright();
        if (input == keyleft) moveleft();
        system("cls");
    }
}

So when I run it it just shows me the cube for ASCII key = 1; And no matter what I press it just blinks showing me the 'player' on the same position. Can you guys tell me what is the PROBLEM?

Mr.Stark135
  • 1
  • 1
  • 6

2 Answers2

2

At first, I recomment using character literals instead of numerical values:

char const keyup = 'u';
//    ^ they are constants, aren't they???

0 is not a printable character, so using it as symbol won't print anything on the screen... You might use e. g. '+' instead.

Then you are repeating pretty much code within your functions. What you actually need is just one printing function; something like:

void update()
{
    system("cls");
    for(int i = 0; i < y; ++i)
        std::cout << '\n'; // navigate to appropriate line

    for(int i = 0; i < x; ++i)
        std::cout << ' '; // navigate to column

    std::cout << symbol << std::endl; // endl flashes buffer, too
}

You can use this to print the the symbol to current position (x/y). On input you just need to modify the coordinates (I personally recommend a switch statement instead of the if/else chain):

std::cin >> input;
switch(input)
{
case keyup: // NEEDS to be a constant to be used that way!
    --y;
    break;
case keydown:
    ++y;
    break;
case keyleft:
    --x;
    break;
case keyright:
    ++x;
    break;
default: // catch invalid user input
    // if you have, appropriate error handling – or just ignore
    break;      
}

An empty default could be left out – it's a good habit, though, always to catch the invalid cases.

Finally: The second clearing of the screen (after your if/else chain) would empty the screen again before user might have seen anything. Just leave it out. All combined:

for(;;)
{
    update(); // first screen update and returning here in every loop
    std::cin >> input;
    switch(input)
    {
    // ...
    case ExitKey: // recommend to add it!
        // the only disadvantage of switch: cannot use 'break' to exit loop!
        goto LOOP_END;
    default:
        break;
    }
}
LOOP_END:
// clean up application
return 0; // exit main...

One thing I yet omitted above, but very important: range checks! Before incrementing or decrementing one of the coordinates, you need to check if you can at all:

if(x > 0)
    --x;

Or a variant I personally like:

y += y < SCREEN_HEIGHT; // needs to be defined appropriately...

About screen size: this might be of interest...

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • Thanks man I will try that. The thing about checking the values of the coordinates: I did not see that. And the ` y += y < SCREEN_HEIGHT; // needs to be defined appropriately.. ` I do not understand so I would rather use ` if(x > 0) --x; ` – Mr.Stark135 May 25 '19 at 14:47
  • Use whatever appears most appropriate for you... Just explaining: `x -= x > 0`: the result of comparison is `bool`, conversion to `int` is guaranteed to yield 0 (false) or 1 (true). So it is just shorter for `int offset = x > 0; /* either 1 or 0 */; x -= offset;`. – Aconcagua May 27 '19 at 09:01
  • Hey what about the screen height "that might be of interest". Tell me something more if you can, I am patient – Mr.Stark135 May 27 '19 at 12:25
  • @Mr.Stark135 You need to know the number of columns within a line and how many lines there are. The easiest way would be simply defining some meaningful constants for. Problem about: they do not adjust to currently selected console size. So you end up in either not using the full console window (probably yet acceptable) or using more than there is available (breaking your game – assuming 80 columns and being at 0/79; moving right once more: 0/80; but as no column left, line wraps/breaks, and output will look like 1/0). Link provided shows how to determine size dynamically... – Aconcagua May 27 '19 at 20:50
0

So the improved code would look like this:

#include <iostream>
#include <conio.h>
#include <cstdlib>
#include <vector>
#include <iomanip>
using namespace std;
char input;
char player = 1;
const char keyup = 'u', keydown = 'd', keyright = 'r', keyleft = 'l', Exitkey = 'k';
int x = 0, y = 0;
void space()
{
    for (int start = 0; start < 7; start++)
    {
        cout << "\n";
    }
}
void update()
{
    system("cls");
    for (int i = 0; i < y; ++i)
    cout << '\n'; 

    for (int i = 0; i < x; ++i)
    cout << ' ';
    cout << player << endl;
}
void inputfunc()
{
    cin >> input; 
    switch (input)
    {
    case keyup:
        if (y = 0)
        {
            y = 0;
        }
        else --y;
        goto endloop;
    case keydown:
        ++y;
        goto endloop;
    case keyleft:
        if (x = 0)
        {
            x = 0;
        }
        else --x;
        goto endloop;
    case keyright:
        ++x;
        goto endloop;
    case Exitkey:
        goto endloop;
    default:
        break;
    }
endloop:;
}
int main()
{
    for (;;)
    {
        update();
        space();
        inputfunc();
    }
}

And one more thing: I do not know how to make it automatically after entering ONE character go on. I need to enter as many characters as I want and then press ENTER to deploy the player.How can I do that Scheff?

Mr.Stark135
  • 1
  • 1
  • 6
  • You are yet missing the range checks. Try a sequence like `uuuddd` – you'll notice that you stay on top, but the subsequent downs will be ignored. Worse: typing `r` too often will result in the line wrapping around. For `space` function, I recommend not adding static space (that will result in the input line moving around), but to make up a fix distance *including* the output: `for(int i = x; i < MAX_HEIGHT; ++i) std:.cout << '\n'`. Having this solved, you might add a little text for the user, something like 'Please enter next command (u, d, l, r, e, h = help)'. – Aconcagua May 27 '19 at 08:55
  • Side-note: about [using namespace std](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice)... – Aconcagua May 27 '19 at 08:56
  • Yeah but I just can not write std:: all the time and the problems that could happen are not bothering me – Mr.Stark135 May 27 '19 at 12:30
  • added range checks. But please can you tell me how to make the program to automatically go further after entering one character? – Mr.Stark135 May 27 '19 at 12:35
  • You only added range checks at one half of where necessary... And what exactly do you mean by "go further"? Or the other way round, what exactly does not occur you expect to do so? – Aconcagua May 27 '19 at 20:52
  • Your range checks won't work at all anyway: `if(x = 0)` will assign 0 to `x` and evaluate `x` afterwards, but as 0, the else branch will be taken, so you'll increment `x` once more. You could have done the whole matter much simpler: `x = 1;`... Suppose you intended to compare (`if(x == 0)`) – but then it is pretty meaningless to re-assign the same value you already know the variable has... So omit this branch entirely and negate the condition: `if(x != 0) --x;` – Aconcagua May 27 '19 at 20:58
  • You won't be able to exit your main loop; have a close look at my code: the label marking the end of the loop is placed directly after the loop, and my goto (I just have *one* of those!) is not inside a separate function! Actually, you could have achieved the same with ordinary breaks – and still would not exit the loop. You might try something different: have a global variable `bool isRunning = true`, replace `for(;;)` with `while(isRunning)` and on user typing the `ExitKey` set `isRunning = false`. If doing so, please drop the `goto`s; if there are better alternatives (`break`!) prefer them! – Aconcagua May 27 '19 at 21:03
  • Do you happen to mean by "going further automatically" not having to type ENTER-key after every character? If so, you should have a look at [`getch` function](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=vs-2019) from header ``; be aware, though, that this is a Windows/DOS header, it is not part of the standard library or POSIX (so not usable on e. g. linux, MacOS, BSD, ...). – Aconcagua May 27 '19 at 21:14
  • Side note: It s not a good idea to accept an answer (yours this time) that (obviously!) doesn't work. I'm absolutely fine with not accepting my answer if you don't like it, but then it would be better just not to accept any answer at all... – Aconcagua May 27 '19 at 21:20