Moving an object using python

Hi,

I havent used blender for a few years and was hoping someone could tell me whats wrong with the following code


import GameLogic as g
cont = g.getCurrentController()
own = cont.owner


aVector = [1.0,1.0,1.0]
bVector = [5.0,5.0,0.0]


for l in range(1, 101):
    l2 = l / 100.0
    cVector = [ aVector[0] + ((bVector[0]-aVector[0])*l2), 
                    aVector[1] + ((bVector[1]-aVector[1])*l2), 
                    aVector[2] + ((bVector[2]-aVector[2])*l2) ]
    
    own.localPosition = cVector    
    print(l2,cVector)



Looking at the console the cVector is smoothly interpolated between the aVector and bVector however on screen the object this is attached to just sits at the bVector coordinates.

Anyone have any ideas?

A for loop takes place in a single game frame, so even if it’s evenly and smoothly interpolated, the result will be what’s shown. I think you’d do better using actual vectors with the mathutils module (with Blender 2.5+), getting the difference, and then setting that difference to be the number of Blender Units you want to move in the game frame. Then, add that to the object’s position.

have a look at:
BGE Guide to the GameLoop
and
BGE Guide to Python Coding

I will find some interesting things regarding loops in Python code ;).

Beside that I agree with SolarLune, better use the Vector methods rather than treating them as lists ;).

SolarLune, thanks for the quick reply and the information on the for loop- now it makes sense. I think i follow what you’re saying but will this still allow me to move the object slowly from one point in space to another?
Monster, thanks for the links i’ll take a look at these later today.

Ive had a look at mathutils and the lerp feature seems perfect but I can’t figure out how this could be used without a for loop as it takes a float between 0.0 and 1.0 to interpolate between the two vectors.

I think I’ve figured out two ways of doing what I wanted and hope i’m using Vectors as opposed to lists but am not sure,

  1. This works whatever the first and second vector are, ie can move an object diagnolly in space, from say [0,2,0] to [5,-1,6] - the only problem is it never reaches the second vectors coordinates, the object will get to [4.999r,-0.999r,5.999r]. This is a problem for me as another part of my script is checking where certain objects are placed and so querying [5,-1,6] would tell me there’s no object there as it’s at [4.999r,-0.999r,5.999r]. I did try to implement a bit of code to check if the object is close to an integer vector and round the number up or down but this caused jerky motion.

import GameLogic as g
import random
import mathutils
cont = g.getCurrentController()
own = cont.owner

aVector = own.worldPosition
bVector = mathutils.Vector((1.0, 5.0, 0.0))


if bVector != aVector:
    
    cVector = aVector + ((bVector-aVector) * 0.01)
    own.worldPosition = cVector



  1. Fortunately I’m only moving objects in straight lines along the objects axis’s, so the following works for me although its not as concise it does have a rounding feature that doesn’t result in jerky motion.

import GameLogic as g
import random
import mathutils
cont = g.getCurrentController()
own = cont.owner

aVector = own.worldPosition
bVector = mathutils.Vector((-1.0, 0.0, 0.0))

if bVector[0] < aVector[0]:
    
    moveVec = mathutils.Vector([-0.01, 0.0, 0.0])
    own.worldPosition += moveVec
    if bVector[0] - aVector[0] > 0.0:   #cleanup 
        own.worldPosition[0] = bVector[0]

if bVector[0] > aVector[0]:
    
    moveVec = mathutils.Vector([0.01, 0.0, 0.0])
    own.worldPosition += moveVec

if bVector[1] < aVector[1]:
    
    moveVec = mathutils.Vector([0.0, -0.01, 0.0])
    own.worldPosition += moveVec
    if bVector[1] - aVector[1] > 0.0:  #cleanup
        own.worldPosition[1] = bVector[1]

if bVector[1] > aVector[1]:
    
    moveVec = mathutils.Vector([0.0, 0.01, 0.0])
    own.worldPosition += moveVec

if bVector[2] < aVector[2]:
    
    moveVec = mathutils.Vector([0.0, 0.0,-0.01])
    own.worldPosition += moveVec
    if bVector[2] - aVector[2] > 0.0:  #cleanup
        own.worldPosition[2] = bVector[2]

if bVector[2] > aVector[2]:
    
    moveVec = mathutils.Vector([0.0, 0.0, 0.01])
    own.worldPosition += moveVec


  

I hope this can be of help to someone and if anyone has any idea of how to use the lerp function of vector without a for loop i’d be really interested to know!

Breaking this down, you will realise that this is a less difficult task than you realise.
LERP means a linear interpolation between two values. It usually involves a normalised factor(time) value.
Therefore, there are a few methods that you could acheive your goal.
You first is to use LERP with a delta time. Here is some sample code


from mathutils import Vector
from time import time

def apply_velocity(a, b, elapsed, duration):
   fac = elapsed / duration
   return a.lerp(b, fac)

def velocity(cont):
   own = cont.owner

   try:
      start = own['start']
      original = own['position']
   except KeyError:
      start = own['start'] = time()
      original = own['position'] = own.worldPosition.copy()

   elapsed = time() - start

   target = Vector((0, 10, 0))
   duration = 5.0

   own.worldPosition = apply_velocity(original, target, elapsed, duration)

Alternatively, you could work out the displacement needed per game tick to get to the new position, and update the object position each time (although I prefer the first method as it will be true to the elapsed time, not tick rate)

@glitchCORD - Why don’t you just:



import GameLogic as g
import random, mathutils

cont = g.getCurrentController()
own = cont.owner

dest = mathutils.Vector((1.0, 5.0, 0.0)) 
     
diff = dest - own.worldPosition
 
if diff.magnitude > 0.1:
     #diff *= 0.1               # Smooth
     diff.magnitude = 0.1   # Even

own.worldPosition += diff


Subtracting the destination vector from the world position of the object will give you another vector. If the magnitude of this vector’s greater than a certain amount (0.1), then you can set it to be 0.1 so that it will move toward the destination, 0.1 Blender Units per frame. If the value is less than that, then the object won’t over-shoot it, but will just set its position to be the destination’s exactly (as the difference between the object position and the destination position isn’t altered).

EDIT: Multiplying the vector gives a more accelerated / ramped approach to the target destination point, since it’s taking ten percent of the distance remaining each game frame. With magnitude, it will move exactly that many Blender Units per game frame. There’s a little bump if you choose the smooth movement. This can be solved by just lowering the value you check the difference’s magnitude by (instead of diff.magnitude > 0.1, you could use diff.magnitude > 0.01).

agoose77, thank you, Using time instead of a for loop makes sense and I can kind of follow whats going on in the code although it’s time like this I realise I need to learn what defining functions are all about.

SolarLune, this is perfect and succinct, thank you. I’m a little unsure of how it works- and would like to figure it out, I’ve tried printing things to the console and looking at the API- if you have a minute could you tell me if i’ve “got it”. I’ve commented the code with what i think is going on.



import GameLogic as g
import random, mathutils

cont = g.getCurrentController()
own = cont.owner

dest = mathutils.Vector((1.0, 5.0, 0.0))   
   
diff = dest - own.worldPosition   # diff = difference between the original position and the destination position we want to move to.  

if diff.magnitude > 0.1:    # If the distance between the original and destination position is greater than 0.1     
    diff.magnitude = 0.1   # Make the Vector a 10th of its current size 

own.worldPosition += diff # Add the 10th of it's current size to the current position

You’re right about that above. diff.magnitude = 0.1 is making the vector a 10th of its current (or original) size, but it’s also 0.1 Blender Units, so be aware of that. While this method works fine, agoose77’s method looks very interesting for moving within a certain amount of time (i.e. get to the destination in 5 seconds).