Another Camera Controller, Orbit style

Return to Code Snippets

Another Camera Controller, Orbit style

Postby piratePanda » Tue Nov 29, 2011 6:57 pm

This is a script I created to use as a default camera control, because I find the built in camera control really awkward.

The script creates a blank NodePath to use as an anchor and reparents the camera to it. The script has 3 inputs to control the camera. They are:

The left mouse button causes the anchor to move forward, taking the camera with it.

Holding the right mouse button and moving the mouse causes the anchor to rotate left, right, up, and down, which makes the camera orbit around the anchor's location.

Holding the middle mouse button and moving the mouse up or down causes the camera to move closer to, or away from, the anchor.

There are 4 variables to help adjust the controls to meet the needs of a given usage. Distances are all in panda units. The variables are:

self.initZoom - the distance from the anchor that the camera will start at.

self.zoomInLimit - the minimum distance the camera can be from the anchor. If this value is negative, the camera can move past the anchor when zooming.

self.zoomOutLimit - the maximum distance the camera can be from the anchor.

self.moveSpeed - the number of units the anchor will move, per frame, when the left mouse button is held.

To use this camera controller, just import and instantiate the class.
Last edited by piratePanda on Tue Nov 29, 2011 7:14 pm, edited 1 time in total.
"Sincere words are not pretty. Pretty words are not sincere." -Lao Tzu
User avatar
piratePanda
 
Posts: 444
Joined: Sat Aug 15, 2009 1:40 pm

Postby piratePanda » Tue Nov 29, 2011 6:58 pm

Code: Select all
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import *

class CameraController(DirectObject):
   def   __init__(self):
      base.disableMouse()
      
      self.setupVars()
      self.setupCamera()
      self.setupInput()
      self.setupTasks()
      
   def setupVars(self):
      self.initZoom = 5         #Camera's initial distance from anchor
      self.zoomInLimit = 1      #Camera's minimum distance from anchor
      self.zoomOutLimit = 1000   #Camera's maximum distance from anchor
      self.moveSpeed = .5         #Rate of movement for the anchor
      self.zoom = None
      self.orbit = None
      self.move = None
   
   def setupCamera(self):
      self.camAnchor = render.attachNewNode("Cam Anchor")
      base.camera.reparentTo(self.camAnchor)
      base.camera.setPos(0, -self.initZoom, 0)
      base.camera.lookAt(self.camAnchor)
      
   def setupInput(self):
      self.accept("mouse1", self.setMove, [True])
      self.accept("mouse1-up", self.setMove, [False])
      self.accept("mouse2", self.setZoom, [True])
      self.accept("mouse2-up", self.setZoom, [False])
      self.accept("mouse3", self.setOrbit, [True])
      self.accept("mouse3-up", self.setOrbit, [False])
   
   def setupTasks(self):
      taskMgr.add(self.cameraOrbit, "Camera Orbit")
      taskMgr.add(self.cameraZoom, "Camera Zoom")
      taskMgr.add(self.cameraMove, "Camera Move")
      
   def setOrbit(self, orbit):
      if(orbit == True):
         props = base.win.getProperties()
         winX = props.getXSize()
         winY = props.getYSize()
         if base.mouseWatcherNode.hasMouse():
            mX = base.mouseWatcherNode.getMouseX()
            mY = base.mouseWatcherNode.getMouseY()
            mPX = winX * ((mX+1)/2)
            mPY = winY * ((-mY+1)/2)
         self.orbit = [[mX, mY], [mPX, mPY]]
      else:
         self.orbit = None
   
   def cameraOrbit(self, task):
      if(self.orbit != None):
         if base.mouseWatcherNode.hasMouse():
            
            mpos = base.mouseWatcherNode.getMouse()
            
            base.win.movePointer(0, int(self.orbit[1][0]), int(self.orbit[1][1]))
            
            deltaH = 90 * (mpos[0] - self.orbit[0][0])
            deltaP = 90 * (mpos[1] - self.orbit[0][1])
            
            limit = .5
            
            if(-limit < deltaH and deltaH < limit):
               deltaH = 0
            elif(deltaH > 0):
               deltaH - limit
            elif(deltaH < 0):
               deltaH + limit
               
            if(-limit < deltaP and deltaP < limit):
               deltaP = 0
            elif(deltaP > 0):
               deltaP - limit
            elif(deltaP < 0):
               deltaP + limit

            newH = (self.camAnchor.getH() + -deltaH)
            newP = (self.camAnchor.getP() + deltaP)
            if(newP < -90): newP = -90
            if(newP > 90): newP = 90
         
            self.camAnchor.setHpr(newH, newP, 0)            
         
      return task.cont
   
   def setZoom(self, zoom):
      if(zoom == True):
         props = base.win.getProperties()
         winX = props.getXSize()
         winY = props.getYSize()
         if base.mouseWatcherNode.hasMouse():
            mX = base.mouseWatcherNode.getMouseX()
            mY = base.mouseWatcherNode.getMouseY()
            mPX = winX * ((mX+1)/2)
            mPY = winY * ((-mY+1)/2)
         self.zoom = [[mX, mY], [mPX, mPY]]
      else:
         self.zoom = None
      
   def cameraZoom(self, task):
      if(self.zoom != None):
         if base.mouseWatcherNode.hasMouse():
            
            mpos = base.mouseWatcherNode.getMouse()
            
            base.win.movePointer(0, int(self.zoom[1][0]), int(self.zoom[1][1]))
            
            deltaY = (mpos[1] - self.zoom[0][1]) * base.camera.getY()
            
            limit = .5
            
            if(-limit < deltaY and deltaY < limit):
               deltaY = 0
            elif(deltaY > 0):
               deltaY - limit
            elif(deltaY < 0):
               deltaY + limit

            newY = (base.camera.getY() - deltaY)
            if(newY > -self.zoomInLimit): newY = -self.zoomInLimit
            if(newY < -self.zoomOutLimit): newY = -self.zoomOutLimit
         
            base.camera.setY(newY)            
         
      return task.cont
      
   def setMove(self, value):
      self.move = value
      
   def cameraMove(self, task):
      if(self.move == True):
         self.camAnchor.setY(self.camAnchor, self.moveSpeed)
         
      return task.cont
"Sincere words are not pretty. Pretty words are not sincere." -Lao Tzu
User avatar
piratePanda
 
Posts: 444
Joined: Sat Aug 15, 2009 1:40 pm


Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 0 guests