python copy worldposition restrictet to X and Y

hi,
i want to copy the location from one obj to another like this

object1.worldposition = object2.worldposition

no problem…so far
but i want the obj2 to stay in Z Axis = 0

how can i access the Axis in the code ?

i could set pos X to 0 after copy position - or i could limit the assignment to X and Y ???

thx for helping :slight_smile:

you can access the individual axis like this:

Obj1posX = Obj1.worldPosition[0]
Obj1posY = Obj1.worldPosition[1]
Obj1posZ = Obj1.worldPosition[2]

Obj2posX = Obj2.worldPosition[0]
Obj2posY = Obj2.worldPosition[1]
Obj2posZ = Obj2.worldPosition[2]

Obj1.worldPosition[0] = Obj2posX

CTBM

nice :slight_smile: it works
thank you !

as worldPosition provides and mathutils.Vector you can access the axis attributes etc. worldPosition.x too.

S1 = own.worldPosition
S2 = target.worldPosition
S2.z=S1.z

own.worldPosition = S2

//this copies X,Y of target, but not Z

Be careful, this sets the position of the game object “target” as well!
The attribute worldPosition returns a reference to the game objects worldPosition.

With S2 = … you copy the reference (not the value). This means S2 and target.worldPosition refer to the identical vector object.

When you do S2.z = … you change the value of the vector. It is still referred by S2 and by worldPosition. This let the game object target teleport to the changed coordinates.

own.worldPosition = S2 distributes the reference even further.

Game object “own”, S2 and game object “target” refer to the same (already changed) vector. This means “own” and “target” will occupy the same position in space.

Remarks:

  • use a naming convention. Variables should be lower case or Upper case not both.
  • use meaningful names (S1, S2 do not have a meaning in this context, I guess target was meant to be “source” :wink: )
  • be aware of side effects

Solution:
break the reference -> copy the value


ownerPosition = own.worldPosition
sourceObjectPosition = sourceObject.worldPosition.copy()
sourceObjectPosition.z = ownerPosition.z

own.worldPosition = sourceObjectPosition

In this situation it is more efficient and easier to understand to copy the single axis:


own.worldPosition.x = sourceObject.worldPosition.x
own.worldPosition.y = sourceObject.worldPosition.y

thx for the replies - interesting to see different solutions and aspects of copy loc !

@Monster - if i get you - in easy words - i should avoid referencing worldposition or attributes in general ?

what is that mean > .copy()
is that copying the value instead of referencing to it ?

@Monster: Your last solution is the nicest way - many thx :slight_smile:

i think (until now) that referencing is (in this case) just a way to create better readable code…

in lot of scripts referencing is used a lot (is every = a reference to an obj or attribute ?)
here another exsample - is there too much referencing going on ?


gl = bge.logic 
 
scene = gl.getCurrentScene() 
List = scene.objects 
cont = gl.getCurrentController() 
own = cont.owner 
 
### you can replace the ['xxx'], with the name of your target object. 
pos = List['xxx'].worldPosition 
own.worldPosition = pos 

could/should i write
List = gl.getCurrentScene().objects
instead of
scene = gl.getCurrentScene()
List = scene.objects

?

thx, Tobi

Firstly, you may also use list slicing to assign the axis:
obj.worldPosition[:2] = otherobj.worldPosition[:2]

Also, no you should really avoid one-liners.
It’s a common feeling that people should use one lines wherever possible. The most important thing is readability.
Secondly, avoid using builtins as local variable names. list is very similar to List, except list is a referral to the built-in list constructor.

No, references are cheap as just a few data are transferred. Unfortunately you can get such side effects as described above. So you need to know about that.

copy() does what you expects - it copies the object (the vector). You get a reference to the copy (rather than the original).
If you modify the copy, the original will not be influenced.

The = operator means "assign what is on the right side to the left side.

This means if the right side gives you a reference, the reference will be assigned.
If the right side is a value (string, int, float…) the value will be assigned.
In that way the reference is a value as well ;).

How to know it is a reference? This is not easy. Thumb rule:
If it is a primitive type (string, number) it is usually a value.
If it is complex (list, dictionary, module, class, function) it is usually a reference.
If you really want to know use the “is” attribute or the “id()” function.


data = ownerObject.worldPosition
if data is ownerObject.worldPosition:
  print( "data is a reference to ownerObject.worldPosition")
#alternative:
#if id(data) == id(ownerObject.worldPosition):

#different check!
if data == ownerObject.worldPosition:
  print("data contains data that are equal to ownerObject.worldPosition")

You will see the same thing on function arguments/parameters. This is especially dangerous as you might not see the side effect.
Therefore a good rule is:

  • avoid changing an argument within a function
    If you need to pass data back,do it by return or use a class

helloString= "Hello"
helloWorldString = append(helloString, " World")

def append(prefix, suffix):
  return prefix + suffix
  #rather than prefix += suffix


helloWorldContainer = StringContainer("Hello")
helloWorldContainer.append(" World")

helloWorldString = helloWorldContainer.completeString

class StringContainer():
  def __init__(self, prefix):
    self.completeString= prefix

  def append(self, suffix):
    self.completeString+= suffix

I hope it does not confuse you.

As agoose77 wrote: “The most important thing is readability.”

It does not matter if it works. (As a programmer you should be able to create code that works). If it is hard to read it is bad code. A professional programmer creates clean code (which indeed works and is readable :wink: ).

Actually, in python all things are references. The reason that some things don’t behave like referred values is because integers, numbers and booleans are not mutable; when you edit the value it returns a new value

many thx guys - that helps me a lot !

@Monster - thx for explaining - and no - it dont confuses me :slight_smile:
i am for example very good in shell programming and other scipting languages (i was a unix trainer for some years) - but with object oriented languages i still have my problems… to get forward with BGE Python i read the API docs and your BGE Guides and Libarys of course - and ask some question - and with such precise answers its really fun learning :wink: thank you very much !
cu
Tobi

Thank you this explains why I have been having so much trouble…

so many hours over a simple .copy()
:slight_smile: