gpt4 book ai didi

c++ - 如何实时使用事件同时按下多个键? (快板 5)

转载 作者:行者123 更新时间:2023-11-30 02:39:11 25 4
gpt4 key购买 nike

这是困扰我多年的问题。

这是我的game.hgame.cpp 文件:

game.h

#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED

#include "init.h"

ALLEGRO_BITMAP *load_bmp(path *s);

struct Actor {
const char *path;
ALLEGRO_BITMAP *bmp;
int x;
int y;
int speed;
};

void init_game_bitmaps();
void draw_game_bitmaps();

extern map<string, bool> key_states;
void init_key_states();
void check_states();

void control_actor(Actor *target, int speed);

extern Actor player;

#endif // GAME_H_INCLUDED

游戏.cpp

#include "game.h"

ALLEGRO_BITMAP *load_bmp(path *s) {
ALLEGRO_BITMAP *bmp = nullptr;
bmp = al_load_bitmap(s);
if (!bmp) {

al_show_native_message_box(display,
"Fatal Error!",
"Failed to load: " ,
s,
NULL,
ALLEGRO_MESSAGEBOX_ERROR);

al_destroy_display(display);
return nullptr;

}

return bmp;
}

map<string, bool> key_states;
void init_key_states() {

key_states["UP"] = false;
key_states["DOWN"] = false;
key_states["LEFT"] = false;
key_states["RIGHT"] = false;

}

void check_states() {
auto key = e.keyboard.keycode;
for (auto it = key_states.begin(); it != key_states.end(); ++it) {
if (e.type == ALLEGRO_EVENT_KEY_DOWN) {
if (key == ALLEGRO_KEY_UP) {
if (it->first == "UP") {
it->second = true;
}
}
if (key == ALLEGRO_KEY_DOWN) {
if (it->first == "DOWN") {
it->second = true;
}
}
if (key == ALLEGRO_KEY_LEFT) {
if (it->first == "LEFT") {
it->second = true;
}
}
if (key == ALLEGRO_KEY_RIGHT) {
if (it->first == "RIGHT") {
it->second = true;
}
}
} else if (e.type == ALLEGRO_EVENT_KEY_UP) {
if (key == ALLEGRO_KEY_UP) {
if (it->first == "UP") {
it->second = false;
}
}
if (key == ALLEGRO_KEY_DOWN) {
if (it->first == "DOWN") {
it->second = false;
}
}
if (key == ALLEGRO_KEY_LEFT) {
if (it->first == "LEFT") {
it->second = false;
}
}
if (key == ALLEGRO_KEY_RIGHT) {
if (it->first == "RIGHT") {
it->second = false;
}
}
}
cout << it->first << " : " << it->second << endl;
}
}

void control_actor(Actor *target, int speed) {
if (key_states["UP"]) {
target->y -= speed;
}
if (key_states["DOWN"]) {
target->y += speed;
}
if (key_states["LEFT"]) {
target->x -= speed;
}
if (key_states["RIGHT"]) {
target->x += speed;
}
}

Actor player = {
"GFX\\player_up.png",
nullptr,
(SCREEN_WIDTH / 2) - (ACTOR_SIZE / 2),
(SCREEN_HEIGHT / 2) - (ACTOR_SIZE / 2),
8};

void init_game_bitmaps() {
player.bmp = load_bmp(player.path);
}

void draw_game_bitmaps() {
al_draw_bitmap(player.bmp, player.x, player.y, 0);
al_flip_display();
}

现在这是我的主文件:

main.cpp

#include "init.h"
#include "game.h"

int main(int argc, char **argv){

init_all();
register_all();
init_game_bitmaps();
init_key_states();

while (running) {

draw_game_bitmaps();
al_wait_for_event(event_queue, &e);

if (e.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
running = false;
}

check_states();
control_actor(&player, player.speed);

if (e.type == ALLEGRO_EVENT_KEY_DOWN) {
if (e.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
running = false;
}
if (e.keyboard.keycode == ALLEGRO_KEY_ENTER) {
cout << "It works!";
}
}

}

destroy_all();

return 0;
}

如您所见,我有一个存储键状态的 std::map(一个对应键盘的每个箭头),然后我有一个名为 check_states() 的过程,它在每个主循环中迭代所有状态, 如果按下(向下)各自的箭头,则将它们设置为 true,而当它们被释放时,则设置为 false。

问题:

如果我按住 UP 键不放,然后按 LEFT 键(不松开 UP 键),玩家将沿对角线移动。 尽管如此,如果我松开 LEFT,同时仍然按住 UP 键,播放器将停止,UP 的状态将为真(我看到这个是因为我' m 计算它)。

理论

al_wait_for_event()等到指定的事件队列非空(这意味着当我按下 UP 键时,它将事件复制到 e,然后当我按下 LEFT 时,它必须取消 UP 并分配一个e 的新事件,因此当我一次按下多个键时会产生令人不快的 LAG)。考虑到这一点,我得出结论:好吧,我至少可以有五个独立的事件队列和五个不同的“事件对象”。我已经设法创建了一个 event_queues 和 events 的 vector ,并在每个主循环中迭代它们,同时将每个事件传递给它各自的 event_queue 并且问题仍然存在

那么,如何实时按下多个键?实时我的意思是真正的实时,没有延迟,没有任何键相互抵消。答案是关键状态?为什么?我怎样才能使用事件来做到这一点?有可能吗?

编辑:

我已经更改了我的 control_actor() 过程以使用 al_key_down() 而不是检查事件,这是它的代码:

void control_actor(ALLEGRO_KEYBOARD_STATE *key, Actor *target, int speed) {
if (al_key_down(key, ALLEGRO_KEY_UP)) {
target->y -= speed;
cout << "UP" << endl;
}
if (al_key_down(key, ALLEGRO_KEY_DOWN)) {
target->y += speed;
cout << "DOWN" << endl;
}
if (al_key_down(key, ALLEGRO_KEY_LEFT)) {
target->x -= speed;
cout << "LEFT" << endl;
}
if (al_key_down(key, ALLEGRO_KEY_RIGHT)) {
target->x += speed;
cout << "RIGHT" << endl;
}
}

以及新的 ma​​in.cpp:

#include "init.h"
#include "game.h"

int main(int argc, char **argv){

init_all();
register_all();
init_game_bitmaps();
ALLEGRO_KEYBOARD_STATE key;

while (running) {

draw_game_bitmaps();
al_wait_for_event(event_queue, &e);

al_get_keyboard_state(&key);

control_actor(&key, &player, player.speed);

if (e.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
running = false;
}

if (e.type == ALLEGRO_EVENT_KEY_DOWN) {
if (e.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
running = false;
}
if (e.keyboard.keycode == ALLEGRO_KEY_ENTER) {
cout << "It works!";
}
}

}

destroy_all();

return 0;
}

The post on the allegro forums linked in the comment is from 2002 ,并且该代码不再适用于 Allegro 5。So I've checked the docs ,然后我会告诉您:问题仍然存在。完全相同的事情发生了。当我同时按下另一个箭头时,一个箭头会取消另一个箭头,玩家会停止移动一段时间。

最佳答案

Basic Keyboard Example在 allegro wiki 上可能比那个旧帖子更有帮助。

这里不需要管理多个事件队列。每个按键按下和释放都应该被插入队列——您只需要确保处理队列中的每个事件。

基本上,您需要一个主循环:

  1. 处理当前队列中的每个事件
  2. 更新游戏状态
  3. 重绘屏幕

这是我起草的一个例子:

#include <stdio.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>

const int SPEED = 5;
const float FPS = 60;

int main(int argc, char **argv) {
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
int x = 0, y = 0; // position
int vx = 0, vy = 0; // velocity

// initialize everything we need -- error checking omitted for brevity
al_init();
al_install_keyboard();
al_init_primitives_addon();
display = al_create_display(640, 480);
event_queue = al_create_event_queue();
timer = al_create_timer(1.0 / FPS);
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_start_timer(timer);

bool done = false;
while(!done) {
bool redraw = false;

// process events until queue is empty
while(!al_is_event_queue_empty(event_queue)) {
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);

switch(ev.type) {
case ALLEGRO_EVENT_KEY_DOWN:
switch(ev.keyboard.keycode) {
case ALLEGRO_KEY_W:
vy -= SPEED; // add upward velocity
break;
case ALLEGRO_KEY_S:
vy += SPEED; // add downward velocity
break;
case ALLEGRO_KEY_A:
vx -= SPEED; // add leftward velocity
break;
case ALLEGRO_KEY_D:
vx += SPEED; // add leftward velocity
break;
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
}
break;
case ALLEGRO_EVENT_KEY_UP:
switch(ev.keyboard.keycode) {
case ALLEGRO_KEY_W:
vy += SPEED; // remove upward velocity
break;
case ALLEGRO_KEY_S:
vy -= SPEED; // remove downward velocity
break;
case ALLEGRO_KEY_A:
vx += SPEED; // remove leftward velocity
break;
case ALLEGRO_KEY_D:
vx -= SPEED; // remove leftward velocity
break;
}
break;
case ALLEGRO_EVENT_TIMER:
redraw = true; // time for next frame
break;
}
}

// got through all the events this loop -- redraw if necessary
if (redraw) {
// move circle
x += vx;
y += vy;

// draw circle
al_clear_to_color(al_map_rgb(0, 0, 0));
al_draw_filled_circle(x, y, 20, al_map_rgb(0, 0, 255));
al_flip_display();
}
}

al_destroy_display(display);

return 0;
}

注意 while(!al_is_event_queue_empty(event_queue))。这确保我们在进入更新循环之前不会错过任何事件。

如果您尝试运行该示例,圆圈应该对 WASD 键的任意组合做出适当的响应。如果您按住 S+D,它将沿对角线向右和向下移动。松开 S,它会继续向右移动,但不会向下移动。

希望这对您有所帮助!

关于c++ - 如何实时使用事件同时按下多个键? (快板 5),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30066991/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com