Search code examples
event-handlingactorrebolrebol3

Should I use an event handler or actor for adding keyboard controls for a game


In Rebol3 Saphir, I am writing a game and I had been poking about with the event handler functionality as well as actors, and I was wondering whether it would be a better idea to use an event handler to take keyboard controls for the game or to add an actor into one of the GUI elements.

If I use an actor, on what level? I'm currently using an image! type for the screen. Can I add an actor to the root(layout) face so even if I click (give focus) to a button also on the GUI the focus will be off the image and it won't take keyboard controls.


Solution

  • Below is an example how you could do it...You might also use just the built-in keyboard shortcuts feature if you don't need key-up events. In such case see example with shortcut keys here: https://github.com/saphirion/documentation/blob/master/r3/r3-gui/examples/layouts/layout-15.r3

    This version is modified to work with the current (09/26/13) release of R3-GUI

    REBOL [
        author: "[email protected]"
    ]
    
    load-gui
    
    ;image for game screen
    img: make image! 400x400
    
    ;just some example game object
    game-object: context [
        offset: 0x0
        draw-block: [
            pen red
            fill-pen white
            line-width 5
            circle offset 20
        ]
        move: func [
            delta [pair!]
        ][
            offset: offset + delta
            img/rgb: black
            ;note: this is not optimal way how to render DRAW objects
            ;but I use image! here because the asking SO user uses image! as well
            ;better way is to just use DRAWING style for DRAW based graphics
            draw img to-draw draw-block copy []
            draw-face game-screen
            ;signal true move has been executed
            return true
        ]
    ]
    
    stylize [
        ;backup the original window style to be able call the original key actor
        window-orig: window []
    
        ;override window style with our key actor
        window: window [
            actors: [
                on-key: [
                    ;execute our key controls prior to 'system' key handling
                    switch arg/type [
                        key [
                            ;here you can handle key-down events
                            moved?: switch/default arg/key [
                                up [
                                    game-object/move 0x-5
                                ]
                                down [
                                    game-object/move 0x5
                                ]
                                left [
                                    game-object/move -5x0
                                ]
                                right [
                                    game-object/move 5x0
                                ]
                            ][
                                false
                            ]
                        ]
                        key-up [
                            ;here you can handle key-up events
                        ]
                    ]
                    ;for example filter out faces that shouldn't get the system key events (for example editable styles)
                     unless all [
                        moved?
                        guie/focal-face
                        tag-face? guie/focal-face 'edit
                     ][
                        ;handle the system key handling
                        do-actor/style face 'on-key arg 'window-orig
                    ]
                ]
            ]
        ]
    ]
    
    view [
        title "Custom keyboard handling (whole window)"
        text "press cursor keys to move the box"
        game-screen: image options [min-size: 400x400 max-size: 400x400]
        text 400 "focus the field below and press to see these keys are filtered out, but other keys works normally"
        field "lorem ipsum"
        when [enter] on-action [
            ;initialize game object
            game-object/move 200x200
        set-face game-screen img
        ]
    ]
    

    This version uses an as-of-yet unreleased version of R3-GUI:

    REBOL [
        author: "[email protected]"
    ]
    
    ;image for game screen
    img: make image! 400x400
    
    ;just some example game object
    game-object: context [
        offset: 0x0
        draw-block: [
            pen red
            fill-pen white
            line-width 5
            circle offset 20
        ]
        move: func [
            delta [pair!]
        ][
            offset: offset + delta
            img/rgb: black
            ;note: this is not optimal way how to render DRAW objects
            ;but I use image! here because the asking SO user uses image! as well
            ;better way is to just use DRAWING style for DRAW based graphics
            draw img to-draw draw-block copy []
            draw-face game-screen
            ;signal true move has been executed
            return true
        ]
    ]
    
    stylize [
        ;backup the original window style to be able call the original key actor
        window-orig: window []
    
        ;override window style with our key actor
        window: window [
            actors: [
                on-key: [
                    ;execute our key controls prior to 'system' key handling
                    switch arg/type [
                        key [
                            ;here you can handle key-down events
                            moved?: switch/default arg/key [
                                up [
                                    game-object/move 0x-5
                                ]
                                down [
                                    game-object/move 0x5
                                ]
                                left [
                                    game-object/move -5x0
                                ]
                                right [
                                    game-object/move 5x0
                                ]
                            ][
                                false
                            ]
                        ]
                        key-up [
                            ;here you can handle key-up events
                        ]
                    ]
                    ;for example filter out faces that shouldn't get the system key events (for example editable styles)
                     unless all [
                        moved?
                        guie/focal-face
                        tag-face? guie/focal-face 'edit
                     ][
                        ;handle the system key handling
                        do-actor/style face 'on-key arg 'window-orig
                    ]
                ]
            ]
        ]
    ]
    
    view [
        title "Custom keyboard handling (whole window)"
        text "press cursor keys to move the box"
        game-screen: image img options [min-size: 400x400 max-size: 400x400]
        text 400 "focus the field below and press to see these keys are filtered out, but other keys works normally"
        field "lorem ipsum"
        when [enter] on-action [
            ;initialize game object
            game-object/move 200x200
        ]
    ]