Table Of Contents

Previous topic

Graphics

Next topic

Audio

This Page

Events

You handle events by overriding methods in the Game class. Typically your game will be structured with a instance of a subclass of Game, which overrides all the event methods you wish to handle.

Bacon also stores the state of all input devices; so for example, you can query whether a particular key is pressed or not at any point in your program, without having to handle the event.

Game events

Before any frame tick events but after the graphics device is initialized, the game receives a single call to Game.on_init(). Overriding this is not usually necessary as most initialization can be done outside of the Game class. However, the event exists for convenience or to initialize offscreen targets.

Note

TODO on_init example

Every frame Bacon sends the Game.on_tick() event. You must override this method, as it is the only way to update and render the game.

In order to keep animations playing back at a constant speed independent of the framerate, refer to timestep:

Note

TODO timestep example

Keyboard

The Game.on_key() function is called when a key is pressed or released:

import bacon

class Game(bacon.Game):
    def on_tick(self):
        bacon.clear(0, 0, 0, 1)

    def on_key(self, key, pressed):
        print('bacon.Keys.%s was %s' % (bacon.Keys.tostring(key), 'pressed' if pressed else 'released'))

bacon.run(Game())

Alternatively, you can check the keys set at any time to determine if a key is currently pressed. The following example clears the screen to green as long as the spacebar is pressed:

import bacon

class Game(bacon.Game):
    def on_tick(self):
        if bacon.Keys.space in bacon.keys:
            bacon.clear(0, 1, 0, 1)
        else:
            bacon.clear(0, 0, 0, 1)

bacon.run(Game())

See the Key code reference for a complete list of supported key codes.

Mouse

The Game.on_mouse_button() function is called when a mouse button is pressed or released:

import bacon

class Game(bacon.Game):
    def on_tick(self):
        bacon.clear(0, 0, 0, 1)

    def on_mouse_button(self, button, pressed):
        print('bacon.MouseButtons.%s was %s' % (bacon.MouseButtons.tostring(button), 'pressed' if pressed else 'released'))

bacon.run(Game())

The Game.on_mouse_scroll() function is called whenever the mouse wheel is scrolled:

import bacon

kitten = bacon.Image('res/kitten.png')

class Game(bacon.Game):
    offset_x = 0
    offset_y = 0

    def on_tick(self):
        bacon.clear(0, 0, 0, 1)
        bacon.draw_image(kitten, self.offset_x, self.offset_y)
        pass

    def on_mouse_scroll(self, dx, dy):
        self.offset_x += dx
        self.offset_y += dy

bacon.run(Game())

The current position of the mouse, and the state of its buttons, can be queried from the bacon.mouse object:

import bacon

font = bacon.Font('res/DejaVuSans.ttf', 12)

class Game(bacon.Game):
    def on_tick(self):
        bacon.clear(0, 0, 0, 1)
        bacon.draw_string(font, 'Mouse is at %d, %d' % (bacon.mouse.x, bacon.mouse.y), 5, 15)
        if bacon.mouse.left:
            bacon.draw_string(font, 'Left button down', 5, 35)
        if bacon.mouse.right:
            bacon.draw_string(font, 'Right button down', 5, 55)

bacon.run(Game())

Game Controllers

To support the use of game controllers, first listen for the Game.on_controller_connected() event. Check the passed in Controller instance for the set of buttons and axes it supports. Then either listen for Game.on_controller_button() and Game.on_controller_axis() events, or check the state of the controller’s buttons and axes on the controller instance itself.

import bacon

kitten = bacon.Image('res/kitten.png')

class Game(bacon.Game):
    controller = None
    def on_tick(self):
        bacon.clear(0, 0, 0, 1)
        if self.controller:
            bacon.translate(bacon.window.width / 2, bacon.window.height / 2)
            bacon.translate(self.controller.left_thumb_x * 100, self.controller.left_thumb_y * 100)
            bacon.rotate(self.controller.right_thumb_x)
            bacon.scale(self.controller.right_thumb_y + 1, self.controller.right_thumb_y + 1)
            bacon.draw_image(kitten, -kitten.width / 2, -kitten.height / 2)

    def on_controller_button(self, controller, button, pressed):
        print('bacon.ControllerButtons.%s on controller %d was %s' % (bacon.ControllerButtons.tostring(button), controller.controller_index, 'pressed' if pressed else 'released'))

    def on_controller_axis(self, controller, axis, value):
        print('bacon.ControllerAxes.%s on controller %d value is now %f' % (bacon.ControllerAxes.tostring(axis), controller.controller_index, value))

    def on_controller_connected(self, controller):
        self.controller = controller
        print('Controller %d connected: %s' % (controller.controller_index, controller.name))
        print('  Vendor ID: %x' % controller.vendor_id)
        print('  Product ID: %x' % controller.product_id)

    def on_controller_disconnected(self, controller):
        print('Controller %d disconnected' % (controller.controller_index))
        if self.controller is controller:
            self.controller = None

bacon.run(Game())

Game Controller Button and Axis Mapping

Unfortunately there is no prescribed standard for game controllers when it comes to the naming of their buttons, thumbsticks and triggers. Bacon attempts to unify all game controllers into one of a small number of predefined ControllerProfile`s, for example ``ControllerProfile.extended`.

Developing a game that can use the generic profile is quite difficult, and usually requires a setup step where the user maps each button and axis on their controller to a game action. Using the standard or extended profiles is easy, however; once you’ve checked that the profiler matches the required profile, start reading the named inputs (such as Controller.dpad_left).

In order to support these profiles, a ControllerMapping must be provided that maps between the generic inputs (such as ControllerButtons.button1) to the profile inputs. Bacon is distributed with some well-known controllers such as the Xbox 360 controller mappings built-in, but you can also provide your own.

To supply a new mapping, call ControllerMapping.register() with the vendor an product IDs of the controller you are describing, and a ControllerMapping that describes the mapping. For example, here is the built-in mapping for the Xbox 360 controller used on OS X:

bacon.controller.ControllerMapping.register(0x45e, 0x28e, bacon.controller.ControllerMapping(
    buttons=dict(
            button3 = 'action_down',
            button4 = 'action_right',
            button5 = 'action_left',
            button6 = 'left_shoulder',
            button7 = 'right_shoulder',
            button8 = 'left_thumb',
            button9 = 'right_thumb',
            button10 = 'start',
            button11 = 'back',
            button13 = 'dpad_up',
            button14 = 'dpad_down',
            button15 = 'dpad_left',
            button16 = 'dpad_right',
            button17 = 'action_up',
        ),
    axes=dict(
            axis1 = 'right_thumb_x',
            axis2 = 'right_thumb_y',
            right_thumb_y = 'right_trigger',
            right_thumb_x = 'left_trigger',
        ),
    dead_zones=dict(
            left_thumb_x = 7849.0 / 65535.0,
            right_thumb_x = 7849.0 / 65535.0,
            left_thumb_y = 8689.0 / 65535.0,
            right_thumb_y = 8689.0 / 65535.0,
            left_trigger = 30.0 / 255.0,
            right_trigger = 30.0 / 255.0
        ),
    profile='extended'
))