Python Scripting in
Blender
Gordon Erlebacher
Fall 2012
Tuesday, October 2, 12
Audience
• Python classes are for the programmers
• Non-programmers should try to
understand, but will not be required to do
homeworks based on Python
• Non-Programmers and Programmers must
work together to develop the game, not in
isolation
Tuesday, October 2, 12
Python Console
Tuesday, October 2, 12
Python Basics
• From the command line (mac/linux/
windows with cygwin)
• type python
>>> 3+3
6
>>> a = “gor”; b = “fran”
>>> a + b
>>> ‘gorfran‘ # concatenation of strings
Tuesday, October 2, 12
Scripting Language
• Write Python in
• Blender Window
• Editor outside Python
• An interpreter reads each line, checks for errors
and executes the line
• it is somewhat more complex than that
• Allows complex interactions not possible in the
game engine
Tuesday, October 2, 12
Example
print(5+6)
exit() # Stop the program
print("x = 6") # line is never executed
Tuesday, October 2, 12
Example
print(5+6)
exit() # Stop the program
a = 3/; # Error (stops program from running)
print("x = 6") # line is never executed
•First, the program is checked for syntactical errors
•Second, the program is executed
Tuesday, October 2, 12
When to use Python
• When the logic panel becomes too complex and hard to
understand
• In situations with complex series of states
• When multiple objects should interact with each other
• When one wishes to create actions (animations) on the fly
• Fancy use of random numbers
• Program complex motions
• Handle the mouse
• Handle multiple cameras, multiple players, multiple viewports
• ... whatever your imagination dictates ...
Tuesday, October 2, 12
Everything is an Object
• Actuator, Controller, Sensor
• Mesh
• IPO
• Texture, Material
• Camera
• etc.
Tuesday, October 2, 12
Scenes
• One can construct one or more scenes
• Each scene contains a collection of objects
• Objects can be shared between scenes
• Scenes help with level design
Tuesday, October 2, 12
Documentation
• Documentation of 2.63 API
• Code fragments (outside the game engine)
• Thread on scripts (outside the game
engine)
• 2.6 Manual (with section on game engine)
• Blender Basics, 4th Edition
Tuesday, October 2, 12
Interactive Console
Tuesday, October 2, 12
MacOSx/Linux
cd /Applications/blender-2.63a-release-
OSX_10.6_x86_64/blender.app/Contents/
MacOS/
./blender # start blender
# errors will be printed out to the window
blender is started in.
Tuesday, October 2, 12
Windows XP/Visa/7
When Blender is started on a Windows operating system, the Console Window is first
created as a separate window on the desktop. Assuming that the right start-up
conditions are met, the main Blender window should also appear and the Console
Window will then be toggled off. This is unlike the 2.4x series where theConsole
Window would remain visible while the main Blender window was open. To display the
console in current versions of Blender, go to Help » Toggle System Console.When
Blender is started on a Windows operating system, the Console Window is first created
as a separate window on the desktop. Assuming that the right start-up conditions are
met, the main Blender window should also appear and the Console Window will then be
toggled off. This is unlike the 2.4x series where theConsole Window would remain
visible while the main Blender window was open. To display the console in current
versions of Blender, go to Help » Toggle System Console.
Tuesday, October 2, 12
Module bge
• bge : Blender Game Engine
• First program:
• import bge
print(dir(bge))
• Output
• Blender Game Engine Started
['__doc__', '__name__', 'constraints', 'events', 'logic', 'render',
'texture', 'types']
['__doc__', '__name__', 'constraints', 'events', 'logic', 'render',
'texture', 'types']
• Blender Game Engine Finished
Tuesday, October 2, 12
Simplest Program
Python script
Tuesday, October 2, 12
How to use the output
import bge
print(dir(bge))
#['__doc__', '__name__', 'constraints', 'events', 'logic', 'render', 'texture', 'types']
print(dir( bge.events))
['__doc__', '__name__', 'constraints', 'events', 'logic', 'render', 'texture', 'types']
['ACCENTGRAVEKEY', 'AKEY', 'BACKSLASHKEY', 'BACKSPACEKEY', 'BKEY',
'CAPSLOCKKEY', 'CKEY', 'COMMAKEY', 'DELKEY', 'DKEY', 'DOWNARROWKEY',
'EIGHTKEY', 'EKEY', 'ENDKEY', 'ENTERKEY', 'EQUALKEY', 'ESCKEY', 'EventToCharacter',
'EventToString', 'F10KEY', 'F11KEY', 'F12KEY', 'F13KEY', 'F14KEY', 'F15KEY', 'F16KEY',
'F17KEY', 'F18KEY', 'F19KEY', 'F1KEY', 'F2KEY', 'F3KEY', 'F4KEY', 'F5KEY', 'F6KEY',
'F7KEY', 'F8KEY', 'F9KEY', 'FIVEKEY', 'FKEY', 'FOURKEY', 'GKEY', 'HKEY', 'HOMEKEY',
'IKEY', 'INSERTKEY', 'JKEY', 'KKEY', 'LEFTALTKEY', 'LEFTARROWKEY',
'LEFTBRACKETKEY', 'LEFTCTRLKEY', 'LEFTMOUSE', 'LEFTSHIFTKEY', 'LINEFEEDKEY',
'LKEY', 'MIDDLEMOUSE', 'MINUSKEY', 'MKEY', 'MOUSEX', 'MOUSEY', 'NINEKEY',
'NKEY', 'OKEY', 'ONEKEY', 'PAD0', 'PAD1', 'PAD2', 'PAD3', 'PAD4', 'PAD5', 'PAD6', 'PAD7',
'PAD8', 'PAD9', 'PADASTERKEY', 'PADENTER', 'PADMINUS', 'PADPERIOD',
'PADPLUSKEY', 'PADSLASHKEY', 'PAGEDOWNKEY', 'PAGEUPKEY', 'PAUSEKEY',
'PERIODKEY', 'PKEY', 'QKEY', 'QUOTEKEY', 'RETKEY', 'RIGHTALTKEY',
Tuesday, October 2, 12
print(bge.logic)
['BL_DST_ALPHA', 'BL_DST_COLOR', 'BL_ONE', 'BL_ONE_MINUS_DST_ALPHA',
'BL_ONE_MINUS_DST_COLOR', 'BL_ONE_MINUS_SRC_ALPHA',
'BL_ONE_MINUS_SRC_COLOR', 'BL_SRC_ALPHA', 'BL_SRC_ALPHA_SATURATE',
'BL_SRC_COLOR', 'BL_ZERO', 'CAM_POS', 'CONSTANT_TIMER',
'CONSTRAINT_IK_COPYPOSE', 'CONSTRAINT_IK_DISTANCE',
... many more items ...
EWMATRIX_TRANSPOSE', '__doc__', '__name__', '__package__', 'addScene', 'endGame',
'error', 'expandPath', 'getAverageFrameRate', 'getBlendFileList', 'getCurrentController',
'getCurrentScene', 'getExitKey', 'getLogicTicRate', 'getMaxLogicFrame', 'getMaxPhysicsFrame',
'getPhysicsTicRate', 'getRandomFloat', 'getSceneList', 'getSpectrum', 'globalDict', 'keyboard',
'loadGlobalDict', 'mouse', 'restartGame', 'saveGlobalDict', 'sendMessage', 'setExitKey',
'setGravity', 'setLogicTicRate', 'setMaxLogicFrame', 'setMaxPhysicsFrame', 'setPhysicsTicRate',
'startGame']
Tuesday, October 2, 12
Do not sweat
the details
Tuesday, October 2, 12
Example 1
Make a cube move with the Akey
Tuesday, October 2, 12
bge.logic.getCurrentScene()
['__class__', '__contains__', '__delattr__', '__delitem__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__', '__le__', '__lt__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'active_camera', 'activity_culling',
'activity_culling_radius', 'addObject', 'cameras', 'dbvt_culling',
'drawObstacleSimulation', 'end', 'get', 'invalid', 'lights', 'name',
'objects', 'objectsInactive', 'post_draw', 'pre_draw', 'replace',
'restart', 'resume', 'suspend', 'suspended']
Tuesday, October 2, 12
Scene objects
import bge
control = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
objs = scene.objects
print(objs)
#Output
[Cube.001, Cube, __default__cam__]
Tuesday, October 2, 12
What are keyboard sensor
properties?
cube = objs[‘Cube.001’]
sensor = cube.sensors[‘mykey’]
print(sensor)
['__class__', '__delattr__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__le__', '__lt__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'events', 'executePriority', 'frequency', 'getKeyStatus',
'hold1', 'hold2', 'invalid', 'invert', 'key', 'level', 'name',
'neg_ticks', 'owner', 'pos_ticks', 'positive', 'reset', 'status',
'tap', 'targetProperty', 'toggleProperty', 'triggered',
'useAllKeys', 'useNegPulseMode', 'usePosPulseMode']
Tuesday, October 2, 12
Tuesday, October 2, 12
Press and release akey
import bge
control =
bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
objs = scene.objects The printout occurs twice.
cube = objs['Cube.001'] WHY?
sensor = cube.sensors['mykey']
print(dir(sensor))
Tuesday, October 2, 12
Controllers and pulses
• The python controller gets called every time
a pulse hits it
• The keyboard sensor sends a positive pulse
when the key is pressed
• The keyboard sensor sends a negative pulse
when the key is released
• How to prevent the negative pulse from
having an effect?
Tuesday, October 2, 12
Avoid negative pulse
import bge
control = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
objs = scene.objects
cube = objs['Cube.001'] The printout only occurs
sensor = cube.sensors['mykey'] when the key is pressed
if (sensor.positive):
print(dir(sensor))
Notice the “:” in the “if statement”
Also: lines inside “if statement” all have the same indentation
(imposed by Python)
Tuesday, October 2, 12
Now, avoid keyboard
sensor
• It is possible to have python capture
keyboard events, without a sensor
• Advantage: you can give the Python code to
your friend
• More complicated, so we will avoid this for
now
• Working with Python sensors/actuators is
faster then writing your own, in most cases
Tuesday, October 2, 12
Two Cameras
• Create a cube and a cone
• camCube and camCone are two cameras,
which point to the cube and to the cone
• “akey” will select the camCube
• “bkey” will select the camCone
• First step: create the scene
(two_cams_python.blend)
Tuesday, October 2, 12
Add two camera actuators, one tracking the cube, one
tracking the cone.
Tracking constraints are not maintained in the game engine
Tuesday, October 2, 12
Object
• bge is an object
• bge has the following variables/subclasses
['__doc__', '__name__', 'constraints',
'events', 'logic', 'render', 'texture', 'types']
• Each subclasses has its own subclasses and
so on
• Check out the API documentation
Tuesday, October 2, 12
Control of the Mouse
• Use the MouseLookup.py module
• Download from class website (Oct.2/Oct.
4)
• How does it work?
Tuesday, October 2, 12
Steps
• Parent a camera to a character object
• The camera is the child of the character
• The character is the parent of the camera
• The character is a dynamic object
• rigid might make the object rotate
• Create flow logic for the camera
• All objects can have any name
• Example on next slide
Tuesday, October 2, 12
Properties that control the
Mouselookup script
Code in file: mouselook.py
Execute main function, which is
the entry point:
mouselook.main
The source code is not loaded with Python. If the blender file is
transferred elsewhere, remember to transfer the source files as well
Tuesday, October 2, 12
Try it out!
• http://www.sc.fsu.edu/~gerlebacher/gd/
• mouseCamera.blend
• Activate layer 2 only
• Layer 1 contains the example that comes with mouselook.py
package.
• 0key to see the view from the camera
• pkey to start the game
• use mouse to rotate the view, then ASWD to move the
dynamic object around (and the parented camera will follow)
Tuesday, October 2, 12
Object Properties
How are they used from within Python?
Let us do something not possible without Python ...
Tuesday, October 2, 12
Object Rotation
• Start an object to rotate slowly (keyboard
Rkey)
• Every time the Rkey is pressed, the object
will rotate a little faster
• Without Python, the rotation value in the
motion actuator is a fixed value, which
cannot be changed.
Tuesday, October 2, 12
Constant Rotation
Key ups are ignored
Once the motion actuator is
turned on, motion only stops
when it is deactivated
Tuesday, October 2, 12
No Deactivation
Script: rotate_start_nostop
Better: cube = cont.owner
Usually bad idea to use specific
object names. If the object name
changes, strange things might
happen
The motion actuator is never deactivated
Tuesday, October 2, 12
Properties
Get property ‘acc’
Use default -.01 if non-existent
The property value is always the
same when accessed. How to
change it?
Tuesday, October 2, 12
Update Property
Every time the key is pressed,
rotz increases by 0.01
Keeping the key pressed does not
increase the acceleration
Increase the acceleration by keeping a
key pressed: simply use positive
frequency button
Tuesday, October 2, 12
Global Variables
• I would like to keep track of the total
number of enemies: nb_enemies
• Multiple objects would like to access this
property
• How is this done?
Tuesday, October 2, 12
Method 1
• Choose an object in the game, and give it a property:
‘nb_enemies’
• cube[‘nb_enemies’] = 5
• Another object: hero, needs access to ‘nb_enemies’
• Inside a script for hero,
cube = objects[‘cube’]
nb_en = cube[‘nb_enemies’]
• Disadvantage: Why should this variable be associated with
‘cube’? If all objects need access to this variable, better to have
a more centralized location. Thus the game dictionary.
Tuesday, October 2, 12
Method 2:
Game Dictionary
• bge.logic.gameDict
• Initially, the dictionary is empty
• Initialize variables in the game:
• bge.logic.gameDict[‘nb_enemies’] = 3
• update as needed
• access:
nbe = bge.logic.gameDict[‘nb_enemies’]
Tuesday, October 2, 12
Always sensor: only gets executed once.
Useful for one-time initializations
save and load globalDict
Save variables between game restarts
When is game restarted?
- when player gets killed (same level)
- when moving from one level to the next
Tuesday, October 2, 12
Without save/load
Tuesday, October 2, 12
Change Scenes
• Create two scenes
• Scene1: a cube, light, camera
• health [0-100] property
• Scene2: a cone, light, camera
• Same health property
• Store health in globalDict.
• maintained between scenes
Tuesday, October 2, 12
Cube Scene
Change scene
Cube.001
cube.camera
Tuesday, October 2, 12
Cone Scene
Cone.001
cone.camera
Change scene
Tuesday, October 2, 12
Notes
• Camera trackers are required
• A TrackTo contraint outside the game engine is not respected
inside the game engine
• The globalDict is not destroyed when changing scenes,
however,
• Object properties are reset to initial values when changing
scenes. Thus, the advantage of the globalDict
• What about when a game is restarted?
• Object variables can be initialized from the dictionary in an
initialization python script (once per game, or for each object)
Tuesday, October 2, 12
Blender 2.49a
Tuesday, October 2, 12
Anatomy of a program
(blender 2.49b)
• Import GameLogic # not required
• cs = getCurrentScene()
• objs = cs.objects
• gd = GameLogic.globalDict;
• gd[‘house’] = ‘number of bullets’
gd[‘nb_bul’] = 30
• I stored two variables in the Global Dictionary
• Any object can access the global dictionary, from any
script, from any scene
Tuesday, October 2, 12
Anatomy of a program
(blender 2.59)
• Import bge # not required
• cs = bge.logic.getCurrentScene()
• objs = cs.objects # list of all objects in the scene
• gd = bge.logic.globalDict;
• gd[‘house’] = ‘number of bullets’
gd[‘nb_bul’] = 30
• I stored two variables in the Global Dictionary
• Any object can access the global dictionary, from any
script, from any scene
Tuesday, October 2, 12
Tuesday, October 2, 12
Printing variables
• print(objs)
• parenthesis are very important!!! Not necessary in the
past
• printout can be seen on the console
• on Windows, the console is behind the Blender
window
• on the Mac, one must start Blender from the command
line within a window, which becomes the console
• Printing simplifies debugging
Tuesday, October 2, 12
Arrays
• How to store objects and information
• In Python, use lists
• a = [4,5,6] (all the same type)
• b = [73,‘gordon’, -45.34] (different types)
• a[0]+b[2] ==> 4-45.35 = -41.35
• different types, but integer converted to float
• a[0]+b[1] ==> error (different types)
• string ‘gordon’ cannot be converted to integer
Tuesday, October 2, 12
Accessing properties
con = bge.logic.getCurrentController()
sc = bge.logic.getCurrentScene()
print(sc.objects) # prints to console
ob = sc.objects['Cube']
print dir(ob)
Tuesday, October 2, 12
Hash tables
• Special kind of array
• Array index can be any type (object, string, ...)
• a = {} # dictionary creation
• a[‘gordon’] = 3
• a[5] = ‘blender’
• a[6] = 23.5
• a[‘gordon’] + a[6] ==> 26.5
Tuesday, October 2, 12
Dictionary
is a hash table
GameLogic = bge.logic
con = GameLogic.getCurrentController()
sc = GameLogic.getCurrentScene()
print(sc.objects)
ob = sc.objects[‘Cube’]
print(dir(ob))
a = {}
a[ob] = 3 # argument can be list, integer, float, string
a[sc] = ‘gordon‘ # probably will not work
print(a)
Tuesday, October 2, 12
Example
demonstrate_simple_python_script.blend
Tuesday, October 2, 12
Program name: test_program
import bge
GameLogic = bge.logic
con = GameLogic.getCurrentController()
sc = GameLogic.getCurrentScene()
print(sc.objects)
ob = sc.objects['Cube']
print(dir(ob))
a = {}
Tuesday, October 2, 12
Tuesday, October 2, 12
Storing information in
objects
• # ob name is ‘Cube’
ob = objects[‘Cube’]
• # to see this variable, create obj property
ob[‘newvel’] = 3.4
print dir(ob) # ‘newvel’ appears in the list
• To see object in debug mode (blender 2.49b)
• changed in blender 2.59b
• Game menu -> Debug Properties
• Add Property (in property panel)
Tuesday, October 2, 12
Tuesday, October 2, 12