Naming conventions
Readability counts, and it helps to be consistent. Since Python lies below all of Ren'Py it makes sense to consider the way Python suggests doing things outlined in PEP-8 . The following named styles are recognised:
- lowercase
- All letters are lower case, no underscores.
- lower_case_with_underscores
- All letters are lower case, words separated by underscores.
- UPPERCASE
- All letters are upper case, no underscores.
- UPPER_CASE_WITH_UNDERSCORES
- All letters are upper case, words separated by underscores.
- CamelCase
- The first letter of each word is upper case, the rest are lower case.
- mixedCase
- The first letter of the first word is lower case, subsequent words have the first letter in upper case.
Underscores
I'll just say it: Python has an underscore fetish. Underscores are used to convey meaning besides being just a separator that isn't a white space. In other places underscores change the way things work.
- Single leading underscore:
_thing
-
Weakly indicates that the thing is for internal use.
Python has no access control mechanism or keyword like
private
in other languages. - Single trailing underscore:
thing_
-
Used to avoid conflict with a keyword like
class
. So if a parameter to a function is supposed to be passed a class you'd name the parameterclass_
. Personally, I prefer Mr. Bounder of Adventure's solution and spell class with a 'k':klass
. - Double leading underscores:
__thing
- Invokes name-mangling for attributes of a class.
- Double leading and trailing underscores (dunder):
__thing__
-
"Magic" objects and attributes. I'm not making this up. These
are fundamental to the way Python works, like
__init__
and__str__
. Don't invent more of them. - Ren'Py itself adds a function
_()
- This is used to mark strings as needing to be translated.
Personally I strongly dislike underscores for a number of reasons:
- I have some astigmatism and I find them visually disturbing. Code containing many underscores is less accessible to me.
- I started coding on CRT based monitors which over-emphasise underscores because of the way the beam electronics works. This made the above problem worse.
- Fundamentally underscores are markup to generate rules and underlines, and have as much place in code as the BEL character.
Files
Script files
Script files must begin with a letter or number, but may not begin with
two zeros 00
. They must have the extension .rpy
.
You can break up your game into as many script files as you wish as
labels are used to find parts of the script.
In some cases the order of scripts may be important. Ren'Py loads them
in order based on the path and filename (depth first). For initialisation
(init blocks) the order can be altered by the init statement.
Image files
Image files have to be named a certain way if they are to be used without specifying the extension of the file.
Labels (Ren'Py)
Python has no goto or jump equivalent for good reason, so the PEP has nothing to offer on how to choose names for labels. Ren'Py's documentation and the behaviour of the "Add from clauses to calls" build option shows a preference for lower_case_with_underscores.
Dingo: Label names should be mixedCase, but
from
clause labels may be lower_case_with_underscores.
Global labels still have to be unique across all .rpy
files. If you are working with subfolders it may help to devise a label
naming scheme that echoes the path to the file. For example the file
act1/scene1.rpy would use label act1_scene1:
.
Local labels only have to be unique within their global label. Where a local label has the same function in multiple files it should have the same name.
Special labels
Ren'Py has a number of labels that have special meanings:
Name | Purpose |
---|---|
after_load | Called after a save game has been loaded. Intended to allow adjustments between save game versions. |
after_warp |
If it exists it is called after the warp but before the
warped-to line is executed.
Warping is a developer mode feature that is invoked from
the command line and makes a best-effort to attempt to
run the game from a specific line.
See Warping to a line . |
before_main_menu | If it exists it is called before the main menu. Can be used to set up the main menu for example by starting a movie in the background. |
hide_windows |
If it exists it is called when the player hides windows
with the H key or the right mouse button.
If it returns True Ren'Py assumes the code
in the label hid the windows. If it returns
False the windows are hidden as normal.
|
main_menu |
If it exists it is called instead of showing the main menu.
When (if) it returns Ren'Py will start the game at the
start label.
|
quit | If it exists it is called when the player quits the game. It is called in a new context. |
splashscreen | If it exists it is called when the game is launched before showing the main menu. |
start | Called when the player clicks Start on the main menu. |
Variables (defaults)
Dingo: Variable names should be mixedCase.
Names to avoid
Single letter names in general. Some are generally considered acceptable
where they represent mathematical symbols such as x
,
y
, and z
where dealing with coordinate systems.
Since Fortran days programmers have used i
, j
,
k
, through n
for integer variables.
Avoid b
, f
, r
, and u
as these are valid prefixes for strings so a missing space can change the
meaning.
Because Ren'Py variables have global scope it's all too easy to completely
fubar everything by creating a variable that overrides or hides
something important like a Python built-in function, particularly if you
come from developing in another language where a variable x
cannot override/hide a function x()
.
Prime offenders are len
and str
.
While the Ren'Py documentation does offer a long list of all the already-used names to search through often a faster method is to:
- Launch your game
- Open the console Shift + O
- Try to print your prospective variable name: print varname
- A message ending NameError: name varname is not defined means it is safe to use that name
Booleans
Most of the time booleans are used to indicate conditions and are used in
if
statements and with logical operators. It makes sense
to use names that are going to read cleanly. For example
if keyFound:
is more obvious than if key:
.
Numbers
Numeric values can be used for measurements in which case I'd recommend
including the unit in the name for example pcHeightIn
or
pcHeightCm
.
This is particularly important if you are mixing unit systems for
accessibility.
Specials
Ren'Py has a number of variables that have special meanings (TBC):
Name | Purpose |
---|---|
_return | Value returned from the last Ren'Py script call |
save_name | An additional line of text to annotate the next game save |
Constants (defines)
Dingo: Constant names should be mixedCase postfixed with 'C'.
Neither Python or Ren'Py have the ability to stop you altering the
value of a variable intended to be constant. There's no equivalent of
const
or other keyword to create a constant.
The naming convention is used as an indication that you shouldn't ever
alter a value.
Functions (Python)
Dingo: Function names should be mixedCase.
Functions follow the same naming conventions as variables. Functions will be covered later.
Classes (Python)
Dingo: Class names should be CamelCase.
Classes are a more advanced topic, and these will be covered later. Classes (and some class-like things) are the only names that have an initial uppercase letter.