This script allows you to easily drag objects. There are several options that you can use to customise it, they are as follow:
- Choose which plane to drag the object in (camera’s, xy, yz, xz)
- Choose whether to have an object snap to the drag location or move towards it
- Choose which mouse button to drag with
- Choose how quickly an dragged object moves (if you have chosen for it to move there)
- Choose whether a dragged object retains it’s velocity once dragging is completed
These are specified as properties on the object, see the script for details.
This script is also quite accurate, if you click in the corner of a cube when you start dragging you can expect the mouse to be over that exact same spot as you finish dragging.
No other sensors apart from an always sensor are needed. Just add a python controller to the object you want to drag, set the controller mode to module and type in ‘drag.main’ then configure the options as described in the script.
Example: drag.blend
"""
drag.py - drag an object in a plane
andrew-101, June 2011, Blender 2.57
Add this script to an object to be able to use the mouse to
drag that object around. You can choose to either drag the
object parallel to the camera's plan, the xy plane, the yz
plane or the xz plane. You can also choose to instantanously
snap the object to the drag position or have it move towards
it making it aware of collisions (requires dynamic or rigid
body physics type)
Usage:
1. Add a python controller set to module and set the
script to be 'drag.main', connect that to a always
sensor with true level triggering.
2. (optional) add a property 'drag_plane', set it to:
'cam' to drag parallel to camera's plane (default)
'xy' to drag parallel to xy plane
'yz' to drag parallel to yz plane
'xz' to drag parallel to xz plane
3. (optional) add a property 'drag_type', set to:
'snap' to snap to drag location for use with static
body type (default)
'move' to use force to move to the drag location, for
use with dynamic/rigid body types
4. (optional) add a property 'drag_event' and set it to
the event constant (of bge.events) you wish to trigger the
drag with, e.g:
'LEFTMOUSE' (default)
'RIGHTMOUSE'
'MIDDLEMOUSE'
5. (optional) add a property 'drag_speed' for usage
with the move type. When being dragged the object will be
forced to always move slower than this. Default is 15.0
6. (optional) add a property 'drag_retain' and set to:
True in order to retain velocity when dragging is
halted.
False in order to set velocity to 0 when dragging is
halted. (default)
"""
import math
import bge
from mathutils import *
PLANE_CAM = 'cam'
PLANE_XY = 'xy'
PLANE_YZ = 'yz'
PLANE_XZ = 'xz'
PLANES = { \
'xy': Vector([0,0,1]),\
'yz': Vector([1,0,0]),\
'xz': Vector([0,1,0])\
}
TYPE_SNAP = 'snap'
TYPE_MOVE = 'move'
def get_point_behind_mouse():
cam = bge.logic.getCurrentScene().active_camera
m_pos = bge.logic.mouse.position
c = Vector([2*m_pos[0]-1, 2*(1-m_pos[1])-1, 0, 1])
v = c * cam.projection_matrix.inverted()
return (v / v.w) * cam.modelview_matrix.inverted()
def get_constrained_position():
# constrain a point to the plane
own = bge.logic.getCurrentController().owner
cam = bge.logic.getCurrentScene().active_camera
p = Vector(get_point_behind_mouse()[:3])
c = cam.worldPosition
o = own.worldPosition-own['drag_point']
plane = own.get('drag_plane', 'cam')
if plane.lower() == PLANE_CAM:
n = cam.worldOrientation[0].cross(cam.worldOrientation[1])
else:
n = PLANES[plane.lower()]
return c + (n.dot(o-c) / n.dot(p-c)) * (p-c) + own['drag_point']
def main(cont):
own = cont.owner
mouse = bge.logic.mouse
event = getattr(bge.events, own.get('drag_event', 'LEFTMOUSE'))
if not own.get('drag_state'):
own['drag_state'] = False
own['drag_distance'] = 0
if own['drag_state']:
if mouse.events[event] == bge.logic.KX_INPUT_JUST_RELEASED:
# finish dragging
own['drag_state'] = False
if not own.get('drag_retain', True) or own.get('drag_type', 'snap') == 'snap':
own.worldLinearVelocity = [0,0,0]
else:
# update dragging
drag_pos = get_constrained_position()
drag_speed = own.get('drag_speed', 15.0)
type = own.get('drag_type', TYPE_SNAP)
own.applyForce([0,0,own.mass*9.8]) # cancel effect of gravity while dragging
if type == TYPE_SNAP:
own.worldPosition = drag_pos
elif type == TYPE_MOVE:
distance = own.getDistanceTo(drag_pos)
own.applyForce(200*(drag_pos-own.worldPosition))
vel = own.worldLinearVelocity
if vel.magnitude > min(5*distance, drag_speed):
vel.magnitude = min(5*distance, drag_speed)
own.worldLinearVelocity = vel
elif mouse.events[event] == bge.logic.KX_INPUT_JUST_ACTIVATED:
# initiate dragging
cam = bge.logic.getCurrentScene().active_camera
p = get_point_behind_mouse()
hit_obj, hit_pos, hit_norm = cam.rayCast(p[:3], cam, cam.far)
if own == hit_obj:
own.worldLinearVelocity = [0,0,0]
own['drag_point'] = own.worldPosition-hit_pos
own['drag_state'] = True
Attachments
drag.blend (485 KB)