Source code for peng3d.actor.player

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  player.py
#  
#  Copyright 2016 notna <notna@apparat.org>
#  
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#  
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#  
#  

__all__ = ["BasicPlayer","FirstPersonPlayer","FourDirectionalMoveController","EgoMouseRotationalController","BasicFlightController"]

import math

try:
    import pyglet
except ImportError:
    pass

from . import Actor,RotatableActor,Controller

[docs]class FourDirectionalMoveController(Controller): """ Controller allowing the user to control the actor with the keyboard. You can configure the used keybinds with the :confval:`controls.controls.forward` etc. The keybinds can also be changed with their ``keybindname``\ , e.g. ``peng3d:actor.<actor uuid>.player.controls.forward`` for forward. The movement speed may also be changed via the :py:attr:`movespeed` instance attribute, which defaults to :confval:`controls.controls.movespeed`\ . You may also access the currently held keys via :py:attr:`move`\ , which is a list with 2 items, forwards/backwards and left/right. """ def __init__(self,*args,**kwargs): super(FourDirectionalMoveController,self).__init__(*args,**kwargs) self.move = [0,0] self.movespeed = self.peng.cfg["controls.controls.movespeed"]
[docs] def registerEventHandlers(self): """ Registers needed keybinds and schedules the :py:meth:`update` Method. You can control what keybinds are used via the :confval:`controls.controls.forward` etc. Configuration Values. """ # Forward self.peng.keybinds.add(self.peng.cfg["controls.controls.forward"],"peng3d:actor.%s.player.controls.forward"%self.actor.uuid,self.on_fwd_down,False) # Backward self.peng.keybinds.add(self.peng.cfg["controls.controls.backward"],"peng3d:actor.%s.player.controls.backward"%self.actor.uuid,self.on_bwd_down,False) # Strafe Left self.peng.keybinds.add(self.peng.cfg["controls.controls.strafeleft"],"peng3d:actor.%s.player.controls.strafeleft"%self.actor.uuid,self.on_left_down,False) # Strafe Right self.peng.keybinds.add(self.peng.cfg["controls.controls.straferight"],"peng3d:actor.%s.player.controls.straferight"%self.actor.uuid,self.on_right_down,False) pyglet.clock.schedule_interval(self.update,1.0/60)
[docs] def update(self,dt): """ Should be called regularly to move the actor. This method does nothing if the :py:attr:`enabled` property is set to false. Note that this method is called automatically and should not be manually called. """ if not self.enabled: return speed = self.movespeed d = dt * speed # distance covered this tick. dx, dy, dz = self.get_motion_vector() # New position in space, before accounting for gravity. dx, dy, dz = dx * d, dy * d, dz * d #dy+=self.vert*VERT_SPEED x,y,z = self.actor._pos newpos = dx+x, dy+y, dz+z self.actor.pos = newpos
[docs] def get_motion_vector(self): """ Returns the movement vector according to held buttons and the rotation. :return: 3-Tuple of ``(dx,dy,dz)`` :rtype: tuple """ if any(self.move): x, y = self.actor._rot strafe = math.degrees(math.atan2(*self.move)) y_angle = math.radians(y) x_angle = math.radians(x + strafe) dy = 0.0 dx = math.cos(x_angle) dz = math.sin(x_angle) else: dy = 0.0 dx = 0.0 dz = 0.0 return (dx, dy, dz)
# Event Handlers def on_fwd_down(self,symbol,modifiers,release): self.move[0]-=1 if not release else -1 def on_bwd_down(self,symbol,modifiers,release): self.move[0]+=1 if not release else -1 def on_left_down(self,symbol,modifiers,release): self.move[1]-=1 if not release else -1 def on_right_down(self,symbol,modifiers,release): self.move[1]+=1 if not release else -1
[docs]class EgoMouseRotationalController(Controller): """ Controller allowing the user to rotate the actor with the mouse. """ def __init__(self,*args,**kwargs): super(EgoMouseRotationalController,self).__init__(*args,**kwargs)
[docs] def registerEventHandlers(self): """ Registers the motion and drag handlers. Note that because of the way pyglet treats mouse dragging, there is also an handler registered to the on_mouse_drag event. """ self.world.registerEventHandler("on_mouse_motion",self.on_mouse_motion) self.world.registerEventHandler("on_mouse_drag",self.on_mouse_drag)
def on_mouse_motion(self, x, y, dx, dy): if self.enabled: m = self.peng.cfg["controls.mouse.sensitivity"] x, y = self.actor._rot x, y = x + dx * m, y + dy * m y = max(-90, min(90, y)) x %= 360 newrot = (x,y) self.actor.rot = newrot def on_mouse_drag(self,x,y,dx,dy,buttons,modifiers): self.on_mouse_motion(x,y,dx,dy)
[docs]class BasicFlightController(Controller): """ Controller allowing the user to move up and down with the jump and crouch controls. The used keybinds may be configured via :confval:`controls.controls.crouch` and :confval:`controls.controls.jump`\ . The vertical speed used when flying may be configured via :confval:`controls.controls.verticalspeed` or the :py:attr:`speed` attribute. """ def __init__(self,*args,**kwargs): super(BasicFlightController,self).__init__(*args,**kwargs) self.speed = self.peng.cfg["controls.controls.verticalspeed"] self.move = 0
[docs] def registerEventHandlers(self): """ Registers the up and down handlers. Also registers a scheduled function every 60th of a second, causing pyglet to redraw your window with 60fps. """ # Crouch/fly down self.peng.keybinds.add(self.peng.cfg["controls.controls.crouch"],"peng3d:actor.%s.player.controls.crouch"%self.actor.uuid,self.on_crouch_down,False) # Jump/fly up self.peng.keybinds.add(self.peng.cfg["controls.controls.jump"],"peng3d:actor.%s.player.controls.jump"%self.actor.uuid,self.on_jump_down,False) pyglet.clock.schedule_interval(self.update,1.0/60)
[docs] def update(self,dt): """ Should be called regularly to move the actor. This method does nothing if the :py:attr:`enabled` property is set to False. This method is called automatically and should not be called manually. """ if not self.enabled: return dy = self.speed * dt * self.move x,y,z = self.actor._pos newpos = x,dy+y,z self.actor.pos = newpos
def on_crouch_down(self,symbol,modifiers,release): self.move -= 1 if not release else -1 def on_jump_down(self,symbol,modifiers,release): self.move += 1 if not release else -1
[docs]class BasicPlayer(RotatableActor): """ Basic Player class, subclass of :py:class:`RotatableActor()`\ . This class adds no features currently, it can be used to identify player actors via :py:func:`isinstance()`\ . """ pass
[docs]class FirstPersonPlayer(BasicPlayer): """ Old class allowing to create standard first-person players easily. :deprecated: See :py:class:`EgoMouseRotationalController()` and :py:class:`FourDirectionalMoveController()` instead """ def __init__(self,peng,world,uuid=None,pos=[0,0,0],rot=[0,0]): super(FirstPersonPlayer,self).__init__(peng,world,uuid,pos,rot) self.move = [0,0] self.movespeed = self.peng.cfg["controls.controls.movespeed"] self.active = True # Event handler registration # Forward self.peng.keybinds.add(self.peng.cfg["controls.controls.forward"],"peng3d:actor.player.controls.forward",self.on_fwd_down) self.peng.keybinds.add("release-"+self.peng.cfg["controls.controls.forward"],"peng3d:actor.player.controls.forward.release",self.on_fwd_up) # Backward self.peng.keybinds.add(self.peng.cfg["controls.controls.backward"],"peng3d:actor.player.controls.backward",self.on_bwd_down) self.peng.keybinds.add("release-"+self.peng.cfg["controls.controls.backward"],"peng3d:actor.player.controls.backward.release",self.on_bwd_up) # Strafe Left self.peng.keybinds.add(self.peng.cfg["controls.controls.strafeleft"],"peng3d:actor.player.controls.strafeleft",self.on_left_down) self.peng.keybinds.add("release-"+self.peng.cfg["controls.controls.strafeleft"],"peng3d:actor.player.controls.strafeleft.release",self.on_left_up) # Strafe Right self.peng.keybinds.add(self.peng.cfg["controls.controls.straferight"],"peng3d:actor.player.controls.straferight",self.on_right_down) self.peng.keybinds.add("release-"+self.peng.cfg["controls.controls.straferight"],"peng3d:actor.player.controls.straferight.release",self.on_right_up) # Mouse self.world.registerEventHandler("on_mouse_motion",self.on_mouse_motion) self.world.registerEventHandler("on_mouse_drag",self.on_mouse_drag) pyglet.clock.schedule_interval(self.update,1.0/60)
[docs] def update(self,dt): """ Internal method used for moving the player. :param float dt: Time delta since the last call to this method """ speed = self.movespeed d = dt * speed # distance covered this tick. dx, dy, dz = self.get_motion_vector() # New position in space, before accounting for gravity. dx, dy, dz = dx * d, dy * d, dz * d #dy+=self.vert*VERT_SPEED x,y,z = self._pos newpos = dx+x, dy+y, dz+z self.pos = newpos
[docs] def get_motion_vector(self): """ Returns the movement vector according to held buttons and the rotation. :return: 3-Tuple of ``(dx,dy,dz)`` :rtype: tuple """ if any(self.move): x, y = self._rot strafe = math.degrees(math.atan2(*self.move)) y_angle = math.radians(y) x_angle = math.radians(x + strafe) dy = 0.0 dx = math.cos(x_angle) dz = math.sin(x_angle) else: dy = 0.0 dx = 0.0 dz = 0.0 return (dx, dy, dz)
# Event Handlers def on_fwd_down(self,symbol,modifiers): self.move[0]-=1 def on_fwd_up(self,symbol,modifiers): self.move[0]+=1 def on_bwd_down(self,symbol,modifiers): self.move[0]+=1 def on_bwd_up(self,symbol,modifiers): self.move[0]-=1 def on_left_down(self,symbol,modifiers): self.move[1]-=1 def on_left_up(self,symbol,modifiers): self.move[1]+=1 def on_right_down(self,symbol,modifiers): self.move[1]+=1 def on_right_up(self,symbol,modifiers): self.move[1]-=1 def on_mouse_motion(self, x, y, dx, dy): if self.active: m = 0.15 x, y = self._rot x, y = x + dx * m, y + dy * m y = max(-90, min(90, y)) x %= 360 newrot = (x,y) self.rot = newrot def on_mouse_drag(self,x,y,dx,dy,buttons,modifiers): self.on_mouse_motion(x,y,dx,dy)