简体   繁体   中英

Movement of Object in a game in C++

So I am making a game for a school project. You might be familiar with this one. Its Arkanoid, or the game in which a ball is used to destroy bricks and is deflected on by a platform.

Currently I am stuck at a point. I have got an idea of how to move my platform using _getch(), but when I put in a ball it is also moving on a key press. I cant figure out on how to run it simultaneously with or without any key presses. Or if there is way to skip a key press every time until it is registered.

Here is my code so far. The movement of the ball is not complete it is just a prototype right now. Any help would be appreciated.

I am using a graphics library provided by my school but you can use the C++ graphics library.

#include <iostream>
#include "myconsole.h"
#include "mygraphics.h"
#include <conio.h>
#include <string>

using namespace std;

void rect() {
    COLORREF White = RGB(255, 255, 255);
    COLORREF Blue = RGB(135, 206, 235);
    //     x1   y    x2   y 
    myRect(400, 475, 550, 480, Blue, Blue);
    _getch();
}

void circle() {
    COLORREF Red = RGB(255, 0, 0);
    myEllipse(0, 50, 300, 350, Red, Red);
    _getch();
}

void moverect() {
    COLORREF White = RGB(255, 255, 255);
    COLORREF Blue = RGB(135, 206, 235);
    char _x;
    const char _r = 'd';
    const char _l = 'a';
    int x1 = 400; 
    int x2 = 550;
    int by1 = 455;
    int by2 = 475;
    int m = 48;
    
    while (1) {
        _x = _getch();
        system("cls");
        if (_x == _r) {
            if (x2 < 970) {
                x1 += 10;
                x2 += 10;
                for (int i = 0; i < 10; i++) {
                    myRect(x1++, 475, x2++, 480, Blue, Blue);
                }
            }
            else
                myRect(x1, 475, x2, 480, Blue, Blue);
        }
        else if (_x == _l) {
            if (x1 > 0) {
                x1 -= 10;
                x2 -= 10;
                for (int i = 0; i < 10; i++) {
                    myRect(x1--, 475, x2--, 480, Blue, Blue);

                }
            }
            else
                myRect(x1, 475, x2, 480, Blue, Blue);
        }
        myEllipse(463, by1 -= 10, 487, by2 -= 10, White, White);
    }
}

int main() {
    {
        moverect();
        return 0;
    }
}

Since you seem to be using Windows and Microsoft Visual C++ you could use _kbhit() , which will tell you if a key is pressed. Note that this is not standard C++.

This might look like:

if (_kbhit()) {
    _x = _getch();
}
else {
    _x = -1;
}

Alternatively, others mentioned threads, although John also noted that _getch() is also not standard C++, but I thought introducing some of the concepts of threads might be helpful.There are multiple ways to do it with threads but I will show what I consider to be the easiest way.

First we will create a class, this is to hide a variable that contains the latest character. We want it hidden so that when it is read from the main thread, the latest character is consumed (set to -1) so that when we next call the function, if another character is yet to be input the function will return -1.

Note that if two threads read and write from a variable at the same time, undefined behaviour occurs, for this reason we are going to use an atomic variable as it is defined when two threads try to access it at the same time. Alternatively mutexes exist, they are slower but allow for more complex types to be locked and unlocked so that only one thread may access them at a time.

class LatestChar {
public:
    /// initialize latest character to -1
    LatestChar() :
        latest_char{ -1 }
    {}
    /// returns latest character or -1 if there is no latest character
    int getLatestChar() {
        // get latest character
        int temp_latest_char{ latest_char };
        // consume latest character (so if this is called again, -1 is returned)
        latest_char = -1;
        // return latest character
        return temp_latest_char;
    }
private:
    /// equal to latest character or -1 when there is no character to get
    ///
    /// this is atomic because it might be read from the main thread at the same
    /// time it is written from the getch thread.
    std::atomic_int latest_char;
};

Next we need to create the thread that calls _getch() . This is a member variable and will be declared in the constuctor, where it will start running and getting the latest character and repeating.

class LatestChar {
public:
    /// initialize latest character to -1,
    /// and starts thread that gets the latest character
    LatestChar() :
        ...,
        getch_thread([this] {
            while (true) {
                latest_char = _getch();
            }
        })
    {}
    ...
private:
    ...
    /// this thread loops until told to stop, and updates the latest character
    std::thread getch_thread;
};

Almost done, we now need to rejoin the thread at the end of the program, we will use another atomic variable, this time a boolean, to represent a flag to say "Hey, we are done getting characters, finish what you are doing and join back up with the main thread.

Note that the getch thread will only check this after it reads a character, so when you close your program you might need to input one more character, the alternative is to call something like std::terminate() which will stop the entire program forcefully, which is probably not desired when it can be avoided.

We will initialize the flag to false in the constructor (make sure it is initialized before the getch thread is, otherwise the getch thread might check the value before it has been set to false. The order is they are initialized is the same order they are declared in the class definition.), check it in the thread, and set it to true in the destructor and then also call the join function which will wait until the thread is finished and connect join it back into main.

class LatestChar {
public:
    /// initialize latest character to -1, end thread flag to false,
    /// and starts thread that gets the latest character
    LatestChar() :
        ...,
        end_thread{ false },
        getch_thread([this] {
            while (!end_thread) {
                latest_char = _getch();
            }
        })
    {}
    /// sets end thread flag to true and joins getch thread with main thread
    ~LatestChar() {
        end_thread = true;
        getch_thread.join();
    }
    ...
private:
    ...
    /// this flag tells the getch thread to stop, like at the end of a program,
    /// _getch() will need to receive a character before this is checked
    /// 
    /// this is atomic because it might be read from the getch thread at the
    /// same time it is written from the main thread.
    ///
    /// make sure this is initialized before the getch thread begins
    std::atomic_bool end_thread;
    ...
};

Finally, let's instantiate the class and call the function.

// somewhere not in a loop
LatestChar latest_char;
...
// somewhere is a loop
_x = latest_char.getLatestChar();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM