Quick reference guide for gamelogic python programming.

Hint: copy the code below to a file (e.g.: bgeQuickRef.py) and save in the template folder (…\2.60a\scripts emplates</i>).
All examples are entirely drawn from a number of working and tested scripts of mine.
Corrections and comments are welcome.

### bgeQuickRef for blender 2.60a - version: 12 nov 2011 ###
''' Change Log:
 10 nov 2011:
    added Keyboard and Joystick inputs
 12 nov 2011:
    keyboard inputs testing logic modified
    mappings for hat button DnLeft/ DnRight swapped
    improved readability
import bge #, GameKeys    # bge.logic is equivalent to GameLogic
from math import pi, degrees, radians, sin, cos, tan#, asin, acos, atan, atan2, sqrt
from mathutils import Matrix, Vector
#from numpy import array, matrix
#import numpy as np

'''Game Objects acquisition:'''
    # objs = bge.logic.getCurrentScene().objects
    # obj = objs['Cube']
    # print(objs)  # list all objects
'''Getting & testing Keyboard Inputs:'''
    # sens = obj.sensors['SensorName']
    # if sens.positive:
        # code for True
    # else:
        # code for False
'''Getting status of an Always Sensor named Reset:'''
    ''' deprecated method:'''
    # reset = obj.sensors['Reset'].getKeyStatus(134)# where 134 = ASCII for "del" key
    ''' preferred method: (needs importing GameKeys)'''
    #reset = obj.sensors['Reset'].getKeyStatus(GameKeys.DELKEY)
    '''...in both cases:'''
    # if reset == bge.logic.KX_INPUT_JUST_ACTIVATED:
        # code for reset
    '''Sensors states:
    bge.logic.KX_SENSOR_INACTIVE = 0
    bge.logic.KX_SENSOR_JUST_ACTIVATED = 1
    bge.logic.KX_SENSOR_ACTIVE = 2
    bge.logic.KX_SENSOR_JUST_DEACTIVATED = 3'''
'''Getting Joystick inputs (may change with joystick model):'''
    # StickAndThr = obj.sensors['PitchRollThr'] #Joystick sensor named 'PitchRollThr', Event Type = Axis
    # StickButtons = obj.sensors['Buttons'] # Joystick sensor named 'Buttons', Event Type = Button
    # StickHat = obj.sensors['Hat'] # Joystick sensor named 'Hat', Event Type = Hat
    # [fiStick, tetStick, thrStick] = StickAndThr.axisValues
    # triggerBtn = StickButtons.getButtonStatus(0)  # Boolean (True/False)
    # stripedBtn = StickButtons.getButtonStatus(1)  # Boolean (True/False)
    # lowBtn = StickButtons.getButtonStatus(2)      # Boolean (True/False)
    # topBtn = StickButtons.getButtonStatus(3)        # Boolean (True/False)
    # hatDir = StickHat.hatSingle                    # Integer (see below)
    '''    Mapping for Hat button:
        - Center/Up/Right/Dn/Left ==&gt; 0/1/2/4/8;
        - UpRight/DnRight/DnLeft/UpLeft ==&gt; 3/6/12/9;
''' Scaling pitch/roll stick to +/-60 deg:'''
    # scale = 60./32768
    # StickX = -scale*fiStick      # degrees (notice sign inversion)
    # StickY = scale*tetStick    # degrees
'''Scaling throttle input within range [0-1]:'''
    # Throttle = (32768 - thrStick)/65536 # Throttle units (notice sign inversion)
''' Getting orientation Matrices & position Vectors:'''
    # Mw = obj.worldOrientation
    # Ml = obj.localOrientation
    # vw = obj.worldPosition
    # vl = obj.localPosition
    # phi, tet, psi = obj.worldOrientation.to_euler()  # get euler angles [rad]
''' Rotating & moving objects (angles in rad):'''
# Incremental:
    # obj.applyRotation([p*dt, q*dt, r*dt], local = false)
    # obj.applyMovement([Vx*dt, Vy*dt, Vz*dt], local = false)
# Absolute:
    # obj.localOrientation = [phi, tet, psi]
    # obj.worldOrientation = [phi, tet, psi]
    # obj.localPosition = [NewX, NewY, NewZ]
    # obj.worldPosition = [NewX, NewY, NewZ]
WARNING: Matrix and vector multiplication are in reversed order, i.e.:
    - M1*M2 returns M2*M1;
    - M*v returns M'*v;
where M, M1, M2 are square matrices, M' is the transpose of M, and v is a vector
The product of a 3x3 matrix by a 3x2 matrix returns a 3x3 matrix (!!!).
If M represents a rotation matrix, then M*v returns v rotated counterclockwise
The orientation matrix of obj2 in the reference frame of obj1 is given by:
    # M = M1.transposed()*M2,where:
    # M1 = obj1.worldOrientation
    # M2 = obj2.worldOrientation
'''    - Method 1: assigning to a gameobject: '''
    # var1 = obj['prop1']  # retrieve from previous iteration
    # var1 = var1 + 1 # update
    # obj['prop1'] = var1 # save for next iteration
'''    - Method 2: define variables in an initialization script TO BE EXECUTED FIRST AND ONLY ONCE.
    The script should be triggered by an always sensor put on top of the sensor list, and with both "level triggering" buttons disabled.
    This latter method is more convenient when one or more initialization values are the result of calculations, rather than constants.'''
# Initialization script:
    # import bge
    # bge.var1 = InitVal
    # bge.var2 = bge.var1/2
    # ...
# Main script:
    # import bge
    # v1 = bge.var1 # retrieve stored variables
    # v2 = bge.var2
    # ... (process all variables as necessary)
    # bge.var1 = v1 # save for next iteration
    # bge.var2 = v2
'''Converting euler rates to local axis angular rates:'''
# direct formulas:
    # p = phip - sin(tet)*psip
    # q = cos(phi)*tetp + cos(tet)*sin(phi)*psip
    # r = -sin(phi)*tetp + cos(tet)*cos(phi)*psip
# inverse formulas:
    # phip = p + sin(phi)*tan(tet)*q + cos(phi)*tan(tet)*r
    # tetp = cos(phi)*q - sin(phi)*r
    # psip = sin(phi)/cos(tet)*q + cos(phi)/cos(tet)*r
''' Timing software execution:'''
    # from time import clock
    # start = clock()
    # ... (code)
    # end =  clock()
    # print(end-start) # returns elapsed time in seconds (floating)
''' Changing the sampling period (default=60 FPS): Properties =&gt; World'''


I really like this idea!

the corners ,my nightmare!:mad:

Updated today (nov 10th, 2011).


Useful script! put more in!:eyebrowlift:

what is this?

Very useful, cheers, someone should write a Blender/python API xD ( I mean as in a hardcopy, not the website :stuck_out_tongue: )

There is a documented version of the entire api, but it is not fully up to date in some cases -> There are literally Hundreds of attributes, if not thousands of classes, functions, etc.

Sorry, for me this looks like a random collection of quick and dirty code placed in comments.

Templates are not the best container for code snippets.
Code snippets should be small and understandable.

Better use the API as reference and type your own code for your own needs.
The existing templates gamelogic_module.py and gamelogic_basic.py provide a good start.

“…dai diamanti non nasce niente, dal letame nascono i fior.”, (F. De André, italian poet)

i.e.: “…nothing grows from diamonds, flowers grow from manure.”


I agree.
It will grow and and will spread around. I assume you want the flowers to grow.

As a good gardener :wink: you do not use cheap manure.
As a good gardener you prefer the flowers over the weeds.
As a good gardener you “guide” your flowers to beauty.
As a good gardener you start a new garden with the seeds of you best flowers.

Why I think it is quick&dirty:
The way it is written - I would write code if I just want to complete it as fast as I can (quick&dirty).
It is nothing wrong with it … if you build a prototype.
In a larger system it will bite you in the back.
It is hard to explain to others.
It is easy to forget what it was supposed to do.
When you publish quick&dirty code it looks like a by-product of something better.

I assume you are still learning Python. Please take this comments as a help.

This are my general critics:

  • Commented code has no syntax highlighting.
  • Usually I would not need everything that is in this code. I would need a small part of it and in different order (code snippets).
  • I miss a structure for orientation to get the snippets. The break lines help but they are not enough.
  • It is hard to find something. It is quite long. It is hard to see the dependencies.
  • It takes some time to remove the comment characters and the not needed code.
  • A lot of the formulas would be better placed in functions.

Code critics:
In a template (even in a snippet) there is no reason to use cryptic names (e.g. lowBtn, Mw, tetp). You type it once and you can copy&paste it several time.

sens = obj.sensors['SensorName']
if sens == True:

  • sens is a sensor not a boolean value -> use sensor.positive
  • “== True” is not necessary. “sensor.positive” represents a boolean value already.

    reset = obj.sensors['Reset'].getKeyStatus(134) 
    if reset == True:

  • 134 means nothing, better use GameKeys.DELKEY. It is much better readable
  • getKeyStatus() does not return a boolean value. It returns a status.
  • The status should be compared against GameLogic.KX_INPUT_JUST_ACTIVATED and GameLogic.KX_INPUT_ACTIVE.

Please follow one naming convention (e.g. all variables start with lower case). Please check the recommendations of PEP#008. It tells you very good reasons to do that.

That is all for now.
I hope it helps you.

Thank you Monster for your suggestions.
I will introduce them in the next issue of my guidelines. Excluding those concerning gardening, but only because they’re out of topic.

That said, I realize now that the idea of suggesting to use this text as a “script template” was unfortunate.
Rather, it should be considered as a series of informal rules to be followed when approaching bge programming.

My intention was in fact mainly to share some notes I wrote for my use as a remind of the conventions used in the bge, according to the trial-and-error experience I made with gamepython.
So the file contains information concerning, for example, methods for moving and rotating objects, a topic about which, in my opinion, there is some confusion and/or misinformation in the community.

I am a noob in python/blender coding (this awareness being strongly reinforced by Monster’s comments) and my (commented) code is not optimized. Nevetheless it should be kept in mind that:

  • the examples are entirely drawn from a number of working and tested scripts of mine;
  • if you want to use this text as a template (as I do) of course you can. But don’t tell software purists;
  • this software has to control a computer game, at the end of the day, not a safety critical spatial mission.


Updated today (12-nov-2011).