Smooth automatic camera move with python

cont = GameLogic.getCurrentController()
own = cont.getOwner()
own.setPosition(position)

Setting object’s location is pretty simple. I’m trying to find a way of smoothly panning from one location to another. The example above directly teleports the camera to its destination right away. Has anyone worked out any algorithms to smoothly move the camera?

cont = GameLogic.getCurrentController()
own = cont.getOwner()

objCam = objList["Camera"]
targetloc = objCam.getPosition()

if newloc[1] > targetloc[1]:
    targetloc[1] += 0.01
if newloc[1] < targetloc[1]:
    targetloc[1] -= 0.01

if newloc[2] > targetloc[2]:
    targetloc[2] += 0.01
if newloc[2] < targetloc[2]:
    targetloc[2] -= 0.01

if newloc[3] > targetloc[3]:
    targetloc[3] += 0.01
if newloc[3] < targetloc[3]:
    targetloc[3] -= 0.01

 own.setPosition(targetloc)

Should work simply enough, but isn’t very graceful (and you’d need to truncate the location decimals).

A more graceful method would involve defining a start and end point and tracking the camera along the line between those points, but I have no clue how to start about doing that. Does anyone have any ideas?

Here’s a start of an idea.

# Get the difference in location between points on X/Y/Z
xdiff = newloc[1] - targetloc[1]
ydiff = newloc[2] - targetloc[2]
zdiff = newloc[3] - targetloc[3]

# Divide by whatever you wish. Whatever you divide by will be roughly
# the number of frames it takes to complete the track.
xstep = xdiff / 100
ystep = ydiff / 100
zstep = zdiff / 100

# Take small steps till we get there.
if newloc != targetloc:
        targetloc[1] += xstep
        targetloc[2] += ystep
        targetloc[3] += zstep

The division of the differences will (almost) never be a factor of newloc. So targetloc will never be equal to newloc, and so the camera it will overshoot it’s target. So if it’s close enough to its target, we’ll just go ahead and set it. We can do this with a near sensor. So when the camera is a certain tolerance from its destination, it automatically sets itself as being there.

targetloc = newloc

But this presents a problem for large distances. If the steps between each frame are too large, the camera will overstep its destination. Perhaps this could be solved by having a script set the ‘distance’ in the ‘near’ sensor to being equal to 1/2 of whichever is larger: xstep, ystep, or zstep.

I’m starting to think I should have posted this in the python forums instead… >_>

sorry, the signal/noise ration is horribly low in this forum, an interesting thread like this one gets covered by questions that were asked 9000 times, “highly detailed” question threads, etc.

btw, you might look how campbel rigged the camera for apricot, its a pretty neat setup

Well, it’s probably interesting…but, if you can post a little example, it’ll be much more, I guess?!

http://userpages.umbc.edu/~smyth1/blender/smoothmove.blend

Hey, it works.

controller = GameLogic.getCurrentController()
owner = controller.getOwner()
objList = GameLogic.getCurrentScene().getObjectList()

# Get objects and locations
obstart = objList["OBstart"]
start = obstart.getPosition()
obend = objList["OBend"]
end = obend.getPosition()

print start, end

# Get the difference in location between points on X/Y/Z
xdiff = start[0] - end[0]
ydiff = start[1] - end[1]
zdiff = start[2] - end[2]

# Divide by whatever you wish. Whatever you divide by will be roughly
# the number of frames it takes to complete the track.
xstep = xdiff / 100
ystep = ydiff / 100
zstep = zdiff / 100

# Take small steps till we get there.
if start != end:
    start[0] -= xstep
    start[1] -= ystep
    start[2] -= zstep
    
obstart.setPosition(start)

Still needs some cleaning up to detect if a value is positive or negative and move in that direction (note that it only moves in one quadrant as it is) but that shouldn’t be difficult. Problems I anticipated before aren’t really problems at all. I’ll clean it up a bit post a more useful version in a bit. I hope someone finds this helpful.

Alrighty, I’ll just go ahead and call this version 0.1. It works great. I hope someone finds this useful. I’ve updated the example file here: http://userpages.umbc.edu/~smyth1/blender/smoothmove.blend

#######################################
# Smoothmoves.py
# Version: 0.1
# by James Smyth (2008)
#
# Takes a target and moves an object
# gracefully towards it.
#######################################

controller = GameLogic.getCurrentController()
owner = controller.getOwner()
objList = GameLogic.getCurrentScene().getObjectList()

# Define your targets here.
stalker = "OBstart"
target = "OBend"

# This determines how fast it approaches.
# The larger the number, the slower the approach.
factor = 50

# Get objects and locations
obstart = objList[stalker]
start = obstart.getPosition()
obend = objList[target]
end = obend.getPosition()

# Get the difference in location between points on X/Y/Z
xdiff = start[0] - end[0]
ydiff = start[1] - end[1]
zdiff = start[2] - end[2]

# Divide by whatever you wish. Whatever you divide by will be roughly
# the number of frames it takes to complete the track.
xstep = xdiff / factor
ystep = ydiff / factor
zstep = zdiff / factor

# Take small steps till we get there.
if start != end:
    start[0] -= xstep
    start[1] -= ystep
    start[2] -= zstep
        
# Make our difference variables positive
if xdiff < 0:
    xdiff = xdiff * -1
if ydiff < 0:
    ydiff = ydiff * -1
if zdiff < 0:
    zdiff = zdiff * -1

# If we're within 0.01 of the target, we'll just
# go ahead and move it there.
if (xdiff < 0.01) and (ydiff < 0.01) and (zdiff < 0.01):
    start = end

# Set the position
obstart.setPosition(start)

EDIT: And here’s a version using the state system. Very simple. It’s useful for keeping the script from running constantly, eating up resources.
http://userpages.umbc.edu/~smyth1/blender/smoothmove-with-states.blend

wow thanks for posting… I was hoping you would… really keen to dissect this…

Sure thing. Of course, this can be applied to more than a camera. Here’s an example watching some objects.
http://userpages.umbc.edu/~smyth1/blender/smoothmove-with-stalker.blend

That’s very interesting, and works pretty well! I have had places where I’ve needed to do this with objects that have physics enabled (podracers :)), and so I derived some physics formulas to give me the correct forces (x,y,z), from F = ma and Dx = 1/2 at^2+vot

Here is the solution for force along the global x axis.

timecst = .4
Fx = (2*mass*((goalX-posX)-own.getVelocity()[0]*timecst))/(timecst*timecst)
motion.setForce(Fx,0,0,0)

This method has some disadvantages: I haven’t quite figured out how to keep my pod engines from jumping through walls.