task mgr problems

im trying to allow key input, but whenever i try to make a task for it i get the error global name KeyInput not defined whenever I try to run it,heres my code

from direct.showbase.ShowBase import ShowBase
from pandac.PandaModules import *
from direct.task import Task
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3
from direct.actor.Actor import Actor

import sys

legoy = 45



class MyApp(ShowBase):

    def KeyInput(task):
            task.accept('escape', sys.exit)
            task.accept('w', self.moveDudeForward)
            return task.cont

   
    def moveDudeForward(self):
        global legoy
        legoy += .5
        return
    def __init__(self):
        ShowBase.__init__(self)

        taskMgr.add(KeyInput, 'ki')

        #hpr (object.setHpr( z, x, y)) rotates around the z, x, and y axis respectively

        self.dude = self.loader.loadModel("Lego_man_CompleteA2.egg")
        self.dude.reparentTo(self.render)
        self.dude.setScale(1.5, 1.5, 1.5)
        self.dude.setPos(-4, legoy, -3)
        self.dude.clearColor()
        self.dude.setColor(1.0, 1.0, 1.0, 1.0)
        self.KeyInput()

        self.land = self.loader.loadModel("Landscape.egg")
        self.land.reparentTo(self.render)
        self.land.setScale(20, 20, 20)
        self.land.setPos(-20, 50, -15)
        self.land.clearColor()
        self.land.setColor(1.0, 1.0, 1.0, 1.0)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)

        base.disableMouse()
        self.camera.setPos(20, 20, 3)
        self.camera.lookAt(self.dude)

app = MyApp()
app.run()

ive tried changing it around for over an hour now, but cant get it to work

Indeed KeyInput isn’t global, it’s inside the class. You should have something like this:

def KeyInput(task):
  [...]

class MyApp(ShowBase):
  [...] 

Or, considering that you’re using self stuff, something like:

class MyApp(ShowBase): 

    def KeyInput(self, task): 
            [...]

    taskMgr.add(self.KeyInput, 'ki')
from direct.showbase.ShowBase import ShowBase
from pandac.PandaModules import *
from direct.task import Task
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3
from direct.actor.Actor import Actor
from direct.showbase import DirectObject

import sys

legoy = 45

def KeyInput(task):
              task.accept('escape', sys.exit)
              task.accept('w', self.moveDudeForward)
              return task.cont


class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.disableMouse()

   
        def moveDudeForward(self):
            global legoy
            legoy += .5
            return

        self.taskMgr.add(KeyInput, 'ki')

        #hpr (object.setHpr( z, x, y)) rotates around the z, x, and y axis respectively

        self.dude = self.loader.loadModel("Lego_man_CompleteA2.egg")
        self.dude.reparentTo(self.render)
        self.dude.setScale(1.5, 1.5, 1.5)
        self.dude.setPos(-4, legoy, -3)
        self.dude.clearColor()
        self.dude.setColor(1.0, 1.0, 1.0, 1.0)

        self.land = self.loader.loadModel("Landscape.egg")
        self.land.reparentTo(self.render)
        self.land.setScale(20, 20, 20)
        self.land.setPos(-20, 50, -15)
        self.land.clearColor()
        self.land.setColor(1.0, 1.0, 1.0, 1.0)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)

        base.disableMouse()
        self.camera.setPos(20, 20, 3)
        self.camera.lookAt(self.dude)

app = MyApp()
app.run()

now the error I get is ‘libpanda.PythonTask’ object has no attribute ‘accept’

Yes, accept is a method of DirectObject, you should create something like the class described in the point 5 here.

now it says no attribute KeyInput…is my indenting off or something? ive been getting allot of indenting errors, Im used to C++ just switched to Python two days ago and Im still getting used to it

from direct.showbase.ShowBase import ShowBase
from pandac.PandaModules import *
from direct.task import Task
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3
from direct.actor.Actor import Actor
from direct.showbase import DirectObject

import sys

legoy = 45

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.disableMouse()

        def KeyInput(self, task):
              task.accept('escape', sys.exit)
              task.accept('w', self.moveDudeForward)
              return task.cont

   
        def moveDudeForward(self):
            global legoy
            legoy += .5
            return

        taskMgr.add(self.KeyInput, 'ki')

        #hpr (object.setHpr( z, x, y)) rotates around the z, x, and y axis respectively

        self.dude = self.loader.loadModel("Lego_man_CompleteA2.egg")
        self.dude.reparentTo(self.render)
        self.dude.setScale(1.5, 1.5, 1.5)
        self.dude.setPos(-4, legoy, -3)
        self.dude.clearColor()
        self.dude.setColor(1.0, 1.0, 1.0, 1.0)

        self.land = self.loader.loadModel("Landscape.egg")
        self.land.reparentTo(self.render)
        self.land.setScale(20, 20, 20)
        self.land.setPos(-20, 50, -15)
        self.land.clearColor()
        self.land.setColor(1.0, 1.0, 1.0, 1.0)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)

        base.disableMouse()
        self.camera.setPos(20, 20, 3)
        self.camera.lookAt(self.dude)

app = MyApp()
app.run()

so how would I set that up in this case? and where in the code would it be located? within MyApp()? or outside?

btw thanks for your help I really appreciate it

Accept is a method of DirectObject, it has nothing to do with Tasks.

You do not need a task to handle events. All you need is a code like this:

class MyApp(DirectObject):
   def __init__(self):
      self.accept("my_message", self.myMethod)

   def myMethod(self):
      print "Me handles events well"

Obviously, you don’t need to inherit from DirectObject. You could as well create a DirectObject class object inside your class and call accept on that object. Like this:

class MyApp():
   def __init__(self):
      self.myDirectObject = DirectObject()
      self.myDirectObject.accept("my_message", self.myMethod)

   def myMethod(self):
      print "Me handles events well too"

Panda will do the rest, you don’t need to invoke accept every frame. You only need to do it once. This method is only meant to tell Panda “react to this event by calling this method, thank you”.

Also, I see you got lost with your indentation.

The first version is closest to what a class’ structure should look like (although, it doesn’t and won’t ever do what you’re trying to do, as I pointed out earlier).

What Yaio meant in his first post here was that you forgot “self.” in front of your KeyInput, not that you should move the KeyInput method anywhere.

Also, note that while you can create a method inside of another method (as you did in the last variant), this method will only be visible inside the scope of the method it was created in. This means, amongst other things, that you cannot pass such method to anything like DirectObject.accept, taskMgr.add etc., because it’s not visible there.

ok Im not sure im following you, my goal is to make it so that if the user presses the ‘w’ key the character model will move, and I wasnt aware I had a method within a method, you talking about my indentation? cause thats bugging the crap outta me, im used to brackets for code grouping and have a hard time following the indentation

with this it says MyApp instance has no attrubute 'moveDudeForward;

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.disableMouse()

        self.accept('escape', sys.exit)
        self.accept('w', self.moveDudeForward)

   
        def moveDudeForward(self):
            global legoy
            legoy += .5
            return

Because it should be indented as it follows:

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.disableMouse()

        self.accept('escape', sys.exit)
        self.accept('w', self.moveDudeForward)

   
    def moveDudeForward(self):
        global legoy
        legoy += .5
        return

Indentation in Python is like the blocks you define in other languages ({} blocks for C/C++/Java/Javascript/… begin-end blocks for Pascal/…).

In your code the moveDudeForward was defined inside the “block” (named “suite” in Python) of init.

well now it will run and it shows the models, but the guy still doesnt move

from direct.showbase.ShowBase import ShowBase
from pandac.PandaModules import *
from direct.task import Task
from direct.interval.IntervalGlobal import Sequence
from panda3d.core import Point3
from direct.actor.Actor import Actor
from direct.showbase import DirectObject

import sys

legoy = 45

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.disableMouse()

        self.accept('escape', sys.exit)
        self.accept('w', self.moveDudeForward)

        self.dude = self.loader.loadModel("Lego_man_CompleteA2.egg")
        self.dude.reparentTo(self.render)
        self.dude.setScale(1.5, 1.5, 1.5)
        self.dude.setPos(-4, legoy, -3)
        self.dude.clearColor()
        self.dude.setColor(1.0, 1.0, 1.0, 1.0)

        self.land = self.loader.loadModel("World1.egg")
        self.land.reparentTo(self.render)
        self.land.setScale(40, 40, 40)
        self.land.setPos(-20, 50, -15)
        self.land.clearColor()
        self.land.setColor(1.0, 1.0, 1.0, 1.0)

        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)

        self.camera.setPos(20, 20, 3)
        self.camera.lookAt(self.dude)
        
    def moveDudeForward(self):
        global legoy
        legoy += 0.5
        return

app = MyApp()
app.run()

is it not checking for the event every frame? or not checking for the correct input?

You should set the position with the new value when the method is called:

    def moveDudeForward(self):
        [...]
        self.dude.setPos(-4, legoy, -3)
        [...]

oh yay now it works, thanks guys, now I can experiment with it

is there a way to make the axis of his movement relative to which direction he is facing? or is it that way already? nvm definately isnt already

		float radx = 0,rady = 0;
		int h = 0;
		double fi = 0, fideg = 0;
		fi = this->maincharacter.get_hpr().get_x();
		h = (fi/360);
		h = fi - (360 * h);
		if (h < 0) {
			h *= -1;
		}
		fi = h;
		fideg=fi * (3.141592653589 / 180.0);
		radx=dist*cos(fideg);
		rady=dist*sin(fideg);

This is something I wrote in C++ for that purpose, it uses simple mathematics, with a rad / grad calculation to let the character always face in the direction he is moving.

It has some failsafes included: It checks for negative bearings, and corrects them as well as it rounds of your bearing, in case there are fractional digits.
(This helped for my field test :wink: )

radx and rady are your values that need to be added to your characters position. (Of course “dist” is the distance of which he should be moved :wink: )

It should be easy to convert this to python :wink: