Manipulating Added Objects

OK…

I have:

  1. Empty1 (the empty obj that contains all the code, and adds the second object “obStem” which is also an empty)

  2. obStem (acts as the “Stem” of the tree, and has many empties parented to it which act as spawners for leafs that are on a different layer)

  3. objLeaf (just a simple object that looks like a leaf thats in a hidden layer)

So here is the sequence:

  1. Empty1 spawns obStem (along with all the leaf spawning empties that are parented to it)
  2. Empty1 then tells all the leaf spawning empties, that are parented to obStem, to each spawn a leaf

Now…my question is:

I want to manipulate these leaves. and in order to do so, i must define them. how can i define these leaves as they are added? I understand that you can use “newobj = scene.addObject(obj2, obj1, 0)” to define a single object that is added. but it doesnt seem to work in my code that is shown below. Any ideas?

def AddTree():
scene.addObject(“TreeStem”, Owner, 1);
TreeChildren = scene.objects[“OBTreeStem”].children;
for obj in TreeChildren:
if “Leaf 1 Spawner” in obj.name:
leaf1 = scene.addObject(“Leaf 1”, obj, 0)
if “Leaf 2 Spawner” in obj.name:
leaf2 = scene.addObject(“Leaf 2”, obj, 0)
if “Leaf 3 Spawner” in obj.name:
leaf3 = scene.addObject(“Leaf 3”, obj, 0)
if “Leaf 4 Spawner” in obj.name:
leaf4 = scene.addObject(“Leaf 4”, obj, 0)
if “Leaf 5 Spawner” in obj.name:
leaf5 = scene.addObject(“Leaf 5”, obj, 0)
if “Leaf 6 Spawner” in obj.name:
leaf6 = scene.addObject(“Leaf 6”, obj, 0)

What manipulation are you aiming for?

You can manipulate the objects without the need to know an (order). You can see it as a bunch of leaves.
You can get them by name as they share the same one


def getLeaves():
  return [leaf for leaf in scene.objects
         if leaf.name == "objLeaf"

then you can operate on this bunch of leaves.

If you need an order you can make a projection. Something like a sort operation.

I keep seeing people say this without any explanation of what exactly doesn’t work or any indication that they’ve tried to debug the code themselves. When using a Python script, errors telling you exactly what went wrong and where are printed in the console window (you can open it under Window->Toggle System Console).

A few things that are obviously wrong with this code:

  1. You have no indentation. In Python you use indentation to denote nested blocks of code (whereas in other languages like C and Java you would use braces {}). Actually I’m guessing you had the correct indentation, but it’s not showing it because you didn’t post the code using the code tags.
  2. You’ve ended a couple lines with semicolons. Python doesn’t use those.
  3. The variables scene and Owner are undefined in the function’s scope, so unless they’re declared as a globals elsewhere you’ll get an error.

where is definited “Owner”?
it just not work or retun o tons of errors?

PS:certain the code can be written better with a loop

where is definited “Owner”?
it just not work or retun o tons of errors?

PS:certain the code can be written better with a loop

my code is indented correctly, but it gets lost as i paste it into BA’s text field. And the variables “scene” and “Owner” are defined in teh rest of my script. The code shown is just the important snippet where the error is occuring.

Ok, did you look at the error in the console and try to fix it?

Yes that would work. But only for accessing all the leafes in the current scene. Even the leafs that belong to other trees. I need a way to define only the leafs that belong to the tree that is running the script.

ok, so it doesnt give me the error when i set the added objects as a variable. But when i add a simple “print(leaf1)” to the end of the function it returns this error:

“UnboundLocalError: local variable ‘leaf1’ referenced before assignment”

Then there must not be an object named “Leaf 1 Spawner” in the stem object’s children. I suggest you put a print statement in the for loop that prints obj.name to make sure you have all the child objects you’re expecting.

On the contrary, there are actually multiple objects parented to the stem with the name “Leaf 1 Spawner”.

ex: Leaf 1 spawner.001, Leaf 1 spawner.002 etc

But now, instead of adding the print(leaf1) at the end of the function. I am adding code that has each leaf end itself right after it has been defined (literally 1 line under) and it seems to be working!!! I will run some more tests and let you know. Thanks so far!

Strings are case sensitive, so

"Leaf 1 Spawner" in "Leaf 1 spawner.001"

will return False since the s is lower case in the second string.

ok mobi. Here is what i found out… When I do use the traditional “leafs = scene.addObject()”, it does in fact define all the leafs that have a similar name. I tested this by simply changing the orientation of the selected leafs. In addition. I have found it also possible to assign a string property to each of these selected leafs. So I do now have access to each of these objects.

But now that “leafs” another question. Is there a better way to do this? The new problem is the fact that “leafs = scene.addObject()” is defined as a local variable. Is there any way to make it global so I can use it in another function? Like, instead of adding an extra property to each of these leafs in order for the script to detect it, couldnt I “mark the leafs from within the script”? Like, for “leafs = scene.addObject()”, is there a way for me to make the property global and not have to waste memory on ill needed properties?

You could have a global list and append each leaf to the list in the function. I would recommend just returning a list of the leaves in the function and use that elsewhere.

def AddTree():    scene.addObject("TreeStem", Owner, 1)
    TreeChildren = scene.objects["OBTreeStem"].children
    leaves = []
    for obj in TreeChildren:
        if "Leaf 1 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 1", obj, 0)
        elif "Leaf 2 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 2", obj, 0)
        elif "Leaf 3 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 3", obj, 0)
        elif "Leaf 4 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 4", obj, 0)
        elif "Leaf 5 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 5", obj, 0)
        else:
            leaf = scene.addObject("Leaf 6", obj, 0)
        leaves.append(leaf)
    return leaves

ive never really used teh elif statement before. what exactly does it do?

elifs are only executed if none of the previous if/elif statements were True. For example:

if False:
    print('A')
elif True:
    print('B')
elif True:
    print('C')

only prints B.

In your case, using just if statements works fine, but you’re unnecessarily preforming more checks on the object’s name after it has already been added. Using elifs lets you continue the loop as soon as you match the object’s name.

Why not simply parent the added objects to the object that adds them?
This way leaves are in the same hierarchy tree as the stems and empties. You can simply traverse through the tree to find all the leaves (as you do already).

There are two options to establish that:
A) each empty creates and parents his own leaves.
B) a builder object creates the and parents the leaves of a number of empties (e.g. the trunk does that for all children that are empties)


“elif” is a short notation of “else if” which concatenates two “if … else …” statements

I would do that, however, my leaves are going to be dynamic. And the parenting would render them static.

ok, so use elif if i find myself having to repeat the same if statement over and over. And what about the else statement at the end? Why isnt that elif aswell? Does it like mark the end of the loop or something?

I just did that to ensure leaf always gets defined. If there are other child objects that you don’t want to spawn a leaf object on, you can change the last couple else statements to:



def AddTree():
    scene.addObject("TreeStem", Owner, 1)
    TreeChildren = scene.objects["OBTreeStem"].children
    leaves = []
    for obj in TreeChildren:
        if "Leaf 1 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 1", obj, 0)
        elif "Leaf 2 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 2", obj, 0)
        elif "Leaf 3 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 3", obj, 0)
        elif "Leaf 4 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 4", obj, 0)
        elif "Leaf 5 Spawner" in obj.name:
            leaf = scene.addObject("Leaf 5", obj, 0)
        elif "Leaf 6 Spanwer" in obj.name:
            leaf = scene.addObject("Leaf 6", obj, 0)
        else:
            continue
        leaves.append(leaf)
    return leaves

The continue statement immediately goes to the next iteration of the for loop (or breaks out of the loop if you were on the last iteration). This prevents the append statement from being executed (which would either raise an error because the leaf variable did not get assigned, or erroneously append the last assigned value of leaf to the list again meaning one leaf would appear in the list multiple times).