WASD character control

Just thought it’d be interesting to share/compare code for WASD character control. I’ve been using sin/cos math for it. But I was thinking of trying a dummy node approach. Changes in HPR would affect the dummy node and then changes in XYZ would affect the player node.

I use this (in connection with key polling, a little bit modified to my taste):

from basePolling import I

class Player():
    def __init__(self):
        self.name = "player"
        self.pivot = render.attachNewNode("pivot")
        self.actor = Actor() # and so on to load actor
        self.actor.reparentTo(self.pivot)
        self.steerer = self.pivot.attachNewNode("steerer")
        self.target = Point3(0, 0, 0)
        self.speed = 15.0
        self.lastsavedtime = 0
        self.updateTask=taskMgr.add(self.update,"update")
        
    def update(self, task):
        elapsedTime = task.time - self.lastsavedtime
        targetMoved = self.setTarget()
        if targetMoved:
            self.steerer.headsUp(self.target)
            move = self.speed * elapsedTime
            self.pivot.setY(self.steerer, move)
        self.lastsavedtime = task.time
        return Task.cont
        
    def setTarget(self):
        self.target = Point3(0, 0, 0)
        if I.keyDown("w"):
            self.target += Point3(0, 1, 0)
        if I.keyDown("a"):
            self.target += Point3(-1, 0, 0)
        if I.keyDown("s"):
            self.target += Point3(0, -1, 0)
        if I.keyDown("d"):
            self.target += Point3(1, 0, 0)
        if self.target != Point3(0, 0, 0):
            return True
        else:
            return False

Explain to me why you would need either for simple WASD control. It is as simple as:

class PlayerControls(object):
def __init__(self, char):
  self.char = char
  base.camera.reparentTo(char)
  base.camera.setPos(0, -10, 10)
  self.mvX = 0
  self.mvY = 0
  self.accept("a", self.__setattr__, ["mvX", -1])
  self.accept("d", self.__setattr__, ["mvX", 1])
  self.accept("w", self.__setattr__, ["mvY", 1])
  self.accept("s", self.__setattr__, ["mvY", -1])
  self.accept("a-up", self.__setattr__, ["mvX", 0])
  self.accept("d-up", self.__setattr__, ["mvX", 0])
  self.accept("w-up", self.__setattr__, ["mvY", 0])
  self.accept("s-up", self.__setattr__, ["mvY", 0])
  taskMgr.add(self.move, "moveTask")

def move(self, task):
  self.char.setX(self.char, self.mvX * globalClock.getDt() * SPD)
  self.char.setY(self.char, self.mvY * globalClock.getDt() * SPD)
  self.char.setH(self.char.getH() + base.mouseWatcherNode.getMouseX())
  self.char.setP(self.char.getP() + base.mouseWatcherNode.getMouseY())
  base.win.movePointer(0, base.win.getXSize() / 2, base.win.getYSize() / 2)
  return task.cont

A good rule-of-thumb is: if you have to use sin/cos/tan, you’re probably doing something wrong. (copyrighted by drwr)