Skip to content

Instantly share code, notes, and snippets.

@mr-linch
Created June 8, 2014 10:19
Show Gist options
  • Save mr-linch/f6dacd2a069887a47fbc to your computer and use it in GitHub Desktop.
Save mr-linch/f6dacd2a069887a47fbc to your computer and use it in GitHub Desktop.

Revisions

  1. mr-linch created this gist Jun 8, 2014.
    164 changes: 164 additions & 0 deletions camera.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,164 @@
    # -*- coding: utf-8 -*-

    import math
    import collections

    import pyglet


    class FirstPersonCamera(object):
    """First person camera implementation
    Usage:
    import pyglet
    from pyglet.gl import *
    from camera import FirstPersonCamera
    window = pyglet.window.Window(fullscreen=True)
    window.set_exclusive_mouse(True)
    camera = FirstPersonCamera(window)
    @window.event
    def on_draw():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    camera.draw()
    # Your draw code here
    return pyglet.event.EVENT_HANDLED
    def on_update(delta_time):
    camera.update(delta_time)
    # Your update code here
    if __name__ == '__main__':
    pyglet.clock.schedule(on_update)
    pyglet.app.run()
    """

    DEFAULT_MOVEMENT_SPEED = 10.0

    DEFAULT_MOUSE_SENSITIVITY = 0.25

    DEFAULT_KEY_MAP = {
    'forward': pyglet.window.key.W,
    'backward': pyglet.window.key.S,
    'left': pyglet.window.key.A,
    'right': pyglet.window.key.D,
    'up': pyglet.window.key.SPACE,
    'down': pyglet.window.key.LSHIFT
    }

    class InputHandler(object):
    def __init__(self):
    self.pressed = collections.defaultdict(bool)
    self.dx = 0
    self.dy = 0

    def on_key_press(self, symbol, modifiers):
    self.pressed[symbol] = True

    def on_key_release(self, symbol, modifiers):
    self.pressed[symbol] = False

    def on_mouse_motion(self, x, y, dx, dy):
    self.dx = dx
    self.dy = dy

    def __init__(self, window, position=(0, 0, 0), key_map=DEFAULT_KEY_MAP, movement_speed=DEFAULT_MOVEMENT_SPEED, mouse_sensitivity=DEFAULT_MOUSE_SENSITIVITY, y_inv=True):
    """Create camera object
    Arguments:
    window -- pyglet window which camera attach
    position -- position of camera
    key_map -- dict like FirstPersonCamera.DEFAULT_KEY_MAP
    movement_speed -- speed of camera move (scalar)
    mouse_sensitivity -- sensitivity of mouse (scalar)
    y_inv -- inversion turn above y-axis
    """

    self.__position = list(position)

    self.__yaw = 0.0
    self.__pitch = 0.0

    self.__input_handler = FirstPersonCamera.InputHandler()

    window.push_handlers(self.__input_handler)

    self.y_inv = y_inv
    self.key_map = key_map
    self.movement_speed = movement_speed
    self.mouse_sensitivity = mouse_sensitivity

    def yaw(self, yaw):
    """Turn above x-axis"""
    self.__yaw += yaw * self.mouse_sensitivity

    def pitch(self, pitch):
    """Turn above y-axis"""
    self.__pitch += pitch * self.mouse_sensitivity * ((-1) if self.y_inv else 1)

    def move_forward(self, distance):
    """Move forward on distance"""
    self.__position[0] -= distance * math.sin(math.radians(self.__yaw))
    self.__position[2] += distance * math.cos(math.radians(self.__yaw))

    def move_backward(self, distance):
    """Move backward on distance"""
    self.__position[0] += distance * math.sin(math.radians(self.__yaw))
    self.__position[2] -= distance * math.cos(math.radians(self.__yaw))

    def move_left(self, distance):
    """Move left on distance"""
    self.__position[0] -= distance * math.sin(math.radians(self.__yaw - 90))
    self.__position[2] += distance * math.cos(math.radians(self.__yaw - 90))

    def move_right(self, distance):
    """Move right on distance"""
    self.__position[0] -= distance * math.sin(math.radians(self.__yaw + 90))
    self.__position[2] += distance * math.cos(math.radians(self.__yaw + 90))

    def move_up(self, distance):
    """Move up on distance"""
    self.__position[1] -= distance

    def move_down(self, distance):
    """Move down on distance"""
    self.__position[1] += distance

    def update(self, delta_time):
    """Update camera state"""
    self.yaw(self.__input_handler.dx)
    self.__input_handler.dx = 0

    self.pitch(self.__input_handler.dy)
    self.__input_handler.dy = 0

    if self.__input_handler.pressed[self.key_map['forward']]:
    self.move_forward(delta_time * self.movement_speed)

    if self.__input_handler.pressed[self.key_map['backward']]:
    self.move_backward(delta_time * self.movement_speed)

    if self.__input_handler.pressed[self.key_map['left']]:
    self.move_left(delta_time * self.movement_speed)

    if self.__input_handler.pressed[self.key_map['right']]:
    self.move_right(delta_time * self.movement_speed)

    if self.__input_handler.pressed[self.key_map['up']]:
    self.move_up(delta_time * self.movement_speed)

    if self.__input_handler.pressed[self.key_map['down']]:
    self.move_down(delta_time * self.movement_speed)

    def draw(self):
    """Apply transform"""
    pyglet.gl.glRotatef(self.__pitch, 1.0, 0.0, 0.0)
    pyglet.gl.glRotatef(self.__yaw, 0.0, 1.0, 0.0)
    pyglet.gl.glTranslatef(*self.__position)