trembling camera problem[solved]

Hi people, I´m still trying to use classes in my Panda3D game, but it looks I haven´t been 100% sucefull since my camera is acting weird.

When The camera rotates(using Q and E keys), it is nice and smooth, but when the charater walks(up,down,left or right) the camera starts trembling until the player stops moving.

Also, when left/right keys are pressed, the charater appears to be moving around the camera, which is not right. When I deactivate my camera(thus using Panda3D default one) the left/right issue don´t happen anymore.

I need some serious help here, since I have been stuck days in these problems. If you need more details to help me, say. Code Below:

OBS: The movimentation is kingdom hearths based.

import direct.directbase.DirectStart

from pandac.PandaModules import PandaNode, LightNode, TextNode, NodePath, Camera
from pandac.PandaModules import Filename
from pandac.PandaModules import PointLight, AmbientLight
from pandac.PandaModules import LightRampAttrib, AuxBitplaneAttrib
from pandac.PandaModules import CardMaker
from pandac.PandaModules import Shader, Texture
from pandac.PandaModules import Point3,Vec2,Vec3,Vec4,BitMask32
from pandac.PandaModules import *

from direct.task import Task
from direct.actor import Actor
from direct.interval.IntervalGlobal import *
from direct.showbase.DirectObject import DirectObject
from direct.filter.CommonFilters import CommonFilters
from direct.gui.OnscreenText import OnscreenText

import random, sys, os, math

base.accept("escape", sys.exit)

base.setFrameRateMeter(True)

render.setAntialias(AntialiasAttrib.MAuto)

# Discovers in which directory this program is
MYDIR=os.path.abspath(sys.path[0])
MYDIR=Filename.fromOsSpecific(MYDIR).getFullpath()

#Player
class Avatar(DirectObject):
    def __init__(self):
        self.states = {"right":0, "left":0, "forward":0, "backward":0}
        self.isMoving = False         
        self.loadActor()
        self.eventCapture()
        
        taskMgr.add(self.move, "move avatar")
        taskMgr.add(self.anim, "anim avatar")
        
    def loadActor(self):
        self.player = render.attachNewNode("player")
        self.playerActor = Actor.Actor("models/player")
        self.playerActor.setScale(0.1,0.1,0.1)
        self.playerActor.reparentTo(self.player)
        self.playerActor.loop("still")
        
    def eventCapture(self):
        self.accept( "d", self.changeState, ["right",1] )
        self.accept( "a", self.changeState, ["left",1] )
        self.accept( "w", self.changeState, ["forward",1] )
        self.accept( "s", self.changeState, ["backward",1] )
                
        self.accept( "d-up", self.changeState, ["right",0] )
        self.accept( "a-up", self.changeState, ["left",0] )
        self.accept( "w-up", self.changeState, ["forward",0] )
        self.accept( "s-up", self.changeState, ["backward",0] )

    def changeState(self, key, value):
        self.states[key] = value

    def move(self, task):
        elapsed = globalClock.getDt()
        
        if (self.states["right"] != 0):
            self.playerActor.setH(90)
            self.player.setH(base.camera.getH())
            self.player.setX(self.player, +(elapsed*5))
             
        if (self.states["left"] != 0):
            self.playerActor.setH(-90)
            self.player.setH(base.camera.getH())
            self.player.setX(self.player, -(elapsed*5))
            
        if (self.states["forward"] != 0):
            self.playerActor.setH(180)
            self.player.setH(base.camera.getH())
            self.player.setY(self.player, +(elapsed*5))
            
        if (self.states["backward"] !=0):
            self.playerActor.setH(0)
            self.player.setH(base.camera.getH())
            self.player.setY(self.player, -(elapsed*5))
            
        return Task.cont 
                   
    def anim(self,task):
        if (self.states["forward"]!=0) or (self.states["left"]!=0) or (self.states["right"]!=0) or (self.states["backward"]!=0):
            if self.isMoving is False:
                self.playerActor.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.playerActor.loop("still")
                self.isMoving = False
        
        return Task.cont

#Level
class Level():
    def __init__(self,player):
        self.player=player
        self.loadScenario()
        
    def loadScenario(self):
        self.Level = loader.loadModel("models/peaks")
        self.Level.reparentTo(render)
        self.Level.setScale(10,10,10)
        self.Level.setPos(0,0,-9)
        playerStartPos = self.Level.find("**/start_point").getPos()
        self.player.setPos(playerStartPos-0.5)

#Camera
class Camera(DirectObject):
    def __init__(self,player):
        self.player=player
        
        self.eventCapture()
        self.states = {"cam_left":0, "cam_right":0}
        
        base.win.setClearColor(Vec4(0,0,0,1))
     
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        self.isMoving = False

        base.disableMouse()
        base.camera.setPos(self.player.getX(),self.player.getY()+10,2.5) 
       
        taskMgr.add(self.camtrack, "Cam track")        
                  
    def eventCapture(self):
        self.accept( "q", self.changeState, ["cam_left",1] )
        self.accept( "e", self.changeState, ["cam_right",1] )
                
        self.accept( "q-up", self.changeState, ["cam_left",0] )
        self.accept( "e-up", self.changeState, ["cam_right",0] )

    def changeState(self, key, value):
        self.states[key] = value
        
    def camtrack(self,task):
        self.elapsed = globalClock.getDt()
        base.camera.lookAt(self.player)
        
        if (self.states["cam_left"] != 0):
            base.camera.setX(base.camera, +(self.elapsed*20))

        if (self.states["cam_right"] !=0):
            base.camera.setX(base.camera, -(self.elapsed*20))
 
        camvec = self.player.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        
        if (camdist > 9.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-9))
            camdist = 9.0
        if (camdist < 9.0):
            base.camera.setPos(base.camera.getPos() - camvec*(9-camdist))
            camdist = 9.0

        self.floater.setPos(self.player.getPos())
        self.floater.setZ(self.player.getZ() + 0.5)
        base.camera.lookAt(self.floater)
        
        return Task.cont 

Avatarobject = Avatar()
Levelobject = Level(Avatarobject.player)
Cameraobject = Camera(Avatarobject.player)

run()

I don’t have the time to fully reproduce your setup, but in my experience a shaky camera means you have multiple things driving your camera simultaneously. The Panda default mouse controls are a common culprit which can be disabled by a single line (which I forget offhand :stuck_out_tongue:). Alternatively, you may be forgetting to update one of your own state variables somewhere, or confusing deltas (differences in position/time/etc) with absolute values somewhere. A little uniquely-trackable debug output after each camera-influencing transformation ought to pin that sort of thing down.

You may also want to play around with the order in which you apply your transformations, and the parts of your hierarchy you apply them to. It’s easy for a composition of parenting and transformations to balloon outside the realm your intuition can handle, which can lead to inverted behaviors, simultaneous contradictory inputs, etc.

I get this most common when float point math fails. Things to keep in mind to avoid this:

  1. Use 1 as your base unit - floats are most accurate around 0 - 1.
  2. Floats are accurate to about 3 digits up and 3 digits down, So you want numbers always to be: XXX.XXX
  3. If your camera is more then 1000 in any axis you are doing some thing wrong.
  4. If you have sizes that are smaller then 0.001 you are doing some thing wrong.
  5. These rules are not hard rules but going beyond them will cause your stuff to wobble more and more, camera (most noticeable), to lighting, finally to vertexes (less noticeable)

Technically “floating point” implies the decimal (or rather, binary) point can be in a wide range of positions relative to the numeric value (in fact, I believe the actual format stores numbers in X*2^Y form), which means that you get about the same granularity of accuracy with respect to the order of magnitude you’re working at pretty much regardless, even though on a strict linear scale, the numerically representable points do get sparser the higher you go.

But the end result is the same- you can operate in the 10,000 range and be accurate to 100, or operate in the .001 range and be accurate to the .000001, but if you’re operating on values at 2 different orders of magnitude, you’re likely to lose precision.

uh…guys, I haven´t been sucefull yet…I have found other problems, corrected them, but yet, this one still remains…

I have spent a lot of time reading what you said, and testing what may be the problem, and I would preffer to aswer only when I solved the problem, but it looks I´m not coming with aswers this time…

I have narrowed the search thought. When I deactivate my camtrack task, I notice the trembling stopped(but without it the camera do not tracks the player anymore),so, the problem should be located somewhere there maybe.

Strange how this code I got from roaming ralph example works without classes, but when I use it inside a class it don´t works right, also, I´m using only integer numbers now, so I think the problem isn´t the floating point stuff(I think…).

class Camera(DirectObject):
    def __init__(self,player):
        base.disableMouse()
        self.player=player
        
        self.eventCapture()
        self.states = {"cam_left":0, "cam_right":0}
        base.win.setClearColor(Vec4(0,0,0,1))
     
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        self.isMoving = False

        base.camera.setPos(self.player.getX(),self.player.getY()+10,20) 
       
        taskMgr.add(self.camtrack, "Cam track")        
                  
    def eventCapture(self):
        self.accept( "q", self.changeState, ["cam_left",1] )
        self.accept( "e", self.changeState, ["cam_right",1] )
                
        self.accept( "q-up", self.changeState, ["cam_left",0] )
        self.accept( "e-up", self.changeState, ["cam_right",0] )

    def changeState(self, key, value):
        self.states[key] = value
        
    def camtrack(self,task):
        elapsed = globalClock.getDt()

        camvec = self.player.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        
        if (self.states["cam_left"] != 0):
            base.camera.setX(base.camera, +(elapsed*100))

        if (self.states["cam_right"] !=0):
            base.camera.setX(base.camera, -(elapsed*100))
                    
        if (camdist > 80.0):
            base.camera.setPos(base.camera.getPos() + camvec*(camdist-80))
            camdist = 80.0
            
        if (camdist < 80.0):
            base.camera.setPos(base.camera.getPos() - camvec*(camdist+80))
            camdist = 80.0

        self.floater.setPos(self.player.getPos())
        self.floater.setZ(self.player.getZ() + 2)
        base.camera.lookAt(self.floater)
        
        return Task.cont 

Thanks in advance for any help, since I´m running out of hope here

well, it looks my suffering is over =),this old thread really says it all:
https://discourse.panda3d.org/viewtopic.php?t=211

I just had to say to the program, which the camera should be updated last, after the player node got updated. The problem was the program was updating the camera before the player node was actually updated.

It wasn´t even the camtrack task I thought to be the source of the problem hehe

So it would be like this:

    def __init__(self,player):
        self.player=player
       
        self.eventCapture()
        self.states = {"cam_left":0, "cam_right":0}
       
        base.win.setClearColor(Vec4(0,0,0,1))
     
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        self.isMoving = False

        base.disableMouse()
        base.camera.setPos(self.player.getX(),self.player.getY()+10,2.5)
       
        taskMgr.add(self.camtrack, "Cam track",priority = 35) 

it doesn´t matter the priority number, just put a value which makes your camera be updated last.

Thanks for the support friends

Mais um brasileiro por aqui ?!?! :laughing:
O negócio tá começando a ficar popular