An open collection of best practice for BGE

Purpose of this thread
Originally opened to hold my own thoughts regarding best practice in BGE, this thread is magically attractive for a lot of good hints and tips.

So everyone can add own thoughts in here. When you do that please keep in mind:

  • :stuck_out_tongue: these are no laws,
    [LIST]

  • this are guide lines

  • it is better to think about it and keep it in mind

  • rather than blindly follow them

  • :rolleyes: if you want to contribute, add one post with your thoughts

  • you can edit and extend it later with new ideas

  • if you change your mind later, you can change your post

  • :cool: provide some reasons, why you prefer a solution

  • this helps to judge if it fits into the situation and

  • this helps to compare different solutions

  • :ba: please do not discuss in this thread, if you disagree or want to discuss

  • open a new thread at the BGE discussion forum

  • invite the BA users you want to discuss with by private message

  • as usual discuss with respect!

  • add the (objective) results of the discussion in your own post

[/LIST]
Thanks to everyone who posted here.
Thanks to everyone who is reading it (you).
Welcome to everyone who learned something from it (it includes me :D).

PS: Rate the thread - so everyone knows it is an important one!

Monster’s best practice for BGE

This post holds my thought about how to create efficient games with the BGE.
It is meant to be a personal use. This are my rules and you do not need to follow them. Finally it is more a guide than a must. Maybe you find it usefull too ;).

Avoid unnecassary triggering of controllers
:Performance (high relevance)

  • belongs to true and false pulse settings of sensors
    [LIST]

  • controllers are executed everytime they are triggered by sensors

  • not executing a controller (regardless of its type) is simply faster than executing

  • belongs to sensors with general setting (like all keys) where a Python controller checks for a few key presses.

  • the controller is also triggered on other keys than the checked ones which wasts processing time

  • a balance between performance and flexibility is required.

  • “all keys” hides what keys are checked and what not (increases complexity).

  • “all keys” is fine if the controler deals with all keys of the game.

[/LIST]
Bad Example:

  • true pulse on any sensor triggering an AND controller which activates a motion actuator. Why: The motion actuator needs just one activation and runs until receiving a deactivation. Any other true or false pulses waste controller time.

Good Example:

  • no pulse on the sensor triggering an AND controller which activates a motion actuator.

Exit Python controllers as soon as possible
: Performance (high relevance)
: Complexity (high relevance)

  • belongs to Python code
    [LIST]
  • running Python code eats time (also compiled code eats time :wink: )
  • reducing executed code as much as possible = faster
  • if you know that you do not want to proceed with processing, exit rather than perform more processing
    [LIST]
  • after that the checked the assumptions are valid(e.g. sensors positive)
  • there is no need for large (and confusing) if
then
else statements
  • indentation is reduced (which improves readablity)

[/LIST]

[/LIST]
Examples:

  • checking sensors to be positive - the check fails -> but the controllers continues to assign local variables, extract data - simply does nothing that “matters” outside of the controller BETTER exit after the check failed
  • parsing through a complete list until its end - but found the results already - BETTER break after finding a result

Use actuators rather than Python controller performing the same tasks
: Performance

  • belongs to tasks that will be processed over more than one frame
    [LIST]
  • this does not belong to tasks that need adjustment by the Python controller at each frame (e.g. changing an actuators parameter dependent on the distance, speed etc.).
  • actuators are compiled code and therefore faster executed than Python code
  • actuators can remain active longer than just one frame - Python controllers needs to be triggered at every frame to remain active

[/LIST]
Examples:

  • rotating an object with a Python controller. BETTER use a motion actuator. It can do the same and is much more efficient.
  • rotating an object with a Python controller dependent on the position of another object. It is fine: There is no actuator doing this.

Disable heavy sensors that are not required all the time
: Performance (medium relevance)

  • belongs to sensors with heavy processing time that are not required all the time
    [LIST]
  • ray, near, radar - each sensors needs to perform additional physics processing
  • fine are mouse over, collision etc. they just use data that is produced anyway (by physics)
  • it is a question of amount
  • several heavy sensors take sums up much, while several light sensors can share the same data (e.g. ray through mouse cursor, keyboard keys)
  • disable sensors by switching states - sensors not connected to an controller of the active state are nor evaluated

[/LIST]
Meaningfull names for game objects, meshes, sensors, actuators, IPO’s, textures etc.
: Ccomplexity (high relevance)

  • It is really difficult to understand a .blend file where everything is called Plane.xxx or Cube.xxx and it is clearly somthing else.
  • Naming increases readablity a lot. You wouldn’t even need to open a logic brick if the names already says what it is doing.
  • I recommend to think about Naming conventions before you start
    [LIST]
  • it difficult to change everything later
  • e.g. All object names start with upper case, all sensor names start with “s”

[/LIST]
Keep it simple
: Complexity (high relevance)

  • this is not easy to do, but helps a lot.
  • Somehow it is difficult to explain :confused:
  • one controller - one function (on high level meaning)

Examples:

  • one controller to switch on Mouse cursor
  • one controller to get the window size (might be triggered more than once!)

Keep it independent
: Complexity
: Reusability

  • one controller - one function (on high level meaning)
  • do only depend on other objects if you really need to (maybe better identify objects by property than name)

Avoid configuration in Python code
: Usability (high relevance)
: Complexity

  • belongs to parameters used in python controllers
    [LIST]
  • do not force users to edit Python code (bad, bad, bad)!
  • configuration parameters are important for flexibility/reusability
  • use properties rather than hardcoded values
  • hardcode default values only
  • clearly document what properties are used and what are expected

[/LIST]
Example:

  • the VehicleWrapper script - contains a lot of hardcoded values at various places - this forces users to dig into code - BETTER use properties - some values can be directly taken from the scene (e.g. wheel positions)

Maintain version numbers if you published files
: Organization

  • belongs to .blend files, Python code etc. everything that is published
    [LIST]
  • if planned to be published add a version number, date and the author
  • when published increase the version number of you local file
  • this allows you to distinguish between different files from several locations.
  • this information can be in a text file, properties or whatever.
  • this gets important latest when more than one user is involved.

[/LIST]
Avoid repetition of static information examination
: Performance
: Useablity

  • belongs to frequent data examination of not changing data
    [LIST]
  • e.g. locating an object in the scenes object list by name if there is just one and never disappears
  • look for it once, store the result (in a property, dict etc.)
  • the search takes more time than directly grapping from the storage
  • remember: properties can hold references to game objects
  • it gets more important on higher number of objects, higher execution frequence of the python code

[/LIST]
Avoid dependency on object names
: Usebility
: Flexibility

  • belongs to Python code
    [LIST]
  • Object names can be different in other files.
  • Objects could be renamed while developing the game
  • better use properties
    [LIST]
  • they can be assigned to multiple objects
  • multiple properties can be assigned to one object

[/LIST]

[/LIST]
Try to follow a coding standard
: Organization
: Readability

  • defining yourself a coding standard
    [LIST]

  • let your code looking consistant through all your files

  • avoids confusion because of different writing styles in one file

  • looks just more professional

  • you can find suggestions and reasons at the Style Guide of Python Code
    [/LIST]

<S> Monster,

Very interesting write down.

I need to check my project accordingly.

Thanks

I would also add for python-related stuff.

Try to avoid a lot of specialized code for similar objects if possible, especially if you’re using large scripts to command large amounts of logic. If possible, use the same loops or variables for those tasks if you can and try to do more with the code you have.

This will mean less code so things are easier to read and you don’t have as many variables and properties lying around in the code or sitting in the properties list.

TL;DR: How I structure my games, with an example.

I feel that this would be a good place to post my best practice also (hope you don’t mind Monster!), however, I’m going to focus on my game structure; in particular the code structure of my games. As monster said, this isn’t necessarily how you have to do it, its just what I’ve found to work best for me.

Anyway, over the years I’ve been refining my structure game-by-game (although I scrapped most of those games) and I feel I have something clean, simple and nice.

Essentially, the bulk of code is taken up by either objects representing scenes or objects. I’m therefore going to whisk (whisk - yeah right!) over how I handle scenes and objects.

Each scene has a ‘core’ set up that I use. It involves a ‘control’ empty (I usually name this control scene_name). On this empty I have a timer property, to keep track of the game time and an always sensor connected to a single python controller, handling the scene’s code. But before I get to that, I generally set up my folder structure like this:

Root\
└â–șGame.blend
└â–șGame.py
└â–șdata\
└â–șlib\
  └â–șLevel.py
  └â–șObjectBase.py
  └â–șPlayer.py
  └â–șMob.py

So I tuck away all the code, textures, sounds and linked files in the data and lib folders.

Game.py handles the initialisation of the game, and contains generic game wide functions that may have to be accessed from different scenes (e.g, save_game(), load_game(), load_lib()). A Typical Game.py in one of my projects may look like this:

# Game.py
import sys

import bge

time = 0.0
time_since_last_frame = 0.0

def init():
    # Tell the python interpreter to look in my lib folder for python scripts
    sys.path.append(bge.logic.expandPath("//lib"))

    # A good place to enable mouse visibility
    bge.render.showMouse(True)

    # Set the default starting scene
    bge.logic.getCurrentScene().replace('level')

def main():
    # A good place to put any code that needs to be called each frame
    # In this case, its only going to update the time attribute of my Game module
    global time, time_since_last_frame
    time_since_last_frame = time - bge.logic.getCurrentController().owner['time']
    time = bge.logic.getCurrentController().owner['time']

Game.py is called from an initialisation scene, the only function of this scene is to call Game.init() so I have an empty with an active python controller set to module with “Game.init” in the text field and a camera. And thats it.

Other scenes’ code is called from that scenes ‘control’ object, like I mentioned before. On the scenes control object, in the python controller (which is set to module) I put in ‘Scene.init’, which gets changed to ‘Scene.main’ at run time.

An example of what a scene’s code in a game may look like is this:

# Level.py
import bge

import Game
from Player import Player
from Mob import Mob

class Level:
    def __init__(self):
        self.player = Player()

        # Populate the level with some enemies
        self.mobs = []
        for n in range(15):
            self.mobs.append(Mob())
            self.mobs[n].worldPosition = [bge.logic.getRandomFloat()*10-5, bge.logic.getRandomFloat()*10-5, 0]

    def handle_player(self):
        # update the player, or call game over scene
        if self.player.is_alive:
            self.player.main()
        else:
            bge.logic.getCurrentScene().replace('game over dude')

    def handle_mobs(self):
        # update or delete mob entities
        for mob in self.mobs:
            if mob.is_alive:
                mob.main()
            else:
                mob.endObject()
                self.mobs.remove(mob)

    def main(self):
        self.handle_player()
        self.handle_mobs()

def init(cont):
    cont.owner['time'] += Game.time
    Game.main()
    cont.owner['scene'] = Level()
    cont.script = 'Level.main'

def main(cont):
    Game.main()
    cont.owner['scene'].main()

You may have noticed two objects that I created in there, Player and Mob. They are objects which represent game objects. Heres what they may look like:

# Player.py

import bge
from mathutils import Vector

import Game
from ObjectBase import ObjectBase

class Player(ObjectBase):
    def __init__(self):
        ObjectBase.__init__(self, 'player')
        self.worldPosition = [0,0,0]
        self['player'] = True
        self.hp = 100
        self.is_alive = True

        self.WALK_FORCE = 300.0
        self.WALK_SPEED = 15.0

    def handle_movement(self):
        keyboard = bge.logic.keyboard
        
        fx = 0.0
        fy = 0.0
        
        if keyboard.events[bge.events.WKEY] == bge.logic.KX_INPUT_ACTIVE:
            fy -= self.WALK_FORCE * Game.time_since_last_frame # as to not make acceleration frame rate dependent
        elif keyboard.events[bge.events.SKEY] == bge.logic.KX_INPUT_ACTIVE:
            fy += self.WALK_FORCE * Game.time_since_last_frame
        if keyboard.events[bge.events.DKEY] == bge.logic.KX_INPUT_ACTIVE:
            fx -= self.WALK_FORCE * Game.time_since_last_frame
        elif keyboard.events[bge.events.AKEY] == bge.logic.KX_INPUT_ACTIVE:
            fx += self.WALK_FORCE * Game.time_since_last_frame
            
        if fx and fy:
            fx *= 0.707
            fy *= 0.707
        
        self.applyForce([fx,fy,0])
        
        # Limit velocity
        vel = self.worldLinearVelocity
        z = vel.z
        vel.z = 0
        if vel.magnitude &gt; self.WALK_SPEED:
            vel.magnitude = self.WALK_SPEED
            vel.z = z
            self.worldLinearVelocity = vel

        # Orientate player to it's velocity vector
        self.alignAxisToVect(self.worldLinearVelocity, 1, 0.2)
        self.alignAxisToVect([0,0,1], 2, 1)

    def handle_attack(self):
        # Attacks for this example game are triggered by space, and are a hit when the player is behind a mob with its back turned.
        keyboard = bge.logic.keyboard

        if keyboard.events[bge.events.SPACEKEY] == bge.logic.KX_INPUT_ACTIVE:
            ray = self.rayCastTo(self.worldPosition + Vector([0,1,0]) * self.worldOrientation)
            if ray:
                if ray.get('mob'):
                    player_dir = self.worldOrientation[1]
                    mob_dir = ray.worldOrientation[1]
                    if player_dir.angle(mob_dir) &lt; 90:
                        ray.is_alive = False

    def main(self):
        self.handle_movement()
        self.handle_attack()

        if self.hp &lt;= 0:
             self.is_alive = False
# Mob.py

import bge
from mathutils import Vector

import Game
from ObjectBase import ObjectBase

class Mob(ObjectBase):
    def __init__(self):
        ObjectBase.__init__(self, 'mob')
        self['mob'] = True
        self.is_alive = True

        self.last_direction_update = 0.0

        self.WALK_SPEED = 100.0
        
        self.DIRECTION_UPDATE_FREQUENCY = 0.05
        self.DIRECTION_UPDATE_STRENGTH = .2

    def handle_direction_update(self):
        if Game.time - self.last_direction_update &gt; self.DIRECTION_UPDATE_FREQUENCY:
            self.applyRotation(Vector([0,0, bge.logic.getRandomFloat()*self.DIRECTION_UPDATE_STRENGTH-self.DIRECTION_UPDATE_STRENGTH/2])*self.worldOrientation)
            self.last_direction_update = Game.time
            
    def handle_collision_avoidance(self):
        ray = self.rayCastTo(self.worldPosition + Vector([0,1,0]) * self.worldOrientation)
        if ray:
            if ray.get('ground') or ray.get('mob'):
                self.applyRotation([0,0, 3.14], True)

    def handle_movement(self):
        self.worldLinearVelocity = Vector([0, -self.WALK_SPEED * Game.time_since_last_frame, 0]) * self.worldOrientation
        
    def handle_attack(self):
        ray = self.rayCastTo(self.worldPosition + Vector([0,0.5,0]) * self.worldOrientation)
        if ray:
            if ray.get('player'):
                ray.hp -= 10

    def main(self):
        self.handle_direction_update()
        self.handle_collision_avoidance()
        self.handle_movement()
        self.handle_attack()

You may have again noticed the use of a previously-not-mentioned object, an ObjectBase, this simply maps all KX_GameObject functions and attributes to the inheriting class.

It may not be entirely obvious, but this code is for a game which the player has to press spacebar behind the ‘mobs’ to kill them whilst avoiding getting hit by the mobs themselves. The whole structure may be obsessive here (Two objects, one scene?) and better suited for a larger example, but I guess you’re getting sick of my post by now ;).

I call this game “The Mob Job”, and you can see the code in action if you want to. For the example I chucked in a title screen and game over scene using the bgui so you can see the benefit of creating a class for each scene - it allows it to inherit another class, in this case bgui.System.

So, if you’re still with me after all that code and babble it might be nice to summarise with a simple run down of the order of execution and a note on OOP.

You’ll notice that there are many main() functions in my structure, however there are only three levels, or tiers, of them. First comes Game.main(), which encapsulates the game wide code. Next comes Scene.main() which handles all code at a scene level and than Object.main() which handles the code down at object level. I generally try not to cross those three levels, for instance, in my Level.py I called the game over scene from there and not in the actual player’s code. This helps to keep things more simple, neater and adds to you games structure.

1 Like

This thread should be sticky!

monster, andrew-101
 LEGENDARY. Thank you very much for your insights, examples, etc. This answers alot of questions i have been pondering myself, and confirms a few ideas i had as to how to best modify the structure of my BGE hacks :slight_smile:

i second for sticky! (or at least update your ‘Useful Threads’ post Monster! :wink: )

And rest/sleep a little!
Monster you never sleep?
Thanks anyway! :wink:

I noticed that this thread was focused on making efficient scripting for games, but I have other tips that may help boost the efficiency of games, that aren’t directly coding related. So to be begin:
CalebR’s tips for game processing efficiency:

Physics:
Tip 1, you should minimize the number of ‘active’ physics objects in the scene. Especially if you’re planning on adding a lot of physics objects.
Instead, I recommend having static physics objects will a small ghost bounds to detect collisions. When the static object’s bounds collide with an active physics object (character, vehicle, etc), the static object is deleted, and an identical object with active (aka Rigid-body) physics is created in its place. After a delay (or once the object stops moving), the active object is deleted, and an identical object is created in its place (or the original location of the first object).
Basically, all ‘physics’ objects are static until they are needed.

This seems like a lot of work - and it is - but it will minimise the amount of processing speed being wasted by physics (especially when there are a lot of objects in scene). I’m fairly sure this is more efficient than simply disabling and enabling physics. You can make it even more efficient by reducing the physics object’s bounds to as few colliding polygons as possible.

Lighting:
Minimise the number of lights in a scene. These can really drag down the framerate, especially lamps with real-time shadows.

Animating: Minimise the number of armatures in a scene. Every armature in scene will use up computational power classified as ‘Scenegraph’. If you have a lot of objects with armatures, they will drain the framerate, whether or not an animation is playing.
Tip 1: For simple objects. For objects with only one moving part, such as cogs, doors, and the like, I recommend removing armatures, and instead use IPOs, or motion. Offset the centre of objects so they pivot correctly (eg. most doors must pivot on one side, not their centre). If an object consists of a variety of independent parts (eg cogs and wheels), this object should be subdivided into separate moving parts.

Tip 2: Complex objects. For complex objects that aren’t always animated (instead triggered by some event, then stop), I recommend a solution similar to my physics tips.
The object should start with no armature. Once triggered by an event, the object is deleted, and replaced by a visibly identical object with an armature. Once this object has played its animation, it is reverted back to a identical static object (with no armature). The problem with this tip is that it assumes the animated object will revert back to its original posture after animation (eg. Machine whirs and spins, but animation’s end is identical to its start).
For objects with that change posture after they finish playing their animation (eg. an extending bridge), the animated object should transform into a static object that has the identical appearance to the last animated frame of the animated object. So to explain using the extending bridge example: 1) short bridge with no armature --> 2) bridge with armature playing extension animation --> 3) extended bridge with no armature.
However, this won’t work with dynamically animating objects (eg. bridge can stop extending at any point).

Conclusion: This is all I can think of for now. Unfortunately, whilst these tips are processing-speed efficient, they aren’t time efficient to implement (This is because every physics object will need a static and active alternative, and animated objects will require a static (non-armature), and animated (with armature) alternative).

Hopefully, if anyone else has any helpful tips, I’m sure this would be the place to post them.
PS. I hope you don’t mind me encroaching on your thread Monster.

This is a basic game design optimization that is used in both 2D and 3D games today. The idea’s simple - when an object is off-screen, there’s no reason to update / animate it anymore. Some games delete the object when it’s off-screen - this is fine for certain objects, like bullets or particle effects, but important objects like pick-ups, enemies, and NPCs can’t be deleted. However, this practice can still be used to optimize CPU power for those instances that use it.

To delete objects that are outside the camera’s view (in Blender 2.5), you can use this:


from bge import logic

cont = logic.getCurrentController()
obj = cont.owner
cam = sce.active_camera
if not cam.pointInsideFrustum(obj.position):
     obj.endObject()

Similarly, to only have an object run code if it’s inside of the camera’s view, you can use this:


from bge import logic

cont = logic.getCurrentController()
obj = cont.owner
cam = sce.active_camera
if cam.pointInsideFrustum(obj.position):
     ### Run your code here ###

This way, the object will only run its code if it’s onscreen. Otherwise, it won’t impact the CPU much at all. I’m working on optimizing my 2D Animated Sprite code, and this is probably one of the optimizations that I will make to get the sprites running faster. By the way, the suggestions posted here are great, especially Andrew’s about optimizing your Python code structure. It’s really professional!

I’ve seen a lot of people do a simple piece of code like this:

variable = variable + 1

It’s just easier to use:

variable += 1

I hit the post limit at post #1 already. So here the hints continue:

Make decorators No-Collision

belongs to game objects without any interaction (Nothing will ever collide with it)
[LIST]

  • static game objects are included into the collision calculation.
  • if the game object logically never receives a collision it does not need to be included into the collision calculation and saves a lot of processing time.
  • I recommend to set No Collision when the game is nearly done, but before the final tests. If you do it earlier you might change your mind and add collisions later. If you do it later the final test might fail and you do not see it.

[/LIST]

Bad Example:

  • All interaction is limited to an area. Objects outside of the area (e.g. clouds, stones, walls) are static or (even more worse) dynamic.

Good Example:

  • All interaction is limited to an area. Objects outside of the area (e.g. clouds, stones, walls) are No-Collision as there is no interaction.

The chance is that quite a few users of the BGE have probably used Blender in some other context beforehand. Thus, there are some important performance notes:
Firstly, individual objects have “individual geometry”. Even instanced gameobjects and linked duplicates only copy the initial geometry on load of the game. For linked duplicates, this speeds up the loading time significantly with larger numbers of objects.
For each individual object, the lighting, physics and logic has to be processed. Because of the inevitable processing overhead required to first check if these calculations must be done, in many cases you will run into slow down:

Reducing processing of separated geometry:
To avoid having to calculate this overhead for multiple objects, first identify if they are individual? Are there groups of objects that won’t move or will collide as one object? Are there groups of objects in the same place that are “detail objects”? If so, you can reduce the amount of processing by joining this geometry. This means that the lighting is done once for each object, thus only once rather than n*object_number.
This takes more processing time for “one object” but there is only one object in total, and thus the overhead is lessened.

Timesteps
In the game engine, we run in a system which is governed by ‘timesteps’. This means that each tick aims to last a certain time step, if force framerate is enabled. If the processing for one tick takes longer than the intended timestep, problems of “Lag” start to occur. The odd spike in processing won’t make a whole lot of difference, but if it occurs regularly within one second (the frame rate is frames / second), then you will see slowdown more visually. Users HATE slowdown. They’d prefer to operate smoothly at 30fps than at a range between 40 and 60 fps. The other problem is that the logic tic rate is tied to the frame rate - thus if the framerate slows down so does the logic processing and, unfortunately, so does the physics tic rate. Therefore having a consistent frame rate is important, especially for multiplayer.
It is therefore important to look at reducing the processing that occurs each frame. For example, particle systems don’t need to be updated every tick, as they are just small visual effects, so perhaps every other tick or every two ticks. At 60 fps, a tick is 1/60th of a second, so a difference of one or two ticks is barely noticeable.

A good thing to know would be that Blender’s very own features/options (such as textures used as skyboxes from Blender’s options) tend to outperform their faked versions (such as using a sphere with a texture as a skybox) :yes:

@SolarLune: Doesnt Blender already does that?