Finally I managed to complete the second part of the ARewO tutorial. It can now distribute objects along a path and include armatures.

If you haven't watched the first part, I strongly recommend you to do so.


So here is the script:

  1. import bpy
  2. import math
  3.  
  4. loops = 30
  5. distanceX = 0
  6. distanceY = 0.4
  7. distanceZ = 0
  8. offset = 6
  9. offset_extra = 0
  10.  
  11. arm = bpy.context.active_object
  12. kinder = bpy.context.selected_objects
  13. placer = bpy.data.objects['Placer']
  14.  
  15. for i in range(loops):
  16.     print(str(i))
  17.     bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":True})
  18.     bpy.context.scene.frame_set(i)
  19.     bpy.ops.object.make_single_user(type = 'SELECTED_OBJECTS', object = False, obdata = False, material = False, texture = False, animation = True)
  20.     bpy.ops.object.select_all(action = 'DESELECT')
  21.     for j in range(3):
  22.         arm.location[j] = placer.matrix_world[j][3]
  23.     animData = arm.animation_data
  24.     action = animData.action
  25.     fcurves = action.fcurves
  26.     for k in range(len(kinder)):
  27.         kinder[k].select = True
  28.     for curve in fcurves:     
  29.         keyframePoints = curve.keyframe_points
  30.         for keyframe in keyframePoints:
  31.             keyframe.co[0] += offset #verschieben
  32.             keyframe.handle_left[0] += offset
  33.             keyframe.handle_right[0] += offset
  34. print("done")

And here the explanation:

  1. arm = bpy.context.active_object
  2. kinder = bpy.context.selected_objects
  3. placer = bpy.data.objects['Placer']
  4.  
These are the important variables. Arm is the armature you want to include, notice that it has to be the active object in your bunch. Kinder are all selected objects and placer is an object that flies anywhere it wants, but it needs to exist with the name "Placer".

  1. for i in range(loops):
  2.     print(str(i))
  3.     bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":True})
  4.     bpy.context.scene.frame_set(i)
This calls a for loop that will execute as many times as you specified with the "loops" variable.
We want a linked copy of our object, in case we want to change something later and also linked objects render faster.
  1.     bpy.ops.object.make_single_user(type = 'SELECTED_OBJECTS', object = False, obdata = False, material = False, texture = False, animation = True)
But we cannot have the animation linked, because we want to offset it in time, and if we wouldn't make it a single user, our offset would go into all our armatures, thus sychronizing them.

  1.     for j in range(3):
  2.         arm.location[j] = placer.matrix_world[j][3]]
Now this is a tricky one, try parenting an object to an empty, then remember it's location displayed in the "n" menu. then move only the empty, you'll see, even though your object has moved in space, it's location is the same. Same for pathes, so we need to find the absolute location of our placer object, in order to be able to make our armature copy it's position. If you type in C.active_object.matrix_world in the console, you'll see that it's a 2 dimensional array, thus requiring 2 indices, I picked out the right ones for you, they result in the world x, y and z location.

  1.     animData = arm.animation_data
  2.     action = animData.action
  3.     fcurves = action.fcurves
Those are just variables that make it a little easier for someone else to follow the code.
  1.     for k in range(len(kinder)):
  2.         kinder[k].select = True
Kinder is german for children. I don't like to use reserved terms for variables like "children". But the code is supposed to select all children, so I chose the German word for it, feel free to change it.
Oh, right, the actual explanation: it will reselect all objects that were selected when we pressed "run script".

  1.     for curve in fcurves:     
  2.         keyframePoints = curve.keyframe_points
  3.         for keyframe in keyframePoints:
  4.             keyframe.co[0] += offset #verschieben
  5.             keyframe.handle_left[0] += offset
  6.             keyframe.handle_right[0] += offset
            
This part looks through all f-curves and then trough all keyframes in each f-curve. It then moves them in x (time) by the offset we specified.

  1. print("done")
This indicates that the script worked with surgical precision.

Download the finished .blend here!