How to move objects inside a collection to random locations

I’m new to Blender ,

I’ve created a Donut by following blender Guru’s youtube tutorial , I want to put that Donut in random locations

My Donut is a collection of objects(Donut,Icing)

I’ve used this code to move the collection , but the problem is , the donut and the icing are moving separately in random locations

My code is

import bpy
from random import randint


col = bpy.data.collections.get("donut")
if col:
   for ob in col.objects:
       ob.select_set(True)
       frame_number = 0
       for i in range(0,100):
           x = randint(-20,20)
           y = randint(-20,20)
           z = randint(-20,20)
           bpy.context.scene.frame_set(frame_number)
           ob.location = (x,y,z)
           ob.keyframe_insert(data_path = "location",index = -1)
           frame_number += 5

Someone please give pointers or suggestions on how to do it please

because x,y,z are randints and are different for both icing and donut? https://docs.python.org/3/library/random.html#random.randint

you need to set a seed for one loop. https://docs.python.org/3/library/random.html#random.seed
tip: that seed can be random, as long as it remains the same for that loop. reset it in next iteration.

1 Like

Thank you bro ,seems like that’s a good idea , will try it :slight_smile:

You could also simply create a collection instance of the Donut collection and rework your script to animate that instance. Not only would this be simpler to code, it also gave you the freedom to continue working on the Donut model without messing with the animation at all.

1 Like

Thank you for the reply bro , seems like a very good alternative idea , will try this one too , and I think this one will be the best as it will be simpler to code and the freedom to continue working on the model without disturbing the animation :slight_smile:

@ankitm I dont know what mistake I am doing , tried with seed in random , its not working :frowning:
@RainerTrummer I dont know how to animate a collection in Python , is there any documentation or reference which I can refer to , if there is , please share it to me .

I think the above code is not selecting the collection as a single element , its selecting the donut as 1st element of the loop and icing as 2nd element of the loop , is there any way i can select both of them together .

I am able to move a single object easily in python but I feel difficult to move a collection

col = bpy.data.collections.get("donut")
if col:
   a=0
   b=0
   for ob in col.objects:
       ob.select_set(True)
       if(a%2==0):
          b=randint(0,1000)
       a+=1
       frame_number = 0
       for i in range(0,100):
           seed(b)
           x = randint(-20,20)
           seed(b)
           y = randint(-20,20)
           seed(b)
           z = randint(-20,20)
           bpy.context.scene.frame_set(frame_number)
           ob.location = (x,y,z)
           ob.keyframe_insert(data_path = "location",index = -1)
           frame_number += 5

try this, I haven’t tested it, could you share a blend file pls ?and the tutorial link too?

1 Like

You’re not supposed to animate the Collection, you should animate the Collection Instance. See this GIF on how to create one (also works with Shift+A -> Collection Instance -> your_collection):

Once you have that instance object (which is nothing else than an empty that instantiates a collection), you can animate this new object, but still work on the base collection at the same time:

1 Like

If however you just wish to solve the original problem, simply turn the logic around: In the for loop for the frame range, first generate the random location, and then iterate over all objects to set that same location on all objects. Make sure to have applied all transforms on the source objects before you run this:

import bpy
from random import randint


col = bpy.data.collections.get("donut")

if col:
	frame_number = 0
	for i in range(0,100):
		x = randint(-20,20)
		y = randint(-20,20)
		z = randint(-20,20)
		bpy.context.scene.frame_set(frame_number)

		for ob in col.objects:
			ob.select_set(True)
			ob.location = (x,y,z)
			ob.keyframe_insert(data_path = "location",index = -1)
			frame_number += 5
2 Likes

much more elegant… I put a%2 assuming there are two objects, and in consecutive order. could be wrong.

@ankitm , @RainerTrummer thank you guys for your time and help , but I am not getting the expected output , I think I am doing something wrong , and sorry I did not explain my problem fully , now I will provide the full details .

I followed this tutorial : https://www.youtube.com/playlist?list=PLxLGgWrla12dEW5mjO09kR2_TzPqDTXdw

So I finished creating donut (level 2 - video 5 ) from the above playlist

I have uploaded my blender file here - https://send.firefox.com/download/e8f2bad79c76ade3/#Jo5bc9piyesej87Hlfuynw

I am able to successfully move the object if it is a single object. Example - I created a cylinder and I moved it easily in python(I am uploading this gif in my next post as it is not allowing me to post 2 images in one post since I am a new user )


In this image , the first half is the donut and icing getting separated after running the codes , 2nd half is the original donut

So , I want the donut to move together with the icing as I did with the cylinder , the problem is the donut and icing are moving separately as shown in the image

I am able to successfully move the object if it is a single object. Example - I created a cylinder and I moved it easily in python


But if it is a collection , its moving separately

I achieved moving the cylinder using the below code and as it is a single object , it was easy for me to do it

import bpy
from random import randrange,randint
import random

spawn_range = [(-2, 3),(-2, 4),(0,1)]


ob = bpy.data.objects["Cylinder"]
frame_number = 0

for i in range(0,50):
    x = random.randrange(spawn_range[0][0], spawn_range[0][1])
    y = random.randrange(spawn_range[1][0], spawn_range[1][1])
    print(x)
    z = (-0.2)
    bpy.context.scene.frame_set(frame_number)
    ob.location = (x,y,z)
    ob.keyframe_insert(data_path="location",index=-1)
    frame_number += 2

The end goal is I want the donut to be placed in various places in a plane with different lightings , camera angles and I want to save those frames as images separately but I am not able to place the donut(donut and icing) together in various positions as they are moving separately

As you can see in your own screenshot, the icing is parented to the donut. Be aware that keyframes are not set in relation to world coordinates, they operate on local ones. If an object is parented to another, the child object’s location is now in relation to the location of the parent. When you now set the same keyframe on both, the icing will be offset by a factor of two:

As a conclusion, if you have a parent-child-relationship, you must not keyframe the child. Updated code here goes in this direction (works on your example at least):

import bpy
from random import randint


col = bpy.data.collections.get("donut")

if col:
	frame_number = 0
	for i in range(0,100):
		x = randint(-20,20)
		y = randint(-20,20)
		z = randint(-20,20)
		bpy.context.scene.frame_set(frame_number)

		for ob in col.objects:
			if not ob.parent:
				ob.select_set(True)
				ob.location = (x,y,z)
				ob.keyframe_insert(data_path = "location",index = -1)
				frame_number += 5

As a side note, since you anyways figured how to animate a single object, why not animate the Collection Instance as initially suggested?

1 Like

Thanks a lot bro ,and once again sorry for not posting the full documents, and I’m sorry I dint know parent-child relationship affects in keyframes, this code is working as expected

As a side note, since you anyways figured how to animate a single object, why not animate the Collection Instance as initially suggested?

I searched on how to animate collection using bpy but ended up not getting anything related to it, would be very happy if u give any link or documentation reference on how to animate collection

I already gave a full answer on that topic above, please check again.

1 Like

Sorry and thank you , just checked it fully , will try that too :slight_smile:

Just tried , animating instance looks easy and working as expected , thank you :slight_smile: