How to use threads in python scripts in Blender Game Engine

Hello everyone!

I need some help again.

Are there any disadvantages to using threads in the game engine?

I receive information from a serial connection and then according to the value received I apply rotation to an object. I already did it in a script, but now I want to put this logic in one thread so that the data reception and the application of this logic would be separated from the others.

So I did it:

import serial #Comunicacion Serial
import bge #Funciones propias de blender
import bpy
import math
from bpy.props import *
from mathutils import Vector
from threading import Thread

class lerDados(Thread):
 def __init__ (self, num):
   Thread.__init__(self)
   self.num = num


 def run(self):
  ser = serial.Serial('COM5', baudrate = 9600, timeout = 1)     
  while (True):       
   #ser = serial.Serial('COM5', baudrate = 9600, timeout = 1)

   leitura = ser.readline() 
   leitura = leitura.decode("utf_8") 
   if leitura[0] == "&" :

     leitura = leitura[1:] #Eliminamos el detector de errores
     leitura = leitura[:-1] #Eliminamos el final de linea
     leitura = int(leitura)
   
     if (leitura >= 180 and leitura <= 360):
      leitura = (leitura - 360) 
    
  
     angulo = math.radians(leitura) 

     
     cont = bge.logic.getCurrentController()
     objects = cont.owner  
    
     main = bge.logic.getCurrentScene()
     cont = logic.getCurrentController()
     objects = cont.owner
     main = logic.getCurrenteScene()

     timao = main.objects["Timao"]
     leme = main.objects["Leme"]
     angulo_text = main.objects["angulo_text"]
     texto = str(angulo)
    
     angulo_text.text = texto

     rotation = timao.localOrientation.to_euler()
     rotation_leme = leme.localOrientation.to_euler()
    
     rot_degree = math.radians(5)
    
     rotacao_atual = rotation.y 
     rotacao_atual_leme = rotation_leme.z
   
     angulo = round(angulo, 1)
     rotacao_atual = round(rotacao_atual, 1)
     rotacao_atual_leme = round(rotacao_atual_leme, 1)
      
     #print('angulo e: ', angulo)
     #print('rotacao e: ', rotacao_atual)
    

    
     
     if (rotacao_atual != angulo):
      if (angulo >= 0):
        if (rotacao_atual < angulo):
          if ((angulo -rotacao_atual) > math.radians(180)):   
            rotation.y -= rot_degree   
          else:
            rotation.y += rot_degree   
        elif (rotacao_atual > angulo):
            rotation.y -= rot_degree        
                 
                     
      elif (angulo < 0):
       if(rotacao_atual > 0):
        if(rotacao_atual < angulo):
            rotation.y += rot_degree 
        elif(rotacao_atual > angulo):
             rotation.y += rot_degree
       elif(rotacao_atual < 0):
          if(rotacao_atual > angulo):
             rotation.y -= rot_degree   
          elif(rotacao_atual < angulo):
              rotation.y += rot_degree        
                 
     timao.localOrientation = rotation


     if (rotacao_atual_leme != angulo):
      if (angulo >= 0):
        if (rotacao_atual_leme < angulo):
           if ((angulo -rotacao_atual_leme) > math.radians(180)):   
              rotation_leme.z -= rot_degree   
           else:
               rotation_leme.z += rot_degree   
        elif (rotacao_atual_leme > angulo):
          rotation_leme.z -= rot_degree        
                 
                     
      elif (angulo < 0):
          if(rotacao_atual_leme > 0):
            if(rotacao_atual_leme < angulo):
              rotation_leme.z += rot_degree 
            elif(rotacao_atual_leme > angulo):
                rotation_leme.z += rot_degree
          elif(rotacao_atual_leme < 0):
             if(rotacao_atual_leme > angulo):
               rotation.y -= rot_degree   
             elif(rotacao_atual_leme < angulo):
               rotation_leme.z += rot_degree        
                 
     leme.localOrientation = rotation_leme

   ser.close()
                 

                 
receber = lerDados(None)
receber.start()

Then I get the error:

File “main.py”, line 35, in run
SystemError: bge.logic.getCurrentController (), this function is running outside the python controllers context, or blenders internal state is corrupt.

Google do not find any reference to this error, I suppose it is because when calling the thread context has been lost. But aren’t threads mini-processes within a larger process, where they share memory space? Why then do I see this error?

Rather than trying to modify things in the BGE from inside the thread, save the changes you want to make to a property on the class. Then, set up a script that runs every pulse that checks your class for changes, and applies those changes to the objects in the BGE.

By the way, the thread won’t automatically stop when you stop the BGE. I would suggest making a script that is bound to the ESC (or whatever you use to close the BGE) that shuts down the thread before stopping the BGE.

don’t put bge functions inside a thread, keep it pure python.

1 Like

you can take a look at this (th-test.blend (469.9 KB) ) you might find some useful information.