Basic Tutorial 5

From PyWiki

Jump to: navigation, search

WARNING - per discussion on ogre3d.org this tutorial is not up to date and does not illustrate how to do buffered input; however, that discussion does provide some hints on the subject. Tutorial 6 explains (shortly) how to set up Buffered Input and Tutorial 7 uses Buffered Input, too.

Contents

[edit] Basic Tutorial 05: Buffered Input

[edit] Prerequisites

This tutorial assumes you have knowledge of Python programming and you have already installed Python-Ogre. This tutorial builds on the material covered in previous tutorials, and it assumes you have read them.

[edit] Introduction

In this short tutorial you will be learning to use Ogre's buffered input as opposed to the unbuffered input we used in Tutorial 04. Ogre3D 1.4.0 uses OIS (Object-oriented Input Library). For more details on using OIS with Ogre3d, please refer to Using OIS. The input devices are separated into multiple objects. This tutorial refers to both "Mouse" and "Keyboard" for each respective device we are dealing with.

As you go through the tutorial you should be slowly adding code to your own project and watching the results as we build it. If you are having problems you can view the completed source code example posted at the end of this tutorial.

[edit] Getting Started

This tutorial will be building on the Tutorial 04, but we are changing the way that we do input. Since the functionality will be basically the same, we will use the same TutorialApplication class, but we will be starting over on the TutorialFrameListener class. Create a file named basic_5.py:

import ogre.renderer.OGRE as ogre
 import ogre.io.OIS as OIS
 import SampleFramework as sf
 
 
 class TutorialFrameListener(sf.FrameListener):
     """A FrameListener class that handles basic user input."""
 
     def __init__(self, renderWindow, camera, sceneManager):
         # Subclass any Python-Ogre class and you must call its constructor.
         sf.FrameListener.__init__(self, renderWindow, camera)
 
         # Populate the camera and scene manager containers.
         self.camNode = camera.parentSceneNode.parentSceneNode
         self.sceneManager = sceneManager
         self.eventProcessor = None
 
         self.rotate = 0.1                      # Rotation speed.
         self.move = 250                        # Movement speed.
         self.direction = ogre.Vector3(0, 0, 0) # Direction heading.
 
         self.keepRendering = True
 
     def frameStarted(self, frameEvent):
         # If the render window has been closed, end the program.
         if(self.renderWindow.isClosed()):
             return False
 
         return self.keepRendering
 
 
 class TutorialApplication(sf.Application):
     """The Application class."""
 
     def _createScene(self):
         # Setup a scene with a low level of ambient light.
         sceneManager = self.sceneManager
         sceneManager.ambientLight = 0.25, 0.25, 0.25
 
         # Setup a mesh entity and attach it to a scene node.
         entity = sceneManager.createEntity('Ninja', 'ninja.mesh')
         node = sceneManager.rootSceneNode.createChildSceneNode('NinjaNode')
         node.attachObject(entity)
 
         # Setup a White point light.
         light = sceneManager.createLight('Light1')
         light.type = ogre.Light.LT_POINT
         light.position = 250, 150, 250
         light.diffuseColour = 1, 1, 1
         light.specularColour = 1, 1, 1
 
         # Setup the first camera node and pitch node and aim it.
         node = sceneManager.rootSceneNode.createChildSceneNode('CamNode1',
                                                                (-400, 200, 400))
         node.yaw(ogre.Degree(-45))
         node = node.createChildSceneNode('PitchNode1')
         node.attachObject(self.camera)
 
         # Setup the second camera node and pitch node.
         node = sceneManager.rootSceneNode.createChildSceneNode('CamNode2',
                                                                (0, 200, 400))
         node.createChildSceneNode('PitchNode2')        
 
     def _createCamera(self):
         self.camera = self.sceneManager.createCamera('PlayerCam')
         self.camera.nearClipDistance = 5
 
     def _createFrameListener(self):
         self.frameListener = TutorialFrameListener(self.renderWindow,
                                                    self.camera,
                                                    self.sceneManager)
         self.root.addFrameListener(self.frameListener)
         self.frameListener.showDebugOverlay(True)
 
 
 if __name__ == '__main__':
     try:
         ta = TutorialApplication()
         ta.go()
     except ogre.OgreException, e:
         print e

The controls will be the same as used in the Tutorial 04.

[edit] Buffered Input in Ogre

[edit] Introduction

In the previous tutorial we used unbuffered input, that is, every frame we queried the state of an input device to see what keys and mouse buttons were being held down. Buffered input uses mouse and key listener interfaces to update objects. For example, when a key is pressed, a KeyListener.keyPressed event is fired and when the button is released (no longer being pressed) a KeyListener.keyReleased event is fired to all registered KeyListener classes. This takes care of having to keep track of toggle times or whether the key was pressed or not during the previous frame.

[edit] Combining FrameListeners with Input Listeners

Even though in this tutorial our FrameListener is also the key and mouse listener, please don't get stuck in the concept of having to combine the FrameListener with the key and mouse listeners. It's often a very good idea to split the two up, especially in larger applications.

[edit] OIS Input Interfaces

There are two interfaces we will be using. The Keyboard interface utilizes a callback listener for key events and the Mouse interface utilizes a listener for mouse button and position events within a MouseState structure.

[edit] KeyListener

The Keyboard interface is relatively simple. You have the callback listener, which has two events, keyPressed and keyReleased. You can also check the status of an individual key using the callback methods isKeyDown and isModifierDown instead of worrying about events.

[edit] MouseListener

The MouseListener interface defines functions for getting mouse input. With the MouseState structure you can receive the very latest recorded mouse state. In it, you have easy access to the relative X/Y/Z and absolute X/Y/Z values. You can also determine the state of any button by using the buttonDown method to test for button IDs, MB_Left, MB_Right, MB_Middle, MB_Button3, MB_Button4, MB_Button5, MB_Button6, and MB_Button7.

[edit] TutorialFrameListener

[edit] Complete Source Code Example

#!/usr/bin/env python
# This code is Public Domain and was written for Python-Ogre 1.0.
"""Python-Ogre Beginner Tutorial 05: Buffered Input."""
 
import ogre.renderer.OGRE as ogre
import ogre.io.OIS as OIS
import SampleFramework as sf
 
class TutorialFrameListener(sf.FrameListener):
    """A FrameListener class that handles basic user input."""
 
    def __init__(self, renderWindow, camera, sceneManager):
        # Subclass any Python-Ogre class and you must call its constructor.
        sf.FrameListener.__init__(self, renderWindow, camera)
 
        # Populate the camera and scene manager containers.
        self.camNode = camera.parentSceneNode.parentSceneNode
        self.sceneManager = sceneManager
        self.eventProcessor = None
 
        self.rotate = 0.1
        self.move = 250
        self.direction = ogre.Vector3(0, 0, 0)
 
        self.keepRendering = True
 
    def _setupInput(self):
        # Initialize OIS.
        windowHnd = self.renderWindow.getCustomAttributeInt("WINDOW")
        self.InputManager = OIS.createPythonInputSystem([("WINDOW", str(windowHnd))])
 
        # Create all devices, only catch joystick exceptions since most people use Key/Mouse.
        self.Keyboard = self.InputManager.createInputObjectKeyboard(OIS.OISKeyboard, self.bufferedKeys)
        self.Mouse = self.InputManager.createInputObjectMouse(OIS.OISMouse, self.bufferedMouse)
        try:
            self.Joy = self.InputManager.createInputObjectJoyStick(OIS.OISJoyStick, self.bufferedJoy)
        except:
            self.Joy = False
 
        #Set initial mouse clipping size.
        self.windowResized(self.renderWindow)
 
        # Register as a Window listener.
        ogre.WindowEventUtilities.addWindowEventListener(self.renderWindow, self);
 
    def frameStarted(self, frameEvent):
        if(self.renderWindow.isClosed()):
            return False
 
        # Capture and update each device, this will also trigger any listeners.
        self.Keyboard.capture()
        self.Mouse.capture()
 
        # Process unbuffered key input.
        if not self.keyPressed(frameEvent):
            return False
 
        # Translate the camera based on time.
        self.camNode.translate(self.camNode.orientation
            * self.direction
            * frameEvent.timeSinceLastFrame)
 
        # Check for Key release to stop moving the camera.
        self.keyReleased(frameEvent)
 
        # Process unbuffered mouse input.
        self.mousePressed(frameEvent)
        self.mouseDragged(frameEvent)
 
        return self.keepRendering
 
    def keyPressed(self, frameEvent):
        # Stop Rendering if Escape was pressed.
        if self.Keyboard.isKeyDown(OIS.KC_ESCAPE):
            return False
        # Attach the camera to PitchNode1.
        if self.Keyboard.isKeyDown(OIS.KC_1):
            self.camera.parentSceneNode.detachObject(self.camera)
            self.camNode = self.sceneManager.getSceneNode("CamNode1")
            self.sceneManager.getSceneNode("PitchNode1").attachObject(self.camera)
        # Attach the camera to PitchNode2.
        if self.Keyboard.isKeyDown(OIS.KC_2):
            self.camera.parentSceneNode.detachObject(self.camera)
            self.camNode = self.sceneManager.getSceneNode("CamNode2")
            self.sceneManager.getSceneNode("PitchNode2").attachObject(self.camera)
        # Move Forward.
        if self.Keyboard.isKeyDown(OIS.KC_UP) or self.Keyboard.isKeyDown(OIS.KC_W):
            self.direction.z -= self.move
        # Move Backward.
        if self.Keyboard.isKeyDown(OIS.KC_DOWN) or self.Keyboard.isKeyDown(OIS.KC_S):
            self.direction.z += self.move
        # Strafe Left.
        if self.Keyboard.isKeyDown(OIS.KC_LEFT) or self.Keyboard.isKeyDown(OIS.KC_A):
            self.direction.x -= self.move
        # Strafe Right.
        if self.Keyboard.isKeyDown(OIS.KC_RIGHT) or self.Keyboard.isKeyDown(OIS.KC_D):
            self.direction.x += self.move
        # Move Up.
        if self.Keyboard.isKeyDown(OIS.KC_PGUP) or self.Keyboard.isKeyDown(OIS.KC_Q):
            self.direction.y += self.move
        # Move Down.
        if self.Keyboard.isKeyDown(OIS.KC_PGDOWN) or self.Keyboard.isKeyDown(OIS.KC_E):
            self.direction.y -= self.move
        return True
 
    def keyReleased(self, frameEvent):
        # Undo change to the direction vector when the key is released to stop movement.
        if self.Keyboard.isKeyDown(OIS.KC_UP) or self.Keyboard.isKeyDown(OIS.KC_W):
            self.direction.z += self.move
        # Move Backward.
        if self.Keyboard.isKeyDown(OIS.KC_DOWN) or self.Keyboard.isKeyDown(OIS.KC_S):
            self.direction.z -= self.move
        # Strafe Left.
        if self.Keyboard.isKeyDown(OIS.KC_LEFT) or self.Keyboard.isKeyDown(OIS.KC_A):
            self.direction.x += self.move
        # Strafe Right.
        if self.Keyboard.isKeyDown(OIS.KC_RIGHT) or self.Keyboard.isKeyDown(OIS.KC_D):
            self.direction.x -= self.move
        # Move Up.
        if self.Keyboard.isKeyDown(OIS.KC_PGUP) or self.Keyboard.isKeyDown(OIS.KC_Q):
            self.direction.y -= self.move
        # Move Down.
        if self.Keyboard.isKeyDown(OIS.KC_PGDOWN) or self.Keyboard.isKeyDown(OIS.KC_E):
            self.direction.y += self.move
 
    def mousePressed(self, frameEvent):
        ms = self.Mouse.getMouseState()
        # Toggle the light.
        if ms.buttonDown(OIS.MB_Left):
            light = self.sceneManager.getLight('Light1')
            light.visible = not light.visible
 
    def mouseDragged(self, frameEvent):
        # Rotate the camera.
        ms = self.Mouse.getMouseState()
        if ms.buttonDown(OIS.MB_Right):
            self.camNode.yaw(ogre.Degree(-self.rotate
                * ms.X.rel).valueRadians())
            self.camNode.getChild(0).pitch(ogre.Degree(-self.rotate
                * ms.Y.rel).valueRadians())
 
class TutorialApplication(sf.Application):
    """Application class."""
 
    def _createScene(self):
        sceneManager = self.sceneManager
        sceneManager.ambientLight = 0.25, 0.25, 0.25
 
        ent = sceneManager.createEntity("Ninja", "ninja.mesh")
        node = sceneManager.rootSceneNode.createChildSceneNode("NinjaNode")
        node.attachObject(ent)
 
        light = sceneManager.createLight("Light1")
        light.type = ogre.Light.LT_POINT
        light.position = 250, 150, 250
        light.diffuseColour = 1, 1, 1
        light.specularColour = 1, 1, 1
 
        # create the first camera node/pitch node
        node = sceneManager.rootSceneNode.createChildSceneNode("CamNode1",
            (-400, 200, 400))
        node.yaw(ogre.Degree(-45))
        node = node.createChildSceneNode("PitchNode1")
        node.attachObject(self.camera)
 
        # create the second camera node/pitch node
        node = sceneManager.rootSceneNode.createChildSceneNode("CamNode2",
            (0, 200, 400))
        node.createChildSceneNode("PitchNode2")
 
    def _createCamera(self):
        self.camera = self.sceneManager.createCamera("PlayerCam")
        self.camera.nearClipDistance = 5
 
    def _createFrameListener(self):
        self.frameListener = TutorialFrameListener(self.renderWindow,
            self.camera,
            self.sceneManager)
        self.root.addFrameListener(self.frameListener)
        self.frameListener.showDebugOverlay(True)
 
if __name__ == '__main__':
    try:
        ta = TutorialApplication()
        ta.go()
    except ogre.OgreException, e:
        print e
Proceed to Basic Tutorial 6 The Ogre Startup Sequence
Python-Ogre Tutorials

Python-Ogre Beginner Tutorials: Beginner 1 - Beginner 2 - Beginner 3 - Beginner 4 - Beginner 5 - Beginner 6 - Beginner 7 - Beginner 8

Intermediate Tutorials: Intermediate 1 - Intermediate 2 - Intermediate 3 - Intermediate 4 - Intermediate 5 - Intermediate 6

Advanced Tutorials: Advanced 1

See also: Artist Tutorials - Ogre Articles - Cookbook

Personal tools