Is there a new method to set an object's position to a stored position value in 2.5?

Because in one line of my script for one of my older games I have this line of code that runs for one logic tic. when needed


GameLogic.startpos=own.position

And then in another line if I need to reset the position I do


own.position = GameLogic.startpos

This worked perfectly in 2.49, but in 2.5 the position stopped getting reset, I tested to see if it was still working by replacing the line that resets the position to something like


own.position = (0,10, -10)

And it sets the object’s position to the specified value like one would expect.

It seems to me that setting a position to a stored position in something like a GameLogic variable isn’t working if you do things in the same way as in 2.49, so I wonder if there’s a different way you have to do it in 2.5. It seems clear to me that you can’t just set the position to a stored one like in a GameLogic variable because I even tried


own.position = (0, 10, GameLogic.startpos[2])

And it set the object’s position like it should for the X and Y axis, but not for the Z-axis, so is there a different method of changing an object’s position to a stored position like one in a GameLogic variable in 2.5 or what?

To copy a list (as opposed to just storing a reference to a list) use slicing:


GameLogic.startpos = own.position[:] # Copies the list
GameLogic.startpos = own.position # Stores a reference to the list

This should have been a problem in 2.49 as well though. Maybe Python 2.6 was more forgiving?

Also, you should use either worldPosition or localPosition as position has been deprecated. The position property did some goofy things, like having different sets and get behaviors. For example:


own.position = own.position

would actually move the object (I think).

Cheers,
Moguri

So would I put those 2 lines down whenever I want to set the object’s position to one stored in a GameLogic variable, a generic tuple, or the position of an empty then and it would work, only difference being I use worldPosition because it’s the closest to the old position property?

I understand if you want us to use worldPosition or localPosition now because of the old property doing goofy things if that would mean our code works like it should more and gives us less frustration. (or the old property simply gets removed later on)

For one, you should avoid using GameLogic as a storage container for all values - you should only use that for things that truly need to be global.

If you need to remember some previous position, store it on the object itself:

own["pos"] = own.worldPosition.copy() # worldPosition is now an Implicit Vector

API docs for Mathutils Vector: http://www.blender.org/documentation/249PythonDoc/GE/Mathutils.Vector-class.html

I already use local object properties to store a previous position in games that have a lot of objects needing to store their positions, this game has just one object that needs its position stored from time to time so I can use just 1 or 2 GameLogic variables and not overload on them, plus then if other objects need to access it they can.

And most of the other values the object uses is done locally and not globally, so I don’t use GameLogic for every value.

Solved the problem by trying to understand what Moguri meant.

Seems like you don’t put those two lines together, you use code like


GameLogic.startpos = own.worldPosition[:]

To assign the value of a new position to another variable and then


own.worldPosition = GameLogic.startpos

When you want to assign an object’s position to the position that was stored and thus move the object there.

I think I get it now because the code works again (I never knew about the [:] thing and how that was important because it wasn’t needed in Python 2.6), thanks for the help.

I didn’t say you did, I simply advised that it’s something you should avoid.

My greater point was the part that followed: “you should only use that for things that truly need to be global” - the situation you describe doesn’t justify a global, in the sense that position information for an object has an obvious relation to that object. Therefore, any potential need to access that information, from some other object, should be satisfied by getting the object reference itself, rather than one specific piece of information that relates to it.

Also, copying a vector through list slicing is bad practice, for a wide variety of reasons, but mainly for the fact that it’s nowhere near as readable as own.worldPosition.copy().

For BGE Mathutils Vector types (which is what worldPosition actually is in 2.5), the native copy method should be used to create a full copy of the vector object in question.

For lists, one should use the following syntax: new_list = list(old_list).

Slicing should be used only when you actually need to extract a list slice.

All in all, the right way to save and restore position is:

own["pos"] = own.worldPosition.copy()

And then restore:

own.worldPosition = own["pos"]

I see what you mean by the .copy() extension, it adds a rather insignificant amount of length to the line of code it’s in compared to [:], but you can read better on what it does and is easier to find if you need to change something related to it, and it also works like the other method.

Yes, copy() is probably a better route. One thing that wasn’t mentioned is that using slicing you turn the vector into a list.

Thank you, gentlemen. You have lifted a cloud of confusion from my Python understanding. I too had gotten into the bad habit of using GameLogic as a catchall in order to avoid referencing simply because I did not properly understand what was happening or how to correctly work around it.

May I ask: Is there also a function which will specifically create a reference instead of a full copy? I’ve had mixed results with the direct method which Moguri demonstrated above. (Edit: In past versions of Blender that is. Haven’t tried it much in 2.5 yet.)

In blender 2.49b, I don’t think it’s actually possible to get a worldPosition reference; blender returns the copy by default. I don’t know why it was done that way (maybe some misguided effort to make things “easier”, since, for the most part, a copy was what you usually wanted), but that little piece of inconsistency always bothered me.

Aside from any blender-specific hacks, in Python, returning references on assignment is the default behavior (assuming that the object in question is mutable - for basic things like bools, ints, floats, strings, tuples … etc, you will always get a full copy).