Sunday, 19 January 2014

Blender FPS movement script

A short script for FPS camera movement in Blender 2.69. Simply attach the Python controller of the camera to an Always sensor. Change the upcap and downcap angle to your liking.

import mathutils
import math

ctrl = bge.logic.getCurrentController()
gobj = ctrl.owner

#Keyboard#

if bge.logic.keyboard.events[bge.events.WKEY] == bge.logic.KX_INPUT_ACTIVE:
    move = gobj.worldOrientation.to_quaternion() * mathutils.Vector((0,0,1)) * 0.1
    move.z = 0
    gobj.worldPosition = gobj.worldPosition - move

if bge.logic.keyboard.events[bge.events.SKEY] == bge.logic.KX_INPUT_ACTIVE:
    move = gobj.worldOrientation.to_quaternion() * mathutils.Vector((0,0,1)) * 0.1
    move.z = 0
    gobj.worldPosition = gobj.worldPosition + move

if bge.logic.keyboard.events[bge.events.AKEY] == bge.logic.KX_INPUT_ACTIVE:
    move = gobj.worldOrientation.to_quaternion() * mathutils.Vector((1,0,0)) * 0.1
    move.z = 0
    gobj.worldPosition = gobj.worldPosition - move

if bge.logic.keyboard.events[bge.events.DKEY] == bge.logic.KX_INPUT_ACTIVE:
    move = gobj.worldOrientation.to_quaternion() * mathutils.Vector((1,0,0)) * 0.1
    move.z = 0
    gobj.worldPosition = gobj.worldPosition + move

#Mouse#

flag = False

tmp = gobj.worldOrientation.to_euler()
posx = bge.logic.mouse.position[0]*float(bge.render.getWindowWidth())
rotz = (posx - float(bge.render.getWindowWidth()/2)) * 0.001
if rotz != 0:
    tmp.x = 0
    tmp.y = 0
    tmp.z = -rotz
    gobj.worldOrientation = tmp.to_matrix() * gobj.worldOrientation
    flag = True

tmp = gobj.worldOrientation.to_euler()
posy = bge.logic.mouse.position[1]*float(bge.render.getWindowHeight())
rotx = (posy - float(bge.render.getWindowHeight()/2)) * 0.001
if rotx != 0:
    tmp.x = -rotx
    tmp.y = 0
    tmp.z = 0
    tmp2 = gobj.worldOrientation * tmp.to_matrix()
    upcap_angle = 100/180 * 3.142
    downcap_angle = 80/180 * 3.142
    if tmp2.to_euler().x < 0 and tmp2.to_euler().x < upcap_angle - math.pi:
        gobj.worldOrientation = tmp2
    elif tmp2.to_euler().x > 0 and tmp2.to_euler().x < upcap_angle and tmp2.to_euler().x > downcap_angle:
        gobj.worldOrientation = tmp2
    flag = True

if flag:
    bge.render.setMousePosition(int(bge.render.getWindowWidth()/2), int(bge.render.getWindowHeight()/2))


The capping part was a bit messy because, for whatever reason, the Euler angles aren't continuous. Screenshot below shows the Euler angles when looking around horizontally (x,y,z).


I don't know, but when I run this on the standalone player, a "bump" will always occur once when looking around horizontally. Any idea why this happens? Is it because of the discontinuity? In the embedded player, there is no bump, but there is a constant drift instead (floats rounding themselves off?).

Anyway, have fun!

No comments:

Post a Comment