为什么当我在 allegro 中将光标悬停在 x 轴上从 0 到 100 的区域时程序突然关闭
Why the program suddenly closes when I hover the cursor in area from 0 to 100 on x axis in allegro
我是 allegro 的新手,正在尝试制作一个非常基本的小型绘画程序。我希望这个程序在 800x600 平面上从 A(0, 0) 到 B(100, 600) 的区域停止绘画。当我将光标悬停在该区域时,程序突然自行关闭。这是代码:
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>
#define screen_width 800
#define screen_height 600
int main()
{
al_init();
ALLEGRO_DISPLAY* display = al_create_display(screen_width, screen_height);
al_install_mouse();
al_install_keyboard();
al_init_primitives_addon();
ALLEGRO_EVENT_QUEUE* event_que = al_create_event_queue();
al_register_event_source(event_que, al_get_display_event_source(display));
al_register_event_source(event_que, al_get_keyboard_event_source());
al_register_event_source(event_que, al_get_mouse_event_source());
bool game_over = false, hold = false;
int x = 10, y = 10;
while (!game_over){
ALLEGRO_EVENT event;
al_wait_for_event(event_que, &event);
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN){
hold = true;
}
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP){
hold = false;
}
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE){
game_over = true;
}
if (hold){
x = event.mouse.x;
y = event.mouse.y;
if (x > 100){
al_draw_filled_circle(x, y, 4, al_map_rgb(210, 0, 0));
}
}
al_flip_display();
}
al_destroy_event_queue(event_que);
al_destroy_display(display);
return 0;
}
编辑:
我发现每当我将鼠标悬停在从 (0, 0) 到 (100, 600) 的那个区域时
正在执行此 if 语句:
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
不知道为什么要执行
让我们看看 ALLEGRO_EVENT event
是什么,来自 the docs:
An ALLEGRO_EVENT
is a union of all builtin event structures, i.e. it is an object large enough to hold the data of any event type. All events have the following fields in common:
type
(ALLEGRO_EVENT_TYPE
)
Indicates the type of event.
[...]
By examining the type
field you can then access type-specific fields
如果 event.type
不是键盘事件,则您不能执行访问 event.keyboard
成员的操作,因为那时您正在从不活动的联合成员读取。这是未定义的行为,因此推测不是很有用 - 但在这种情况下,看起来你读取了一些鼠标坐标,就好像它是一个键,但它不是。由于 UB 导致的结果毫无意义,但在这种情况下,它们似乎与坐标相关,使您的代码认为按下了 Esc。
在阅读 keyboard
成员之前,请检查您是否有键盘事件 type
:
if (event.type == ALLEGRO_EVENT_KEY_DOWN &&
event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
{
game_over = true;
}
在使用 union
的任何地方,您都需要格外小心,以便在读取任何成员时都知道它是有效的。唯一可以确定的真正方法是用类型标记它——即使那样也需要你记得先检查类型!
一种更好的方法是 std::variant
,它可以让您检查当前保存的类型,或者如果转换为它,则在它不保存该类型时抛出。当然,你不能在这里使用它,除非有人为 ALLEGRO_EVENT
创建了一个包装器——你可能有时间! - 但我提到它是为了在您自己的代码中替换 union
s。
我是 allegro 的新手,正在尝试制作一个非常基本的小型绘画程序。我希望这个程序在 800x600 平面上从 A(0, 0) 到 B(100, 600) 的区域停止绘画。当我将光标悬停在该区域时,程序突然自行关闭。这是代码:
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>
#define screen_width 800
#define screen_height 600
int main()
{
al_init();
ALLEGRO_DISPLAY* display = al_create_display(screen_width, screen_height);
al_install_mouse();
al_install_keyboard();
al_init_primitives_addon();
ALLEGRO_EVENT_QUEUE* event_que = al_create_event_queue();
al_register_event_source(event_que, al_get_display_event_source(display));
al_register_event_source(event_que, al_get_keyboard_event_source());
al_register_event_source(event_que, al_get_mouse_event_source());
bool game_over = false, hold = false;
int x = 10, y = 10;
while (!game_over){
ALLEGRO_EVENT event;
al_wait_for_event(event_que, &event);
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN){
hold = true;
}
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP){
hold = false;
}
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE){
game_over = true;
}
if (hold){
x = event.mouse.x;
y = event.mouse.y;
if (x > 100){
al_draw_filled_circle(x, y, 4, al_map_rgb(210, 0, 0));
}
}
al_flip_display();
}
al_destroy_event_queue(event_que);
al_destroy_display(display);
return 0;
}
编辑:
我发现每当我将鼠标悬停在从 (0, 0) 到 (100, 600) 的那个区域时 正在执行此 if 语句:
if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
不知道为什么要执行
让我们看看 ALLEGRO_EVENT event
是什么,来自 the docs:
An
ALLEGRO_EVENT
is a union of all builtin event structures, i.e. it is an object large enough to hold the data of any event type. All events have the following fields in common:
type
(ALLEGRO_EVENT_TYPE
)Indicates the type of event.
[...]
By examining the
type
field you can then access type-specific fields
如果 event.type
不是键盘事件,则您不能执行访问 event.keyboard
成员的操作,因为那时您正在从不活动的联合成员读取。这是未定义的行为,因此推测不是很有用 - 但在这种情况下,看起来你读取了一些鼠标坐标,就好像它是一个键,但它不是。由于 UB 导致的结果毫无意义,但在这种情况下,它们似乎与坐标相关,使您的代码认为按下了 Esc。
在阅读 keyboard
成员之前,请检查您是否有键盘事件 type
:
if (event.type == ALLEGRO_EVENT_KEY_DOWN &&
event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
{
game_over = true;
}
在使用 union
的任何地方,您都需要格外小心,以便在读取任何成员时都知道它是有效的。唯一可以确定的真正方法是用类型标记它——即使那样也需要你记得先检查类型!
一种更好的方法是 std::variant
,它可以让您检查当前保存的类型,或者如果转换为它,则在它不保存该类型时抛出。当然,你不能在这里使用它,除非有人为 ALLEGRO_EVENT
创建了一个包装器——你可能有时间! - 但我提到它是为了在您自己的代码中替换 union
s。