[Python] Fixing Inconsistent Mouse Look Rotation in Panda3D

Discussão em 'Python' iniciado por Stack, Fevereiro 7, 2025.

  1. Stack

    Stack Membro Participativo

    Recently, I wanted to get started on making a 3d tester game with panda3d using python. However, I can't seem to mimic the mouse rotation within the environment that other popular first-person games have.

    Let me explain:

    If I move my mouse slowly over a long period of time, starting on the left side of my mousepad and moving to the right, I have to move it to about the center of the mousepad to make a full 360 degree turn within the game. However, If I move my mouse really quickly over a shorter period of time, I can make a full revolution in much less space, allowing me to make even more rotations in one mouse motion.

    This does not happen in games that I play daily. In popular games that I have played, mouse speed did not effect the amount turned.

    After testing, I attempted to set the movement delta so that it would be a flat movement each time, instead of mouse distance from the center. However, this ended up having the opposite event occurring, where moving the mouse slower over a longer period of time caused the camera to rotate more.

    Unfortunately, I am unable to upload clips of it occurring, but I am happy to provide the code, for other people to test it themselves. Start by looking at the box, then moving your mouse slowly over a longer period of time, counting the revolutions, and then try moving your mouse faster. I got about 2 revolutions for the slow test, and 4 for the fast one.

    Code:

    from direct.showbase.ShowBase import ShowBase
    from panda3d.core import CardMaker, LVector3, Vec4, NodePath, Mat3, WindowProperties
    from math import sin, cos, radians

    class WalkingGame(ShowBase):
    def __init__(self):
    global base
    base=self
    ShowBase.__init__(self)

    cm = CardMaker("ground")
    cm.setFrame(-10, 10, -10, 10)
    self.plane = NodePath(cm.generate())
    self.plane.reparentTo(self.render)
    self.plane.setHpr(0, -90, 0)
    self.plane.setColor(Vec4(1, 1, 1, 1)) # White


    self.player = self.loader.loadModel("models/box")
    self.player.reparentTo(self.render)
    self.player.setScale(0.5)
    self.player.setPos(0, 0, 0)

    self.camLens.setFov(75)

    # Camera
    self.taskMgr.add(self.update_camera, "camera_task")
    self.taskMgr.add(self.update_movement, "move_task")
    self.camera.setPos(0.2,2,2)
    # Detect key presses
    self.keys = []
    self.buttonThrowers[0].node().setButtonDownEvent('any')
    self.buttonThrowers[0].node().setButtonUpEvent('any-up')
    self.accept('escape',self.userExit)
    self.accept('any', self.press)
    self.accept('any-up', self.release)


    self.disableMouse()
    props = WindowProperties()
    props.setCursorHidden(True)
    props.setFullscreen(True)
    self.win.requestProperties(props)


    def lockMouse(self, task):
    center_x = self.win.getXSize() // 2
    center_y = self.win.getYSize() // 2
    self.win.movePointer(0, center_x, center_y)
    return task.cont

    def press(self, key: str):
    key=key.replace("shift-","")
    self.keys.append(key)

    def release(self, key: str):
    key=key.replace("shift-","")
    self.keys.remove(key)

    def update_movement(self, task):
    yaw=self.camera.getHpr()[0]
    rotation_matrix = Mat3.rotateMatNormaxis(yaw, LVector3(0, 0, 1))
    direction = rotation_matrix.xform(LVector3(0, 1, 0))

    yaw_rad = radians(yaw+90)

    right_x = -sin(yaw_rad)
    right_y = cos(yaw_rad)
    pos = self.camera.getPos()

    speed = 0.1 if "shift" in self.keys else 0.05

    if "w" in self.keys:
    pos += direction * speed
    if "s" in self.keys:
    pos -= direction * speed
    if "a" in self.keys:
    pos.x += right_x * speed
    pos.y += right_y * speed
    if "d" in self.keys:
    pos.x -= right_x * speed
    pos.y -= right_y * speed

    self.camera.setPos(pos)

    return task.cont

    def update_camera(self, task):
    sensitivity = 100
    center_x = base.win.getXSize() // 2
    center_y = base.win.getYSize() // 2

    if base.mouseWatcherNode.hasMouse():
    # Get current mouse position
    x = base.win.getPointer(0).getX()
    y = base.win.getPointer(0).getY()

    # Calculate movement delta
    dx = center_x - x
    dy = center_y - y

    # Get current camera rotation
    h, p, r = self.camera.getHpr()


    new_h = h + dx * sensitivity * 0.003
    new_p = max(min(p + dy * sensitivity * 0.003, 90), -90) # Clamp pitch

    # Apply
    self.camera.setHpr(new_h, new_p, r)

    # Reset mouse position to the center
    base.win.movePointer(0, center_x, center_y)

    return task.cont

    if __name__ == "__main__":
    game = WalkingGame()
    game.run()

    Continue reading...

Compartilhe esta Página