Jumping in Panda3D[Solved]

from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor
from direct.showbase import DirectObject
from direct.task import Task
from panda3d.core import Fog
from panda3d.core import CollisionTraverser, CollisionHandlerPusher, CollisionSphere, CollisionNode, CollisionTube
from direct.showbase.ShowBase import ShowBase
from direct.gui.DirectGui import DirectButton, DirectWaitBar
from direct.gui.DirectGui import *

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        self.gameOverScreen = DirectDialog(frameSize=(-0.7, 0.7, -0.7, 0.7),
                                           fadeScreen=0.4,
                                           relief=DGG.FLAT)
        self.gameOverScreen.hide()
        self.label = DirectLabel(text="Game Over!",
                            parent=self.gameOverScreen,
                            scale=0.1,
                            pos=(0, 0, 0.2))
        self.label.hide()

        self.cTrav = CollisionTraverser()
        self.pusher = CollisionHandlerPusher()

        self.bar = DirectWaitBar(pos=(0, 0, -0.7))
        self.bar['range'] = 100
        self.bar['value'] = 100

        self.taskMgr.doMethodLater(1, self.life, "life-")


        # Load the environment model.
        music = self.loader.loadMusic('/Users/38167/PycharmProjects/viren/venv/minecraft.mp3')
        music.setLoop(True)
        music.setVolume(1)
        music.play()
        self.environ = self.loader.loadModel("environment")
        self.environ.reparentTo(self.render)
        tex = self.loader.loadTexture('/Users/38167/PycharmProjects/viren/venv/Png.png')
        self.environ.setTexture(tex, 1)
        # We do not have a skybox, so we will just use a sky blue background color
        self.setBackgroundColor(0.53, 0.80, 0.92, 1)

        myFog = Fog("Fog Name")
        myFog.setColor(0, 0 , 0)
        myFog.setExpDensity(0.01)
        self.render.setFog(myFog)

        self.pandaActor = Actor("models/panda-model",
                                {"walk": "models/panda-walk4"})
        self.pandaActor.setScale(0.005, 0.005, 0.005)
        self.pandaActor.reparentTo(self.render)

        colliderNode = CollisionNode("player")
        colliderNode.addSolid(CollisionSphere(0, 0, 345, 900))
        collider = self.pandaActor.attachNewNode(colliderNode)

        self.pusher.addCollider(collider, self.pandaActor)
        self.cTrav.addCollider(collider, self.pusher)
        self.pusher.setHorizontal(True)
        

        wallSolid = CollisionTube(-20.0, 0, 0, 20.0, 0, 0, 0.2)
        wallNode = CollisionNode("wall")
        wallNode.addSolid(wallSolid)
        wall = self.render.attachNewNode(wallNode)
        wall.setY(20.0)

        wallSolid = CollisionTube(-20.0, 0, 0, 20.0, 0, 0, 0.2)
        wallNode = CollisionNode("wall")
        wallNode.addSolid(wallSolid)
        wall = self.render.attachNewNode(wallNode)
        wall.setY(-8.0)

        wallSolid = CollisionTube(0, -20.0, 0, 0, 20.0, 0, 0.2)
        wallNode = CollisionNode("wall")
        wallNode.addSolid(wallSolid)
        wall = self.render.attachNewNode(wallNode)
        wall.setX(20.0)

        wallSolid = CollisionTube(0, -20.0, 0, 0, 20.0, 0, 0.2)
        wallNode = CollisionNode("wall")
        wallNode.addSolid(wallSolid)
        wall = self.render.attachNewNode(wallNode)
        wall.setX(-20.0)

        self.accept("arrow_up", self.Move)
        self.accept("arrow_up-repeat", self.Move)
        self.accept("arrow_up-up", self.stopMove)
        self.accept("arrow_right", self.Move2)

        self.taskMgr.add(self.camera_task, "camera")

    def Move(self):
        self.WalkSound = self.loader.loadSfx("/Users/38167/PycharmProjects/viren/venv/walk.mp3")
        self.pandaActor.setY(self.pandaActor, -200)
        self.pandaActor.setPlayRate(2, "walk")
        walk = self.pandaActor.getAnimControl("walk")
        self.WalkSound.play()
        if not walk.isPlaying():
            self.pandaActor.loop("walk")

    def stopMove(self):
        self.pandaActor.stop("walk")

    def Move2(self):
        self.pandaActor.setH(self.pandaActor, -90)

    def camera_task(self, task):
        self.camera.setPos(self.pandaActor.getX(), self.pandaActor.getY() + 15, 5)
        self.camera.lookAt(self.pandaActor)
        return Task.cont

    def life(self, task):
        if (self.bar['value'] >= 0):
            self.bar['value'] -= 1
        else:

            self.gameOverScreen.show()
            self.label.show()
            return task.done

        return task.again


app = MyApp()
app.run()

Here is my current code. How do I implement a feature that will allow jumping? I tried to look at other sources but it gave me a 404 error. Srry if this has been said before. :grin:

Thanks!
EDIT1: this is what I have so far

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


def jumpingAction(self, task):
    dt = globalClock.getDt()
    self.jumpSpeed -= 10*dt
    self.pandaActor.setZ(self.pandaActor, self.jumpSpeed )

def spacePressed(self):
    
    self.taskMgr.add(self.jumpingAction, "jump")

Don’t really know where to go beyond this point so if anyone has any ideas please leave them below. Thanks again!

You can answer yourself, if you have implemented the movement of X and Y, then I think rethinking the rest is not difficult. Yes, you need mathematics, the concept of time, also a coefficient of 9.8 :slight_smile:

Can you please walk me through it?

As with horizontal movement, you will likely want to control the character’s vertical position.

  • When the player indicates that the character should jump, give the character a positive vertical speed
    • Over time, reduce this speed according to gravity, allowing it to fall into the negative (so that it eventually produces downwards movement).
  • Then, each frame, update the character’s vertical position according to this vertical speed.
  • And finally, when the character hits the ground, set the vertical speed to zero.
    • (How you define “hitting the ground” might depend on your game.)

Oh, and don’t forget to disable jumping while the character is in the process of jumping! (If you don’t, the player may be able to “fly” indefinitely by repeatedly hitting the “jump” button!)

Could you possibly give me some samples or a source to get me going?
Thanks again for your time!

I presume that you know how to position the object, so I won’t cover that.

Let’s assume that you’re accepting some key-press for jumping (as you’re doing for moving). In the method related to that, you might set something like this:

self.jumpSpeed = 5
(The actual value might vary according to the specifics of your game–indeed, from what I’ve gathered of movement in your game, it might be a good idea to use a rather higher value. Play around with numbers until you find something that works for your game.)

Then, in a task, you might have something like this:

dt = globalClock.getDt()
self.jumpSpeed -= 10*dt

Again, 10 is an arbitrary value; adjust to your game.

I’m using the delta-time (dt; the amount of time since the previous frame) above so that the maths adjusts to the frame-rate of your game. If your game has a fixed frame-rate, you can omit that.

You can then use this jump-speed when setting your character’s position.

As to hitting the ground: If your game-world takes place on a flat plane, you can perhaps just check whether the character is below whatever height you consider to be “ground”. If your game-world has uneven ground (as in the “Roaming Ralph” example), you might want to use collision-detection, or a vertical ray-cast, to determine whether the character has “hit the ground”.

Thanks for your help, do you know any sources I could use that also has jumping?

Not offhand, I think–have you tried searching the forum? A quick search seems to indicate that it’s been asked before, and while I don’t know whether any of those threads has a good answer, one of them might.

ok thanks will look into it!

1 Like
1 Like

(Note that there seems to be a slightly simplified version a few posts below the first post in that thread.)

So this is what I have so far, sorry if it’s not that much:

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


def jumpingAction(self, task):
    dt = globalClock.getDt()
    self.jumpSpeed -= 10*dt

def spacePressed(self):
    
    self.taskMgr.add(self.jumpingAction, "jump")

What else should I add or edit? Thanks!

Well, think about what a jump involves: when you jump, you push off the ground suddenly. You then move up into the air; all the while gravity accelerates you downwards, until your speed is directed towards the ground. This results in you falling–until you hit the ground, stop falling, and the jump is over.

Looking at your code, right now you’re handling the “gravity” part of that: you’re altering the jump-speed over time. The rest is yet to be added!

On a technical side, your task likely won’t work properly, as you’re not returning one of the expected values in it. You also don’t seem to have a means of stopping the “jumping task” once its purpose is done, or of preventing multiple presses of the space-bar from causing multiple jumps in mid-air.

I’m not really sure how to accomplish that, could you give me some examples? I know that I have to do things related to the z axis but I’m not sure how to do it.

Thank you!

You do it in the same way as you did it on the horizontal axes: myNodePath.setZ(<z-value>) or myNodePath.setZ(<someNodePath>, <z-value>), where <someNodePath> might be “myNodePath”, which would place the “myNodePath” relative to itself.

More generally, is there anything that wasn’t covered in the above thread?

How to stop it when it’s already being called, to prevent jumping. I’m not so sure how to do that. Also would it be like?:

self.pandaActor.setZ(self.pandaActor, self.jumpSpeed )

EDIT: So with self.jumpSpeed instead of the -200?

Fair enough!

To the first: There are ways–you can call “taskMgr.remove” to remove a task, as I recall–but I would suggest doing it in a slightly different way: instead of starting a new task for every jump, just have one task that always runs, but that only applies its logic when you indicate that the player is jumping.

To the second, similarly, I would suggest having an indication of whether the player is jumping or not. Then simply check this in the method called when the space-bar is pressed, and only run the jumping logic if it indicates that the player isn’t jumping.

The right basic idea, indeed–just with a variable instead of a static “-200”.

would I do this then?

self.pandaActor.setZ(self.pandaActor, self.jumpSpeed )
self.accept("space", self.spacePressed)


def jumpingAction(self, task):
    dt = globalClock.getDt()
    self.jumpSpeed -= 10*dt
    self.pandaActor.setZ(self.pandaActor, self.jumpSpeed )

def spacePressed(self):
    
    self.taskMgr.add(self.jumpingAction, "jump")

This is what I have now, not really sure where to go next. If anyone can help me out it would be great!

What I suggest is going back to my earlier posts–in particular, these two:

(Click on the “up arrow” at the top-right of each of those quotes to go back the post itself, allowing you to read them with proper formatting.)

Go through each thing that I mention, ignoring any bits that you’ve already done (like using a variable instead of a static number–well done on that). Focus on a single statement, and figure out how to implement that.