【发布时间】:2015-05-06 03:31:56
【问题描述】:
这是困扰我多年的问题。
这是我的 game.h 和 game.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
game.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_queue 和五个不同的“事件对象”。我设法创建了一个 event_queues 和 events 的向量,并在每个主循环中对它们进行迭代,同时将每个事件传递给其各自的 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;
}
}
还有新的main.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,我会告诉你:问题仍然存在。完全相同的事情发生了。当我同时按下另一个箭头时,一个箭头会取消另一个箭头,并且玩家会停止移动一段时间。
【问题讨论】:
-
不能创建
e和f这样的两个事件变量。然后您可以轮询以查看e事件是否拾取按键,然后查看f事件是否拾取按键。不过,它似乎需要很多 if-else 案例。否则,this 似乎可以解决您的问题。 -
那篇文章是 2002 年发布的,代码不再有效。尽管如此,我已经在文档中了解了如何以这种方式使用它,并且我已经编辑了更新问题的帖子。
标签: c++ events allegro allegro5