为什么当我在 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 创建了一个包装器——你可能有时间! - 但我提到它是为了在您自己的代码中替换 unions。