Bullet Physics + world + Tasks

Ive been messing with bullet and ran into an issue i couldne seemto find a fix for (i tried this thread [passing args to tasks) thinking that was my issue - to no avail) Before i get into my rambling rant of whats wrong this time - heres my code -

##############################################
#                 #IMPORT#                   #
##############################################
from direct.showbase.ShowBase import ShowBase
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *
from panda3d.core import Texture
#Bullet Physics Engine
from panda3d.core import Vec3
from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletPlaneShape
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletBoxShape

##############################################
#         #External Class IMPORT#            #
##############################################
from GameLight import *
from Player import *
from Level import *
from Collisions import *
from shapeGenerator import *

##############################################       
#                #NEW CLASS#                 #
##############################################
class initGame(ShowBase):
    
    world = BulletWorld()
    world.setGravity(Vec3(0, 0, -9.81))
        
    def __init__(self):
        ShowBase.__init__(self)
        
        ######################################################
        #keeps the game running the same speed on all systems#
        FPS = 60##############################################
        globalClock = ClockObject.getGlobalClock()############
        globalClock.setMode(ClockObject.MLimited)#############
        globalClock.setFrameRate(FPS)#########################
        #keeps the game running the same speed on all systems#
        ######################################################
        
        self.disableMouse()
        self.loadPlayer()
        self.loadLevel()
        self.createLight()
        
        taskMgr.add(self.update(), 'update')
        
    def loadPlayer(self):
        self.player = Player(self.world)
        
    def loadLevel(self):
        self.level = Level(self.player.np, self.world)
        
    def createLight(self):
        self.lightSource = GameLight(self.player.np)
        
    def update(task):
        dt = globalClock.getDt()
        world.doPhysics(dt)
        
        return task.cont
            
app = initGame()
app.run()

I cant seem to pass self/world to the task manager. any ideas/something im obviously overlooking?

Perhaps you meant to put “self.world = BulletWorld()”, and “self.world.setGravity(…)” in the constructor?

Also, you forgot to put the “self” in the definition of the “update” method, and you also forgot to put the self in “self.world.doPhysics(dt)”.

im not defining them in any function so itd be the same as defininsg it with self IN a function :stuck_out_tongue: and as far as putting self in the task as self.world ive tried, doesnt work D: just says self is undefined

edit - justto make sure imnot making i fool of myself i tried your siggestions

##############################################
#                 #IMPORT#                   #
##############################################
from direct.showbase.ShowBase import ShowBase
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *
from panda3d.core import Texture
#Bullet Physics Engine
from panda3d.core import Vec3
from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletPlaneShape
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletBoxShape

##############################################
#         #External Class IMPORT#            #
##############################################
from GameLight import *
from Player import *
from Level import *
from Collisions import *
from shapeGenerator import *

##############################################       
#                #NEW CLASS#                 #
##############################################
class initGame(ShowBase):
        
    def __init__(self):
        ShowBase.__init__(self)
        
        ######################################################
        #keeps the game running the same speed on all systems#
        FPS = 60##############################################
        globalClock = ClockObject.getGlobalClock()############
        globalClock.setMode(ClockObject.MLimited)#############
        globalClock.setFrameRate(FPS)#########################
        #keeps the game running the same speed on all systems#
        ######################################################
        
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -9.81))
        
        self.disableMouse()
        self.loadPlayer()
        self.loadLevel()
        self.createLight()
        
        taskMgr.add(self.update(), 'update')
        
    def loadPlayer(self):
        self.player = Player(self.world)
        
    def loadLevel(self):
        self.level = Level(self.player.np, self.world)
        
    def createLight(self):
        self.lightSource = GameLight(self.player.np)
        
    def update(task):
        dt = globalClock.getDt()
        self.world.doPhysics(dt)
        
        return task.cont
            
app = initGame()
app.run()

and got the same results

another edit - the self is nto defined error is coming from taskMgr.add(self.update(), ‘update’) not self.world.doPhysics(dt) i just found out. and i tried taskMgr.add(self.update, ‘update’) to no avail as well

As I pointed out in my previous point, you missed the “self” argument in this line:

    def update(task):

It should be:

    def update(self, task):

Another mistake is this line:

taskMgr.add(self.update(), 'update') 

You are passing the return value of the method “initGame.update” as first parameter to the task manager. What you should pass is the method itself:

taskMgr.add(self.update, 'update')

A little explanation about Python: the way you originally create the BulletWorld is troublesome. You create a “class member” and not an “instance member”. This means the instance is created when the class is loaded (!) and not when the instance is created (init). Other languages often call this a “static” member.

While it is possible to access class member using the “instance.member” syntax (i. e. self.world) it is good style to access them by means of “class.member” syntax (i. e. initGame.world).

The problematic part is that this instance of BulletWorld is not released when the initGame instance is released, but when the class is unloaded. Cleaning up - e. g. upon reload of a saved game - can be problematic. I don’t say it’s impossible, you just have to pay close attention to when objects get released.

Here is an (NOT RECOMMENDED!) way of modifying the original code you posted. It’s just to teach a bit of Python.

class initGame(ShowBase):
       
    world = BulletWorld()
    world.setGravity(Vec3(0, 0, -9.81))

    def __init__(self):
        ShowBase.__init__(self)
        ...
        taskMgr.add(initGame.update, 'update')

    def __del__(self):
        taskMgr.remove('update')
       
    @staticmethod
    def update(task):
        dt = globalClock.getDt()
        initGame.world.doPhysics(dt)
        return task.cont
           
app = initGame()
app.run()

Say I through them in the init method, would there be. More straightforward and future proof(loading saved games etc) of doing it?

marking as closed :slight_smile: thanks for all the help :smiley:

I should stop talking about “alternate” ways. This just confuses people.

The recommended way is to use instance members (aka “self.world”). And keep setup and teardown symmetrical.