Handling keyboard and mouse input

With the exception of karaoke and guitar games like Rock Band or Guitar Hero, it is generally a pretty bad idea to require a specialized controller or other input device for a video game. So, unless you have the marketing budget for advertising your new and special controller, you should always opt to use the most common and most widely available devices.

On consoles you would therefore aim for the standard gamepad, while the most widespread input measure for PC games is a combination of keyboard and mouse. Because Panda3D is targeted towards PC game production, in this example, you will learn how to handle input data received from the latter input method.

Getting ready

This recipe will of course be using our standard application skeleton that we created in the first chapter. Additionally, we will reuse the FollowCam class from the recipe Making the camera smoothly follow an object in Chapter 2, Creating and Building Scenes. Be sure to implement that class and place the source file called FollowCam.py inside the src subdirectory of the project.

How to do it...

Implement keyboard and mouse input by following these steps:

  1. Import the required libraries and implement the constructor of the Application class as well as the resetMouse() method:
    from direct.showbase.ShowBase import ShowBase
    from direct.actor.Actor import Actor
    from panda3d.core import *
    from FollowCam import FollowCam
    class Application(ShowBase):
    def __init__(self):
    ShowBase.__init__(self)
    self.world = loader.loadModel("environment")
    self.world.reparentTo(render)
    self.world.setScale(0.5)
    self.world.setPos(-8, 80, 0)
    self.panda = Actor("panda", {"walk": "panda-walk"})
    self.panda.reparentTo(render)
    self.followCam = FollowCam(self.cam, self.panda)
    base.disableMouse()
    props = WindowProperties.getDefault()
    props.setCursorHidden(True)
    base.win.requestProperties(props)
    self.resetMouse()
    # don't use -repeat because of slight delay after keydown
    self.pandaWalk = False
    self.pandaReverse = False
    self.pandaLeft = False
    self.pandaRight = False
    self.accept("escape", exit)
    self.accept("w", self.beginWalk)
    self.accept("w-up", self.endWalk)
    self.accept("s", self.beginReverse)
    self.accept("s-up", self.endReverse)
    self.accept("a", self.beginTurnLeft)
    self.accept("a-up", self.endTurnLeft)
    self.accept("d", self.beginTurnRight)
    self.accept("d-up", self.endTurnRight)
    taskMgr.add(self.updatePanda, "update panda")
    def resetMouse(self):
    cx = base.win.getProperties().getXSize() / 2
    cy = base.win.getProperties().getYSize() / 2
    base.win.movePointer(0, cx, cy)
    
  2. Add these keyboard event handling methods to the Application class:
    def beginWalk(self):
    self.panda.setPlayRate(1.0, "walk")
    self.panda.loop("walk")
    self.pandaWalk = True
    def endWalk(self):
    self.panda.stop()
    self.pandaWalk = False
    def beginReverse(self):
    self.panda.setPlayRate(-1.0, "walk")
    self.panda.loop("walk")
    self.pandaReverse = True
    def endReverse(self):
    self.panda.stop()
    self.pandaReverse = False
    def beginTurnLeft(self):
    self.pandaLeft = True
    def endTurnLeft(self):
    self.pandaLeft = False
    def beginTurnRight(self):
    self.pandaRight = True
    def endTurnRight(self):
    self.pandaRight = False
    
  3. Extend the Application class further by adding this method:
    def updatePanda(self, task):
    if base.mouseWatcherNode.hasMouse():
    self.panda.setH(self.panda, -base.mouseWatcherNode.getMouseX() * 10)
    self.resetMouse()
    if self.pandaWalk:
    self.panda.setY(self.panda, -0.2)
    elif self.pandaReverse:
    self.panda.setY(self.panda, 0.2)
    if self.pandaLeft:
    self.panda.setH(self.panda, 0.8)
    elif self.pandaRight:
    self.panda.setH(self.panda, -0.8)
    return task.cont
    
  4. Start the program. Use the W and S keys to walk forward and backward. Press A, D, or use the mouse to turn left and right. Press the Escape key to quit.

How it works...

After loading and positioning all the scene objects and setting up the FollowCam class to follow the panda, we encounter the line base.disableMouse(). The method name is somewhat misleading, as it does not literally do what it says. After calling base.disableMouse() the engine will still receive mouse input but the default mouse-based camera controls will be disabled.

We then hide the mouse cursor by setting the appropriate flag in WindowProperties and use the resetMouse() method to reset the mouse pointer to the center of the window. This is important for detecting mouse movement later on in the code.

Next, we initialize a set of Boolean flags. These will be used to inform the updating task which action to perform and in which direction to move the panda. These flags are modified by the event handling methods we register for keyboard presses in the following lines.

After the line that adds the task for updating the panda's position, we can find the keyboard event handling methods. Here we set the movement flags pandaWalk, pandaReverse, pandaLeft, and PandaRight and activate the appropriate animations depending on the key being pressed. We need the Boolean flags to make the panda move as long as the key is in a pressed state, where the flag is set to True. As soon as an"-up" event occurs, the flag is set back to False and the panda stops moving.

We explicitly do not use the"-repeat" events here for a reason: The engine starts to send this type of event a short moment after the key was initially pressed. In our case this would cause the panda to twitch, pause, and then move on normally, which is not what we intend to achieve.

Finally, we implement the updatePanda() method. At runtime, this code is called at every frame and is responsible for moving the panda around, based on which of the movement flags are set. It is also the place where we finally handle mouse movement: First we check if the mouse is within our window. The position of the mouse pointer in Panda3D is relative to the center of the window. We use this fact to check how far the mouse pointer was moved from the window center since the last frame to change the heading of the panda model. Of course, we need to reset the mouse pointer to the center of the window again to keep this technique working and prevent it from leaving the window.

There's more...

As we can see, Panda3D automatically creates various events for when a key is pressed down or released again. This reduces accepting keyboard events to simply adding the correct event handlers for these events.

Character and number keys create events named after the symbol on the key. The events for character keys are always in lower case. Special and control keys have their own, but not hard to guess, event names:"enter", "lshift", "ralt", "f1", "f2", "page_down", and so on. The same applies for mouse buttons, which are named consecutively, starting with"mouse1" and"mouse2" for the left and right mouse buttons.

For handling keys being held down or being released after having been pressed, the event names are modified with a set of post- and prefixes. In our sample, we can see the"-up" modifier that is used when the player takes a finger off a key. Apart from that, there are also the"time-" and"-repeat" variants of each event. The former passes the time when the event occurred to the event handler, while the latter is sent continuously if a key is held down over a period of time. These modifiers can also be mixed:"time-enter", "time-f1-repeat", "a-up", and"time-lshift-up" are all valid samples of event names to accept.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset