[SOLVED]Jumping Actor

Hi guys,
So recently I’ve been having some troubles making my character jump.
I thought maybe I could do something like this:

import time

self.blaze.setZ(self.blaze.getZ() + 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() + 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() + 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() + 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() - 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() - 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() - 0.2)
time.sleep(0.2)
self.blaze.setZ(self.blaze.getZ() - 0.2)

Now, Yes. Of course this isn’t my full code,
I did leave out running the game, all my un-necissary things, and my button-pressing for this,
But in this case, Those all work fine, So they are not needed at all.

My problem in this case is this:
I’m trying to make it so when pressing Space, Your character jumps into the air.
time.sleep() being the time slept until the next 0.2 Z’s changed.

However, What really happens is when pressing space,
It sleeps my frames, Not until my next 0.2 Z’s changed. It looks as if my computer freezes for a short time.

How can I make it so my character jumps?

The sleep function will pause your whole program, so it cannot be used in this scenario.

In Panda, you can use a task to perform an action over a period of time. This is described in detail in the Tasks section of the manual, and also used in the Hello World tutorial in the manual where it uses a task to control the movement of the camera.

I tried reading the manual for this,
And to me, it seems too jumbled together.

I learn by reading in step format, or one-at-a-time. Not big long posts that I feel bothered just to look at. Honestly, I tried reading it all (I did), but I just don’t understand it well enough.

Much appreciated for a little more help on what I’m asking for.

I’m inclined to suggest using the manual as a reference, rather than attempting to read through the entire thing: when you have an issue, go to the manual, search the contents for a relevant section and take a look at it.

In this case, the section, as mentioned, would be that on “tasks”

As to your current issue, there are a few approaches that you could take, I think:

  1. You could create a task for each jump.

  2. You could have each object maintain an “update” task, which includes code that performs jumps.

  3. You could have an overall “update” task, which updates a number of objects, including code intended to handle jumping.

  4. You could use an interval to handle jumps.

Which is appropriate for your situation depends, I suppose, on the specifics of that situation. For what it’s worth, I tend to use the third option above, although there are likely advantages to the second and fourth; I’m a little dubious of the likely performance of the first.

By the way, if you want an object to move relative to itself, you should be able to use the following:

myObj.setPos(myObj, xOffset, yOffset, zOffset)

instead of

myObj.setPos(myObj.getX()+xOffset, myObj.getY()+yOffset, myObj.getZ()+zOffset)

You should also be able to similarly move an object relative to another.

Alright, I had read the task section
(seems I wasn’t on the right part of the manual earlier). So this is what I have done for setting my task:

from direct.task import Task
     #Here I imported "Task"

    self.accept("space", self.jumpingAction)
         #Here I added the space button, On press, jumpingAction (the Task) would trigger. I'm not completely sure I did this right.

    def jumpingAction(task):
        if task.time >= 0.0 and task.time <= 2.0:
            return task.cont
            self.blaze.setPos(self.blaze.getX(), self.blaze.getY(), self.blaze.getZ() + 2)
        elif task.time >= 2.0 and task.time <= 4.0:
            return task.cont
            self.blaze.setPos(self.blaze.getX(), self.blaze.getY(), self.blaze.getZ() - 2)
        return task.done
             #Here I tried putting together my Task, something seems to be wrong up here.

This isn’t working, And I don’t really understand why.
This is the error I am getting:

**** End of process output ****
DirectStart: Starting the game.
Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
Traceback (most recent call last):
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 61, in eventLoopTask
    self.doEvents()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 55, in doEvents
    processFunc(self.eventQueue.dequeueEvent())
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 124, in processEvent
    messenger.send(eventName)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 388, in send
    self.__dispatch(acceptorDict, event, sentArgs, foundWatch)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 473, in __dispatch
    method (*(extraArgs + sentArgs))
  File "maincourse3.py", line 129, in jumpingAction
    if task.time >= 0.0 and task.time <= 2.0:
AttributeError: World instance has no attribute 'time'
:task(error): Exception occurred in PythonTask eventManager
Traceback (most recent call last):
  File "maincourse3.py", line 243, in <module>
    run()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\ShowBase.py", line 2630, in run
    self.taskMgr.run()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 502, in run
    self.step()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 460, in step
    self.mgr.poll()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 61, in eventLoopTask
    self.doEvents()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 55, in doEvents
    processFunc(self.eventQueue.dequeueEvent())
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 124, in processEvent
    messenger.send(eventName)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 388, in send
    self.__dispatch(acceptorDict, event, sentArgs, foundWatch)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 473, in __dispatch
    method (*(extraArgs + sentArgs))
  File "maincourse3.py", line 129, in jumpingAction
    if task.time >= 0.0 and task.time <= 2.0:
AttributeError: World instance has no attribute 'time'

**** End of process output ****

Some pointers in what I’m doing would be much appreciated. Thanks!

I see three problems, I believe:

  1. You’re calling the task method rather than passing it to the task manager. Simply calling it isn’t, I believe, the expected usage; instead, pass the method to the task manager and have it perform the call, as shown in the examples on the manual page.

In order to have this work with your keyboard event, I suggest creating another method that handles the event and creates a new task using your current method.

  1. You’ve only given your task method a single parameter. Remember that since you’ve made the method a member of a class the method should automatically get the “world” object passed in as the first parameter. Instead, define it as having two parameters: “self” (the “world” object, passed in automatically) and “task” (the parameter that you’re expecting to have a variable named “time”).

(The examples given on the manual page don’t have that first parameter, I believe, because they are not members of a class, and thus lack the default first parameter.)

  1. You’re returning “task.done” after the first run of your method. Since I presume that you want it to run more than once (since I imagine that you want your object to be updated over several updates), I recommend returning “task.done” only when the method is done with (that is, once the jump is over), and “task.cont” otherwise.

1.) I do have a problem understanding how to “preform the call”. As the example shown doesn’t show this, but rather, a how-to on setting up a task.

With this “another method”, do you mean something like:

self.accept("space", self.setKey, "space-press")

And then setting in after space-press, place “preform the call” or whatever?
(Again, could you maybe show me how I could set this up into: after pressing space, the task is called?)

2.) What would be the point of adding “self, task” in my world class?
I don’t have any tasks set up inside of it, so I’m having troubles understanding that as well.
(Much appreciated on your help).

3.) Thanks for this, I understand now.

  1. If I understand you correctly, “setting up the task” is what you’re supposed to do, not perform the call yourself. The calling of the method is intended to be done by Panda’s task system; hence, I presume, the lack of the call being done in the example.

  2. Hmm… It occurs to me that I’ve likely made an invalid assumption: I presumed that this was taking place in your “world” class, and not some other; my apologies for that.

However, it does seem that this is taking place in some class or other, since you use “self.jumpingAction” rather than just “jumpingAction”.

That said, I’m not suggesting adding “self, task” to the class itself, but rather to the definition of “jumpingAction”.

Simply put, since “jumpingAction” is a method of a class, it will automatically be sent the instance of that class (your “world”, in this case) when it is called; whatever you call the first parameter of the method, it should end up as a reference to your world instance. As a result, any other parameters that you want the method to take - your “task”, for example - are added after that first parameter.

Here’s a little code to give example of both of the above:

    self.accept("space", self.spacePressed)

# Note that jumpingAction now takes two parameters:
#  "self" : The instance of the class, passed in
#           automatically
#  "task" : The task object
def jumpingAction(self, task):
    # Your jumping code here

# The method actually called by the keyboard
# event as specified above.
def spacePressed(self):
    # Add the task to the task manager
    taskMgr.add(self.jumpingAction, "jump")
    # Panda should now call your method automatically!

I love your help, you always seem to know exactly what I need to do: to fix it.

However, I am having one last problem.

I’m trying to make it so that if I press space,
My character goes up 0.2 four times. And then back down 0.2 four times.
Although, what actually happens is that if I press space, I go up 0.2 and it stops.
Then I press it again, and I go up 0.2, and it stops. (Two more times) and then a continuation, from my task
This is what I had (this one was just, press space, and you will only go up 0.2, and then back down to your last position, there is no continuation):

def jumpingAction(self, task):
     if task.time >= 0.0 and task.time <= 1.0:
          self.blaze.setPos(self.blaze.getX(), self.blaze.getY(), self.blaze.getZ() + 0.2)
     elif task.time >= 1.1 and task.time <= 2.0:
          self.blaze.setPos(self.blaze.getX(), self.blaze.getY(), self.blaze.getZ() + 0.2)

And so on…

But if I add:

return task.cont

After the self.blaze.setPos(), I have to press space each time to continue the task.
Which isn’t what I want.

Thanks again for all of the other help, I really, really appreciate it!

Here you have two working samples for very simple jumping.

With a task:
bpaste.net/show/grqIzCTvu8aX9EaHyxYN/

With a sequence of intervals:
bpaste.net/show/MXG32OZzq1i1RKwfM903/

The code should be self-explaining, but if it’s not, feel free to ask.

In effect they’re equivalent.
Sequences and intervals are great for simple stuff and they have easing functions built-in.
Tasks offer more flexibility, but are a bit more complex.

Have a nice day

Hello,
Those are two very well samples.
But I do have another problem… (Sorry)

I would much rather use tasks, Seems more legit for usage. I took the exact code and editted it to fit my character. Here’s the error I got:

DirectStart: Starting the game.
Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
Traceback (most recent call last):
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 61, in eventLoopTask
    self.doEvents()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 55, in doEvents
    processFunc(self.eventQueue.dequeueEvent())
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 124, in processEvent
    messenger.send(eventName)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 388, in send
    self.__dispatch(acceptorDict, event, sentArgs, foundWatch)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 473, in __dispatch
    method (*(extraArgs + sentArgs))
  File "maincourse3.py", line 141, in testPressed
    self.jumpingTask = taskMgr.add(self.jumping, "jumping")
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 366, in add
    task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 377, in __setupTask
    'add: Tried to add a task that was not a Task or a func')
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\directnotify\Notifier.py", line 132, in error
    raise exception(errorString)
StandardError: add: Tried to add a task that was not a Task or a func
:task(error): Exception occurred in PythonTask eventManager
Traceback (most recent call last):
  File "maincourse3.py", line 276, in <module>
    run()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\ShowBase.py", line 2630, in run
    self.taskMgr.run()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 502, in run
    self.step()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 460, in step
    self.mgr.poll()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 61, in eventLoopTask
    self.doEvents()
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 55, in doEvents
    processFunc(self.eventQueue.dequeueEvent())
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\EventManager.py", line 124, in processEvent
    messenger.send(eventName)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 388, in send
    self.__dispatch(acceptorDict, event, sentArgs, foundWatch)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\showbase\Messenger.py", line 473, in __dispatch
    method (*(extraArgs + sentArgs))
  File "maincourse3.py", line 141, in testPressed
    self.jumpingTask = taskMgr.add(self.jumping, "jumping")
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 366, in add
    task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath)
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\task\Task.py", line 377, in __setupTask
    'add: Tried to add a task that was not a Task or a func')
  File "C:\Users\Britany\Desktop\Panda3D\Panda3D-1.7.2\direct\directnotify\Notifier.py", line 132, in error
    raise exception(errorString)
StandardError: add: Tried to add a task that was not a Task or a func

**** End of process output ****

I would way much rather use Tasks, So if you could please explain to me what’s wrong here? That’d be great for future references…

I did, however, try using intervals as well.
I used nearly the same code as in pastebin, and what happens is that my character not only jumps, But he ALWAYS warps back to an X and Y of 0.
(Yes, he still jumps fine.)

Again,
I would MUCH rather learn my mistakes of Tasks, As you’re right, They are more flexible to use.

The line of code that is generating the error is:

self.jumpingTask = taskMgr.add(self.jumping, "jumping")

and the error message is:

StandardError: add: Tried to add a task that was not a Task or a func

So from this we can determine that self.jumping, which is being passed to taskMgr.add, is not a function.
Do you have a function named jumping in your class?

You can find out what self.jumping really is by using a print statement before the line that is generating the error:

print "self.jumping has a value of:", self.jumping
print "self.jumping has a type of:", type(self.jumping)
self.jumpingTask = taskMgr.add(self.jumping, "jumping")

Maybe you have a function named jumping, but then later overwrite that by assigning a different value to self.jumping. Without seeing the rest of the code it is only possible to guess.

Thanks, you were right :astonished: didn’t notice, but it was already being used as a variable.

Pressing space to jump now works, but the problem is now that I only go up about a third what I set it as (6.0 to about 2.0), and my character (after falling back down) will quickly hop up and down repeatedly - non-stop.

Same code used in the pastebin for tasks.

EDIT: Actually, it required me to re-write it out, but I got the bouncing to stop :slight_smile:
But once again, my character doesn’t jump even half what I put down. I tried setting the jump height to a very heigh number, but I still only go up about 2.0 no matter what.
So it’s definitely not the problem that I have the height too low.

Ideas how to fix the jumping height? (height code not changed from pastebin)

EDIT(2): Fixed the height problem. Turns out the self.height variable wasn’t working, oddly. So I just replaced it with an actual number.
However, a new problem occurred. It makes my character warp into the air, then warp back down. Nothing of the sort where you look like you’re moving upward.

There was a small bug in the first sample. I guess you notíced, but I corrected it nonetheless. I also changed the height values to 3.0 just for testing, which seems to work for me.

With Tasks:
bpaste.net/show/C732p9yBH6BwMvNjeBWV/

With Intervals/Sequence:
bpaste.net/show/ysGZeeIKUyYMZWCj5yoV/

For the repositioning you need to use either the smiley node or attach a new node between jumper and the smiley. The problem with the simple PosLerpInterval is that it affects all three values (x,y,z). That’s why I made the jumping a separate node: jumper.node. That node is meant to only go up and down and be the parent of your model you want to jump. Remember, child nodes inherit the transforms of their parent.

Add this line somewhere in your code:

base.accept("a", render.ls)

Given that, every time you press the a-key, you’ll get the whole scene graph printed to the terminal. There you can see what nodes you have and what transforms they obey to.

Wait, so I HAVE to make the actor a node.name? Because I’ve been going with self.blaze rather than node.blaze, figured they’d work the same.
Maybe this could result in one of my problems? How would I fix this without completely removing my actor?
Could I do something like:

node.blaze = self.blaze

If its unnecessary, just say so.

Also, with the “fixed” version, I see no difference in the codes (next to the height change).

Sorry, I don’t understand your problem, I guess. Put your code on a pastebin and try to summarize what’s happening unexpected.

Your example states that your actor is set as a node.smiley or whatever.
I’ve been using self.blaze (in this case, referred to as self.smiley), is their an effect on using self. Or node. For my actor?

Considering I had tried your new version, and it still does not seem to work, then again: I see no reason to switch from self. To node.
Tried your new version, my actor still warps upward, and warps back down to the first position.
Another way to explain would be:
would switching self.blaze to node.blaze have an effect on why my actor is warping rather than “floating” upward and back down?
If not, what’s my problem, then?
Because I saw no difference in the first example in the first post with the examples, than the first example in the second post with the “fixed” examples (beside the self.height change)

Sorry, but I see no such thing in the samples I posted.

An actor is nothing but a special node (NodePath to be precise). You can use it the same way I used smiley. Just replace loader.loadModel(“mymodel”) with Actor(“mymodel”)

Where do you take that “node” from and what is it?

I also changed “jumper” to “jumper.node” in the last few lines, since the Jumper class is no NodePath, but it controls one that is stored in its attribute called “node”.

If you still can’t find the problem, put your code onto a pastebin (e.g. bpaste.net) and let us see.

I did not include my models and actors, or any of that sort, But here’s what i’m using;
bpaste.net/show/XE361ampZrGsCMrC3ZlV/

Ok, first thing I notice is your use of code after a return statement.
After

return task.cont

has been executed, all code that follows in that function will not be run.
Also you use task.done in the middle of a jump.
And you’re using self.rising and self.isRising, which is quite confusing. Try to comment all used variables in init so that you know yourself what to do later on.

As far as I can see you have three states:

  • on ground (able to jump)
  • rising
  • falling

Try to chose your variables in a way so that you can depict that.

Oh and one last tip: play the python interpreter and go through the lines one after another just as pythoh would. You’ll notice that in your current code the block for rising the node is run only once, because the next time the task function is called, the self.isRising attribute is True and only the block for falling gets through.