Customizing the Interface
Ren'Py is extremely customizable. Below is information on the many ways available to customize Ren'Py.
Themes
Themes provide a simple way of changing the look of the main and game menus. A single function call applies styles to many of the elements of the main and game menus, giving a consistent look to the interface. These colors, and the background images used, can be changed by supplying parameters to the theme functions.
Theme functions should be called after the config.screen_width, config.screen_height, and library.script_version variables have been set. They should be called before any style is changed by hand.
Function: theme.roundrect( | widget="#003c78", widget_hover="#0050a0", widget_text="#c8e1ff", widget_selected="#ffffc8", disabled="#404040", disabled_text="#c8c8c8", label=,"#ffffff" frame="#6496c8", window="#000000c0", mm_root=..., gm_root=..., centered=False, button_menu=True) |
This enables the use of the roundrect theme. By default, this theme styles the game in a blue color scheme. However, by supplying one or more of the parameters given below, the color scheme can be changed.
widget - The background color of non-focued buttons and sliders.
widget_hover - The background color of focused buttons and sliders.
widget_text - The text color of non-selected buttons.
widget_selected - The text color of selected buttons.
disabled - The background color of disabled buttons.
disabled_text - The text color of disabled buttons.
label - The text color of non-selected labels.
frame - The background color of frames.
mm_root - A displayable (such as an Image or Solid) that will be used as the background for the main menu.
gm_root - A displayable (such as an Image or Solid) that will be used as the background for the game menu.
centered - If True, the buttons and sliders will be centered in the frames or windows that contain them. If False, the default, they will be pushed to the right side.
Function: theme.roundrect_red( | **params) |
This sets up a red/pink variant of the roundrect theme.
The arguments are the same as for theme.roundrect .
Customizing the Keymap
The variable config.keymap contains a map from functions that can be performed by the various user-interface elements of Ren'Py to a list of keysyms (a keysym is a key symbol) that actually perform those functions. Modifying the contents of the keymap can change the keys and mouse buttons that cause things to happen.
While this functionality has been added to Ren'Py at a user's request (and because it simplifies the Ren'Py code), it's not altogether clear that it should be used. Having a common set of keybindings makes games easier to play by reducing the learning curve of users. It's probably better to build consensus around a change in keybindings, rather than unilaterally making one game different from every other game.
Anyway, in Ren'Py keysyms are strings. The first kind of keysym is of the form 'mouseup_#' or 'mousedown_#', for a number between 1 and 5. These keysyms are generated by mouse button presses, releases, or turns of the mouse wheel. For example, "mousedown_1" is generally a press of the left mouse button, "mouseup_1" is a release of that button, and "mousedown_4" is a turn of the the mouse wheel to the top.
A second kind of keysym is a joystick keysym. These begin with joy_. They are defined in config.joystick_keys , and mapped to actual joystick events by the user.
A third kind of keysym is a string containing a character that is generated when a key is pressed. This is useful for binding alphabetic keys and numbers. Examples of these keysyms include "a", "A", and "7".
The final kind of keysym is the symbolic name for the key. This can be any of the K_ constants taken from pygame.constants This type of keysym looks like "K_BACKSPACE", "K_RETURN", and "K_TAB".
To change a binding, update the appropriate list in config.keymap . The following code adds the 't' key to the list of keys that dismiss a say statement, and removes the space key from that list.
init: $ config.keymap['dismiss'].append('t') $ config.keymap['dismiss'].remove('K_SPACE')
The default keymap is contained inside the python code implementing Ren'Py, and as of version 5.6.4 is as follows:
config.keymap = dict( # Bindings present almost everywhere, unless explicitly # disabled. rollback = [ 'K_PAGEUP', 'mousedown_4', 'joy_rollback' ], screenshot = [ 's' ], toggle_fullscreen = [ 'f' ], toggle_music = [ 'm' ], game_menu = [ 'K_ESCAPE', 'mouseup_3', 'joy_menu' ], hide_windows = [ 'mouseup_2', 'h' ], launch_editor = [ 'E' ], dump_styles = [ 'Y' ], # Say. rollforward = [ 'mousedown_5', 'K_PAGEDOWN' ], dismiss = [ 'mouseup_1', 'K_RETURN', 'K_SPACE', 'K_KP_ENTER', 'joy_dismiss' ], # Focus. focus_left = [ 'K_LEFT', 'K_KP_LEFT', 'joy_left' ], focus_right = [ 'K_RIGHT', 'K_KP_RIGHT', 'joy_right' ], focus_up = [ 'K_UP', 'K_KP_UP', 'joy_up' ], focus_down = [ 'K_DOWN', 'K_KP_DOWN', 'joy_down' ], # Button. button_select = [ 'mouseup_1', 'K_RETURN', 'K_KP_ENTER', 'joy_dismiss' ], # Input. input_backspace = [ 'K_BACKSPACE' ], input_enter = [ 'K_RETURN', 'K_KP_ENTER' ], # These keys control skipping. skip = [ 'K_LCTRL', 'K_RCTRL' ], toggle_skip = [ 'K_TAB', 'joy_skip' ], fast_skip = [ '>' ], # These control the bar. bar_activate = [ 'mousedown_1', 'K_RETURN', 'K_KP_ENTER', 'joy_dismiss' ], bar_deactivate = [ 'mouseup_1', 'K_RETURN', 'K_KP_ENTER', 'joy_dismiss' ], bar_decrease = [ 'K_LEFT', 'joy_left' ], bar_increase = [ 'K_RIGHT', 'joy_right' ], )
Customizing the Main and Game Menus
This section describes how the content of the various menus can be customized. If you just want to change the look of the menus (to the extent made possible by the style system), use styles. To change just the text of menu items, consider using config.translations . To change just the position of buttons in a menu, use config.game_menu_positions and config.main_menu_positions .
Main Menu
The main menu can be customized by setting the config.main_menu variable. This variable should be a list of pairs. The first element of each pair is the name of the button on the main menu. The second item can be one of three things. It can be a string, in which case it is a label at which the game execution starts (after a jump out of the menu context). It can be a function, in which case the function is called when the button is clicked. Finally, it can be None, which causes the button to be insensitive.
If one wants to change the main menu each time it is invoked, but keep the look of it the same, then the thing to do is to provide a main_menu label. The code after this main_menu label should set config.main_menu, and then jump to _library_main_menu. This is useful, for example, if there are some items in the main menu that should be absent or disabled until some condition is met. (Say, the user reaching an ending for the first time.)
From Scratch. Finally, it may be desirable to write your own menu from scratch. This is done by creating the menu using ui functions called from code invoked through the main_menu label. To start the game, the code should jump out of the context, using ui.jumpsoutofcontext or renpy.jump_out_of_context . The code can jump to game menu screens, using the jump statement, renpy.jump , or ui.jumps . When interacting with the user, ui.interact should be called with suppress_overlay=True, suppress_underlay=True, and perhaps mouse="mainmenu".
The functions that are used to make a game menu screen, _game_nav() and _game_interact(), should also work with the main menu screen. When necessary, renpy.context().main_menu can be checked to see if we are in the main menu (it is True) or game menu (it is False). (see renpy.context )
Game Menu
The first thing one may wish to do when modifying the game menu is to add a screen to it. This is done in two steps. The first is to create the screen, and the second is to add it to the config.game_menu list so that it can be reached from the game menu.
Each screen is represented in the code as a label that is jumped to to display the screen. There are five steps that this label should do in order to display the screen. First, it should call _game_nav(screen), where screen is the name of the screen (the first component of the tuples in config.game_menu, described below). Second, it should call the ui functions to actually draw the screen. Third, it should call _game_interact, instead of ui.interact , to interact with the user. This ensures that the game menu interaction is handled properly. Fourth, it should examine the results of _game_interact, and react appropriately. Finally, it should jump back up to the screen label, showing the screen again after each interaction.
So that the user can see it, the screen should be added to config.game_menu. This is a list of four-component tuples. The first is the name of the screen. It's used to determine if the button used to reach that screen should be indicated as selected. The second component is the text used for that button. The third component is a function that executes when the button is clicked. Normally, an appropriate function is ui.jumps ('label'), where label is the name of the label under which your screen was defined above. Finally, the fourth parameter is a string containing a python expression. If the expression is not true, the button is insensitive.
To customize the game menu navigation buttons, one can replace the _game_nav() function.
Function: _game_nav( | screen) |
Called by Ren'Py to display navigation for a game menu screen.
screen- the screen we're at. Default parameters for this are "restart", "load", "save", "prefs", "quit", or None. When None, navigation buttons should't be shown.
Variable: _game_menu_screen = | "_load_screen" |
One can customize the screen the game menu jumps to by default by changing the value of _game_menu_screen. For example, one could set this to "_load_screen" for the first few interactions, and then set it to "_save_screen" for the rest of the game. This is especially useful for a game with no main menu.
There is a convenience function for prompting the user for their response to a yes and no question.
Function: _yesno_prompt( | screen, message) |
screen - The screen button that should be highlighted when this prompt is shown. If None, then no game menu navigation is shown.
message - The message that is shown to the user to prompt them to answer yes or no.
This function returns True if the user clicks Yes, or False if the user clicks No.
Pre-defined Screens. The load screen, save screen, and preferences screen are define at the _load_screen, _save_screen and _prefs_screen labels, respectively.
From scratch. To write your own game menu entirely from scratch, set _game_menu_screen to point to the screen you would like to access when the user right-clicks. You can then jump between game menu screens using the jump statement, renpy.jump or ui.jumps . Jump to _return to return to the game or the main menu, as appropriate.
Customizing the Preferences Screen
Customizing the preferences screen is accomplished by modifying config.preferences, which is a dictionary mapping from vbox style to a list of preferences to be placed in that vbox. Modifying this dictionary and lists can move preferences around, and eliminate preferences entirely. It may be desirable to create new vbox styles, by using style.create .
Alternative, one can position preferences using config.preference_positions .
To create an entirely new preference, create it with _Preference, _SliderPreference, or _VolumePreference, and then add it to an appropriate list in config.preferences.
Function: _Preference( | name, field, values, base=...) |
This is a class that's used to represent a multiple-choice preference.
name - The name of this preference. It will be displayed to the user.
variable - The field on the base object that will be assigned the selected value. This field must exist.
values - A list of value name, value, condition triples. The value name is the name of this value that will be shown to the user. The value is the literal python value that will be assigned if this value is selected. The condition is a condition that will be evaluated to determine if this is a legal value. If no conditions are true, this preference will not be displayed to the user. A condition of None is always considered to be True.
base - The base object on which the variable is read from and set. This defaults to _preferences, the user preferences object.
Function: _SliderPreference( | name, range, get, set, enable='True') |
A class that represents a preference that is controlled by a slider.
set - The name of this preference, that is shown to the user.
range - An integer giving the maximum value of this slider. The slider goes from 0 to range.
get - A function that's called to get the initial value of the slider. It's called with no arguments, and should return an integet between 0 and range, inclusive.
set - A function that's called when the value of the slider is set by the user. It is called with a single integer, in the range 0 to range, inclusive.
enable - A string giving a python expression. If the expression is evaluates to false, this preference is not shown.
Function: _VolumePreference( | name, mixer, enable='True', sound='None', channel=0) |
This represents a preference that controls one of the volumes in the system. It is represented as a slider bar, and a button that can be pushed to play a sample sound on a channel.
name - The name of this preference, as shown to the user.
mixer - The mixer this preference controls.
enable - A string giving a python expression. If the expression is evaluates to false, this preference is not shown.
sound - A string that is evaluated to yield another string. The yielded string is expected to give a sound file, which is played as the sample sound. (We apologize for the convolution of this.)
channel - The number of the channel the sample sound is played on.