【问题标题】:Movement of Object in a game in C++C++游戏中物体的运动
【发布时间】:2020-12-26 09:48:30
【问题描述】:

所以我正在为学校项目制作游戏。你可能对这个很熟悉。它的打砖块,或用球破坏砖块并被平台偏转的游戏。

目前我被困在一个点上。我知道如何使用 _getch() 移动我的平台,但是当我放入一个球时,它也在按键上移动。我无法弄清楚如何在有或没有任何按键的情况下同时运行它。或者如果有办法跳过每次按键直到它被注册。

到目前为止,这是我的代码。球的运动并不完整,它现在只是一个原型。任何帮助将不胜感激。

我使用的是学校提供的图形库,但你可以使用 C++ 图形库。

#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;
    }
}

【问题讨论】:

  • 您要问的是线程或事件驱动编程。这是一个高级话题。由于您正在学习,因此为您的项目尝试一些更简单的方法可能是个好主意。
  • 这与 Java 有什么关系?请不要垃圾邮件无关的标签。也请阅读How to Ask,以及this question checklist
  • 也许,这给了一些灵感:SO: I/O in concurrent program
  • 任何帮助都将不胜感激,是的,我确实看到了一些关于多线程的帖子,但它超出了我的想象。 @约翰
  • 不要试图用线程来解决你的问题。它们是不必要的并发症。

标签: c++ game-physics game-development linkmovementmethod


【解决方案1】:

由于您似乎使用的是 Windows 和 Microsoft Visual C++,您可以使用_kbhit(),它会告诉您是否按下了某个键。请注意,这不是标准 C++。

这可能看起来像:

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

另外,其他人提到了线程,虽然 John 也指出 _getch() 也不是标准 C++,但我认为介绍线程的一些概念可能会有所帮助。有多种方法可以用线程来实现,但我会展示我认为是最简单的方法。

首先我们将创建一个类,这是隐藏一个包含最新字符的变量。我们希望它隐藏,这样当从主线程读取它时,会消耗最新的字符(设置为 -1),这样当我们下一次调用函数时,如果尚未输入另一个字符,函数将返回 -1。

请注意,如果两个线程同时从一个变量读取和写入,则会发生未定义的行为,因此我们将使用两个线程同时尝试访问它时定义的原子变量。或者存在互斥体,它们速度较慢,但​​允许锁定和解锁更复杂的类型,因此一次只能有一个线程访问它们。

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;
};

接下来我们需要创建调用_getch() 的线程。这是一个成员变量,将在构造函数中声明,它将开始运行并获取最新的字符并重复。

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;
};

几乎完成了,我们现在需要在程序结束时重新加入线程,我们将使用另一个原子变量,这次是一个布尔值,表示一个标志,表示“嘿,我们已经完成了获取字符,完成你的任务正在做并加入主线程。

请注意,getch 线程只会在读取一个字符后检查它,因此当您关闭程序时,您可能需要再输入一个字符,另一种方法是调用 std::terminate() 之类的东西,这将停止强制整个程序,如果可以避免,这可能是不希望的。

我们将在构造函数中将标志初始化为false(确保它在getch线程之前被初始化,否则getch线程可能会在它被设置为false之前检查值。它们被初始化的顺序是相同的在类定义中声明它们的顺序。),在线程中检查它,并在析构函数中将其设置为true,然后还调用join函数,该函数将等待线程完成并将其连接回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;
    ...
};

最后,让我们实例化类并调用函数。

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

【讨论】:

  • 感谢您的回复,我一定会试一试的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多