c++allegro

Why the program suddenly closes when I hover the cursor in area from 0 to 100 on x axis in allegro


I'm new in allegro and trying to make a small, very basic painting program. I want this program to stop painting when in the area from A(0, 0) to B(100, 600) on 800x600 plane. When I hover my cursor in this area the program suddenly closes itself. Here is the code:

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

Edit:

I've found that whenever i hover in that area from (0, 0) to (100, 600) this if statement is being executed:

if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)

I don't know why it is executing.


Solution

  • Let's look at what ALLEGRO_EVENT event is, via 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

    You can't do stuff that accesses event.keyboard members if the event.type is not a keyboard event, because then you're reading from an inactive union member. That is undefined behaviour, so speculation is not very useful - but in this case, it looks like you read some bit of a mouse coordinate as if it were a key, but it's not. Results due to UB are meaningless, but it seems that, in this case, they correlated with coordinates to make your code think Esc was pressed.

    Check you have a keyboard event type before reading the keyboard members:

    if (event.type == ALLEGRO_EVENT_KEY_DOWN &&
        event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
    {
        game_over = true;
    }
    

    You need to be extremely careful, anywhere you use a union, to know any member is valid when you read from it. About the only real way to be sure is to tag it with a type - and even that requires that you remember to check the type first!

    A superior way is std::variant, which lets you check the currently held type or, if casting to it, throws if it doesn't hold that. Of course, you can't use that here, unless someone creates a wrapper for ALLEGRO_EVENT - which you might have time for! - but I mention it to replace unions in your own code.