Scripting problem with WorldPosition

Hi,

I’m having a little bit of trouble with the WorlPosition command.
I want save position by pressing a key and then put the object back to the position by pressing another key. But the obj.worldPosition = pos doesn’t work.

Here’s my code

import GameLogic

# get the controller 
controller = GameLogic.getCurrentController()
senlist = controller.sensors

obj = controller.owner


on = senlist["On"]
off = senlist["Off"]
coll = senlist["Collision"]
touche = senlist["Touche"]
reg = senlist["reg"]

actlist = controller.actuators

spin = actlist["Spin"]
make = actlist["Make"]
 
if on.positive == True:
     controller.activate(spin)
     
if off.positive == True:
     controller.deactivate(spin)
     
if reg.positive == True:
    pos = obj.worldPosition
    
if touche.positive == True:
    obj.worldPosition = pos

if I put obj.worldPosition = [ 1.0, 1.0, 2.0] then it workds, but with the variable it doesn’t I don’t understand how to put it.

Also, is there a way of displaying the content of a variable? I’ve tried print(pos) but nothing happens. I don’t know where to look.

In advance thank you for your help.

I think it is because you should save “pos” permanently, for example as an attribute of GameLogic:

GameLogic.pos = obj.worldPosition

then you can retrieve it similarly:

obj.worldPosition = GameLogic.pos

Alternatively, you could create a ‘pos’ property for obj, then:

obj['pos'] = obj.worldPosition
obj.worldPosition = obj['pos']

Thank you for your quick reply but I tried what the code you gave me but unfortunately it still doesn’t work.

Some debug print is mandatory at this point.
Print outputs should be visible on system console (help menu: ‘Toggle System Console’).
Are you using blender 2.62?

Yes, I’m using the lastest version of Blender.

try the following:
import mathutils

GameLogic.pos = mathutils.Vector(obj.worldPosition)

…so, make the console visible and print(pos), according to your original idea.
Also, you should ensure that your code is activated at every frame, not only once. For example, if you use an always sensor connected to your python controller, at least one trigger button (three small dots: …) should be activated.

Problem

This is a potential error situation. You create a variable when one condition is met. You use this variable when another (independent) condition is met.

There is no guaranty that both conditions are true at the same time.

If the second condition is met but not the first one you will get an error (see console).

better do this:


if reg.positive:
    pos = obj.worldPosition    
    if touche.positive:
        obj.worldPosition = pos

Design issue
Finally this makes no sense at all as it sets what it just read (obj.worldPosition=obj.worldPosition).
The variable “pos” will not survive the end of the script.

Suggestion
I think you need to implement what mb10 suggested:


if reg.positive:
    obj["storedPosition"] = obj.worldPosition.copy()
    
if touche.positive:
    obj.worldPosition = obj["storedPosition"]

Do not forget the copy() attribute.
Reason: worldPosition returns a reference to the position of the object. That means if the position changed the value of the reference changed too as it is a reference to exactly the same data.
You are interested in the value at the time of storage not the value at the time of restore. So create a independent copy of the position with the copy() attribute.

Remarks:
Code design
I suggest to use module mode. Then implement two different access points. One to store the position and one to restore the position. This helps to keep your logic/code simple and well structured. Mixing independent code together is usually not a good idea.
e.g
MyModule.storePosition
MyModule.restorePosition

Comparing boolean values with a boolean constant.

if booleanValue == True: 

“if” expects a boolean value.
KX_Sensor.positive provides a boolean value already. You do not ned to compare it against a boolean constant. It simple eats more processing time. Better use the value directly.

if booleanValue: 

Reason:
“booleanValue == True” is logically the same as “booleanValue”.
(in opposite to:
“booleanValue == False” is logically the same as “not booleanValue”.

So, I’ve tried with the mathutils but it doesn’t work either. As for my sensors I use keyboard sensors. But I’m not sure how I can make sure the code is activated at every frame.

I do not agree with this statement. There is absolutely no reason to run code for nothing.

You do not need mathutils.
worldPosition already provides a mathutils.Vector.
THis means it has the attribute copy() as mentioned above ;).

I suspected that your code run only once, but this is not the case: if you are using keyboard sensors the script is triggered at every keypress, and this should be OK.

Can you see the console now?
Did you print object position on it?
You should see a new print at every keypress. Do you?

yes , you must using .copy() as say Monster
and store it in one property of the obj

for example , you add one property “pos” in logic brick, then change your code in this way


if reg.positive :
    obj["pos"] = obj.worldPosition.copy()
    
if touche.positive :
    obj.worldPosition = obj["pos"]

else ,there 2 error, pos save only the reference(this mean which become a “mirror” of worldPosition) plus pos , cannot survivor in the next frame

instead with copy() you cut the link and get only the value!

Despite I suggested this solution as an alternative, I’m afraid it is not feasible, because it is not possible to assign a vector to an object property: object properties, in fact, are scalars.

The following is still applicable, however:

a reason exist
become too easy the script!!! (at least seem to me!)

if you keep the sensors in the sensors , you have “2 sensors keyboard” instead of “2 if”

if you have more many sensors can become a bit mess

and many time in the script there a timer or something which need to run all frame…

change only the “position” anyway :rolleyes:

So I followed all your advice, and it still doesn’t work. I made progress though. I know where the problem is now. The debug console gives me the position so I see where things don’t do what they’re supposed to.
I made a function state_record, and at first I could not get the vector out, even though I put return and then insert the function into a variable. The result was NULL.
Finnally I can get the vector out of the fonction with the GameLogic variable. But now I have another issue I can’t fix. I watched the debug console and apparently when the “touche.position” becomes true, the position is taken again and therefore no movement is done. I tried to cheat by using other variables, x,y,z but in vain, they change as well.
I’m not sure what to do next.
Here’s my code for now, it’s not too clean for now, I’ve tried a lot of things.

def state_record():
    if reg.positive:
        pos = obj.worldPosition    
        bod = pos.copy()
        print(bod)
        GameLogic.pose = pos
state_record()  

x = GameLogic.pose[0]
y = GameLogic.pose[1]
z = GameLogic.pose[2]

if touche.positive:
print(GameLogic.pose)

print(x,y,z)
obj.worldPosition = [ x, y, z]  

I also suggest to implement what mb10 mentioned - a check to see if a key is pressed, and if so, store the value (the object’s world position) in the object (which is fine to do; object properties set in Blender (not with Python) can only be one of the predefined variable types). Then, in the other key check, restore the position to the object. It’s pretty simple:



from bge import logic

cont = logic.getCurrentController() # Controller running this script
obj = cont.owner
savekey = cont.sensors['Savekey'] # Sensor for saving the object's position; named 'Savekey' here - you can rename it what your keyboard sensor is

loadkey = cont.sensors['Loadkey'] # Sensor for loading the object's position

if not 'init' in obj: # Initialize variables
     obj['init'] = 1
     obj['lastpos'] = obj.worldPosition.copy() # Just set the object's last position variable a copy of the world position Vector

if savekey.positive:
     obj['lastpos'] = obj.worldPosition.copy()
if loadkey.positive:
     obj.worldPosition = obj['lastpos']


That should do it.

EDIT: You probably need to make sure the keyboard sensors are set to TAP to only run once, not all of the time that they’re held down. Also, you probably couldn’t get the vector out of the function because you didn’t use ‘return variable’, where ‘variable’ is the vector that you get. Just ‘return’ won’t do anything.

i never used the “global dictionary” (GlobalLogic), but i tried and work as excpected

in your script there a error


def state_record():
    if reg.positive:
        pos = obj.worldPosition    
        bod = pos.copy()
        print(bod)
        GameLogic.pose = pos #<<<<<<<<<
state_record()  


GameLogic.pose = pos
save only the reference of worldPosition!!

you need to save instead “bod”

but i counsill to not create ton of variable which make confusion.

in this way:



def state_record():
    if reg.positive:
        GameLogic.pose = obj.worldPosition.copy()
        print(GameLogic.pose)
state_record()  

or if want keep the same code:

def state_record():
    if reg.positive:
        pos = obj.worldPosition    
        bod = pos.copy()
        print(bod)
        GameLogic.pose = bod
state_record()  


:wink:

the script of SolarLune is complete… in fact the variable can be created “on the fly” in the script also…

Yeah, it could, but then there’d be an error if you pressed the load key before the save key.


if not 'init' in obj: # Initialize variables
     obj['init'] = 1
     obj['lastpos'] = obj.worldPosition.copy() # Just set the object's last position variable a copy of the world position Vecto

this provvide to avoid this potential error
for this,I prefer keep the script which run ever…(laziness :wink: )