FPS Camera

I have been faffing around trying to get a semblance of control over the camera and have stripped the code found in the bump map example/sample to get it. I can now move the camera forward and back and strafe left and right while turning the camera with the mouse. I thought I’d submit it for comment and, hopefully, feedback that might make the code better. Also, can someone explain what a dir is… it is highlighted in the code. You can save the code into the bump map example and it will run. ‘e’ forward, ‘f’ back, ‘a’ strafe left, ‘space’ strafe right.

from panda3d.core import loadPrcFileData

import direct.directbase.DirectStart
from panda3d.core import WindowProperties
from panda3d.core import AmbientLight,PointLight
from panda3d.core import TextNode
from panda3d.core import Point3,Vec3,Vec4
from direct.task.Task import Task
from direct.showbase.DirectObject import DirectObject
import sys,os


class FPSCamera(DirectObject):

    def __init__(self):

        self.room = loader.loadModel("models/abstractroom")
        self.room.reparentTo(render)

        # Make the mouse invisible, turn off normal mouse controls
        base.disableMouse()
        props = WindowProperties()
        props.setCursorHidden(True)
        base.win.requestProperties(props)

        # Set the current viewing target
        self.focus = Vec3(0,0,0)
        self.heading = 0
        self.pitch = 0
        self.mousex = 0
        self.mousey = 0
        self.last = 0
        self.keys = [0,0,0,0]

        # Start the camera control task:
        taskMgr.add(self.controlCamera, "camera-task")
        self.accept("escape", sys.exit, [0])
        self.accept("e", self.setKeys, [0, 1])#forward
        self.accept("e-up", self.setKeys, [0, 0])
        self.accept("f", self.setKeys, [1, 1])#back
        self.accept("f-up", self.setKeys, [1, 0])
        self.accept("a", self.setKeys, [2, 1])#strafe left
        self.accept("a-up", self.setKeys, [2, 0])
        self.accept("space", self.setKeys, [3, 1])#strafe right
        self.accept("space-up", self.setKeys, [3, 0])
        
        # Add an ambient light
        alight = AmbientLight('alight')
        alight.setColor(Vec4(0.4, 0.4, 0.4, 1))
        alnp = render.attachNewNode(alight)
        self.room.setLight(alnp)

    #switch upon which buttons are pressed with if statements 
    def setKeys(self, btn, value):
        self.keys[btn] = value

    #main loop
    def controlCamera(self, task):
      md = base.win.getPointer(0)
      x = md.getX()
      y = md.getY()
      if base.win.movePointer(0, 100, 100):
        self.heading = self.heading - (x - 100) * 0.2
        self.pitch = self.pitch - (y - 100) * 0.2
      if (self.pitch < -45): self.pitch = -45
      if (self.pitch >  45): self.pitch =  45
      base.camera.setHpr(self.heading,self.pitch,0)
      elapsed = task.time - self.last
      dir = base.camera.getMat().getRow3(1)
      if (self.last == 0): elapsed = 0
      if (self.keys[0]):
        dir = base.camera.getMat().getRow3(1) #0 is x, 1 is y, 2 is z,
        self.focus = self.focus + dir * elapsed*40 #gives speed
        base.camera.setPos(self.focus - (dir*5))
      if (self.keys[1]):
        dir = base.camera.getMat().getRow3(1)
        self.focus = self.focus - dir * elapsed*40
        base.camera.setPos(self.focus - (dir*5))
      if (self.keys[2]):
        dir = base.camera.getMat().getRow3(0)
        self.focus = self.focus - dir * elapsed*20 
        base.camera.setPos(self.focus - (dir*5))
      if (self.keys[3]):
        dir = base.camera.getMat().getRow3(0)
        self.focus = self.focus + dir * elapsed*20
        base.camera.setPos(self.focus - (dir*5))
              
      if (base.camera.getX() < -59.0): base.camera.setX(-59)
      if (base.camera.getX() >  59.0): base.camera.setX( 59)
      if (base.camera.getY() < -59.0): base.camera.setY(-59)
      if (base.camera.getY() >  59.0): base.camera.setY( 59)
      if (base.camera.getZ() <   5.0): base.camera.setZ(  5)
      if (base.camera.getZ() >  45.0): base.camera.setZ( 45)
      self.focus = base.camera.getPos() + (dir*5)
      self.last = task.time
      return Task.cont

play = FPSCamera()

run()

The ‘code’ tags didn’t work for me. You should edit the post and try to get them to.

Sorry about that… I supposedly formatted the code as code when I submitted it. I have removed the tags.

My communication attempt failed wretchedly.

What I meant was, the forum software is capable of preserving spacing for blocks of text that are marked as code, and in Python it’s important to preserve spacing. You didn’t seem to be aware of that capability, given some moderate assumptions.

We can’t copy and paste your code as it is, although there is an apparent meaning. You hadn’t and still haven’t availed yourself of the forum’s ability to preserve the original meaning, so we don’t know it. And that information should be much closer to your hands now.

Just select your code in the editor and click on the button.

I will do exactly as you ask if you can tell me how to turn on HTML tags… they are off. The reason the code originally had the code tags literally in place was because I had done as you say… selected the text and hit the code button.

Thanks castironpi… all sorted.

There are check boxes underneath the text entry area. One says, “Disable BBCode in this post”. Uncheck it, and verify to the left that “BBCode is ON”.

BBCode: discourse.panda3d.org/faq.php?mode=bbcode

nice piece of code over here - just what a strange keymapping: normally it is used the classic WASD or the arrow keys but anyhow is not very important.

walking sideways is buggy.
you first jump in the opposite direction a bit and move forward.

You’re right. Funny thing is if you change the first instance of
dir = base.camera.getMat().getRow3(1) to
dir = base.camera.getMat().getRow3(0)

the jumping changes to the forward motion. Frankly I am at a loss, I have googled to understand how Panda works with openGL, or the primitive matrices that the code must grab, so that I can get a handle on why the code works, or doesn’t as the case may be, but nothing. SDL might be a lot of banging your head against brick walls, but at least I can understand how the camera moves via translations and rotations.

I found the easiest way to handle camera is to handle a PandaNode, which the camera is parented to.
Also using martices, vectors or even other low-level items often tends to failures. Simple np.setPos(np, x, y, z) works best in most cases, IMHO.

Rokmonkey has provided just such code under the Scripting Issues folder.