BGE: menu buttons and opening webpages

This tutorial will look at the method I use to create menu buttons in the BGE. We’ll cover how to change a button’s text when it’s being hovered over, how to change the game scene or exit from a button and how we can use the webbrowser module to open websites from within the BGE.

Button set up

Open up blender and delete everything in the default scene. Then add a text object. Now, add a plane, and move it on the z-axis to sit just above the text object. In edit mode, adjust the plane to fit around the text. Then in the physics properties set the plane to be invisible (make sure you’re in game engine mode). Next, add a game property called “url”, set it to string and enter the web address you want the button to lead to.

setup1

In the logic panel, add 2 mouse sensors to the plane, one set to mouse over called ‘Over’, another set to left click, called ‘Click’. Connect these to a python controller set to module mode and in the module box enter “menus.goToSite”. Then select the text object and then the plane and make the plane the parent of the text object. And that’s our button set up and ready to go.

setup2

Before we get stuck in with the python, we need to add a camera. So do that. Then move it a bit above the plane and text. In the camera properties panel set it to orthographic. Now, instead of moving the camera up and down the z-axis to fit the text in you can adjust the orthographic text. Using this mode will ensure that all objects/text in the menu will appear flat.

setup3

The python

In the text editor lets create a new text file and call it ‘menus.py’ and enter the following:

import bge
import webbrowser

def goToSite():
    own = bge.logic.getCurrentController().owner
    click = own.sensors['Click']
    over = own.sensors['Over']    
    if over.positive:
        own.children[0].color = [1,0,0,1]
        if click.positive:
            webbrowser.open(own['url'], new=2)
    else:
        own.children[0].color = [1,1,1,1]

So lets break this down. You’ll notice that all the magic happens within the function goToSite(). Because we’re operating in module mode more-or-less all the code we need will exist will exist within a function. This includes the standard BGE set up stuff most scripts do (get the owner etc). That’s because when we’re using python in module mode only the function in the called function will be executed.

Text objects, do not use materials, but get their colour from their object colour. We can take advantage of this. So when the mouse over sensor is positive we can change our text colour (line 9). Because we parented the text object to the button plane we can access it through own.children[0]. Because there is only one child we know it’s index will always be 0. If your button plane had more than one child it would be better to call it through its object name (own.children[‘myTextObj’], or whatever you called it). The KX_GameObject.color propery takes a list of 4 floats (0.0 <-> 1.0), red, green, blue and alpha. Here we just set it to red.

Next we check the click sensor has been activated. Notice how it’s nested in after the over sensor. Without this it would just detect the click and not care if our mouse is over our button or not. Now the magic really happens. We use python’s bundled webbrowswer module to open the link stored in our button object by calling webbrowser.open(). And all we have to pass to this is the url we wish to open, which we’ve stored in our button object as a property. By doing this, instead of hard coding the url into our function, we can reuse our button function with other buttons and let each button object define what site it goes to. webbrowser.open() actually takes 3 arguments (url, new and raise), the last 2 have default values. New controls if it opens in the current browser window, a new window or a new tab (set to 0, 1, or 2 respectively, 0 is the default. Raise can be set to True or False and controls if the window is raised, ie, pops-up. By default this is set to True.

While the webbrowser module will try to open the browser using the behaviours we’ve specified, it is at the whim of the system and browser set up and that will have the final say over how things are opened. Outside of that function the webbrowser module doesn’t do much else. All it’s there for is to open links in the webbrowser. The other bits in that module you’ll probably never need.

Finally, we take advantage that when the mouse is no longer over our button object the mouse over sensor will send a negative pulse to the python module controller. This will cause the function to run one last time, this time setting our text back to its original colour.

Taking it further

This is how I set up all my menu buttons. In menu.py I define a separate function for each type of behaviour. Where buttons share behaviours but have different values (like url’s) I store these values in the button object to save on code re-writing. We can put any code after checking the click sensor. So we could create an exit button:

def exit():
    own = bge.logic.getCurrentController().owner
    click = own.sensors['Click']
    over = own.sensors['Over'] 
    if over.positive:
        own.children[0].color = [1,0,0,1]
        if click.positive:
            bge.logic.endGame()
    else:
        own.children[0].color = [1,1,1,1]

Or we could go to another scene, such as going to the game from the main menu:

def playGame():
    own = bge.logic.getCurrentController().owner
    click = own.sensors['Click']
    over = own.sensors['Over'] 
    if over.positive:
        own.children[0].color = [1,0,0,1]
        if click.positive:
            bge.logic.mouse.visible = False
            bge.logic.getCurrentScene().replace('Level1')
    else:
        own.children[0].color = [1,1,1,1]

Each time, we can just copy and paste the code from our previous button behaviour and change what happens in the inner-most if block.

Check boxes

Just to show you how extensible this method is, here’s a check box example.

Set up your button like before, but instead of using a text object, create a kind of check box shape:

setup4

And instead of adding a property called ‘url’ give it a property called ‘tickOb’ and make sure it is set to 0.

Then, in a new (hidden) layer, create a small tick/dot object that will go in your check box and name it something sensible. Finally, add the below function to menus.py and set the check boxes python module controller to call that.

def checkBox():
    own = bge.logic.getCurrentController().owner
    click = own.sensors['Click']
    over = own.sensors['Over'] 
    if over.positive:
        own.children[0].color = [1,0,0,1]
        if click.positive:
            if own['tickOb']:
                # deselect box
                own['tickOb'].endObject()
                own['tickOb'] = None
                
                # update your game options/settings/whatever here
                
            else:
                # select box
                own['tickOb'] = own.scene.addObject('Tick', own)
            
                # update your game options/settings/whatever here
    else:
        own.children[0].color = [1,1,1,1]

To get your check box to change colour on when the cursor’s hovering over it, add a material and set it to use the object color:

setup5

Thoughts on menu design

Designing good menus it not too hard. I think the key thing is to keep it simple. Avoid overly chaotic, detailed or busy backgrounds. Block colours work better. Use fonts that are easy to read. And try not to include too many buttons on one singular menu. If you’ve got lots of buttons, can they be split across sub-menus? The purpose of each button and menu should be clear to the player without having to put in too much thought. At the end of the day, they want to spend most of their time playing the game, not navigating menus and figuring them out.

Think about the colour pallet of your game. Choose menu colours from that to help them feel tied in with the rest of the game. If you use game objects/images/elements/moving parts in the background don’t place them underneath text. Instead, use them as a framing tool to draw the player’s eye to the menu buttons. Blender Jones BGMC15 entry is a really good example of this:

menu example

In closing

I like using python modules for menu buttons. I find it leads to a really fast menu development and keeps all the menu functions tidy and in one place. If you look closely at the buttons.blend in the resources below, you might notice that each of the button objects is just copied down from the first one, all I’ve had to change is the function called. One of the beauties about the BGE using python is the amount of modules that python provides us with. We can use these modules to perform all kinds of actions outside of the BGE, such as directing them to a website. From a game development perspective you can use this to point players to updates, new content, or your blog **winky-face**

As always, if you’ve got any comments or suggestions leave them below. And feel free to leave your own menu/button design tips and share your own button functions.

Resources

buttons.blend

~ by Jay on February 25, 2015.

Leave a comment