I am trying to create an array of cubes with python.
array of cubes

So far, I have:

class RunSimulation(bpy.types.Operator):
"""Run CrowdMaster simulation"""
bl_idname = "scene.cm_run_simulation"
bl_label = "Run Simulation"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
    scene = context.scene
    groupObjs = bpy.data.groups[scene.agentGroup].objects
    halfAgents = scene.agentNumber // 2

    for object in groupObjs:
        if scene.groundObject == object.name:
            self.report({'ERROR'}, "The ground object must not be in the same group as the agent!")

    bpy.context.scene.objects.active.select = False

    if scene.positionType == "formation":
        if scene.formationPositionType == "array":
            for a in range(halfAgents):
                obj1 = bpy.data.objects[groupObjs[1].name]
                ground =  bpy.data.objects[scene.groundObject]
                offset_x = (obj1.dimensions.x + scene.formationArrayX)
                obj1.select = True
                obj1 = obj1.copy()
                if scene.positionMode == "vector":
                    location = Vector((scene.positionVector[0], scene.positionVector[1], ground.location.z))
                elif scene.positionMode == "object":
                    objStart = bpy.data.objects[scene.positionObject]
                    location = Vector((objStart.location.x, objStart.location.y, ground.location.z))
                obj1.location = location
                location.x -= offset_x

    return {'FINISHED'}

But this gives me
python script result

The offset value is formationArrayX

How can I add that offset in between each item? Right now, it just adds all the cubes in the same place. All of my code in multiple files is at https://github.com/johnroper100/CrowdMaster.

  • 1
    $\begingroup$ The script isn't usable on its own. Could you make a small self contained example? $\endgroup$ – ideasman42 Jul 16 '16 at 19:08
  • $\begingroup$ Done! I updated the code to work with regular objects. The arrayed object is called "Cube" the floor is called "Plane" and the location empty is called "Empty" $\endgroup$ – John Roper Jul 16 '16 at 19:27
  • $\begingroup$ Could I suggest you refrain from this type of question editing. It makes some answers that were right at the time of your initial question code now misleading... have a look at my last comment on my answer. You have taken code from the answer, posted a wrongly edited (nuffs up the logic) version as your question, commented on answer that it doesn't work. The question script again isn't usable on its own (like in @ideasman42 comment) with gear like scene.formationPositionType $\endgroup$ – batFINGER Jul 19 '16 at 19:27

Currently your duplicating an object and moving it by -(2a + 1.5) units on the x axis. This doesn't give you a offset between the objects as objects are still exactly 2 units away of each other (because a changes by 1).

You should multiply formationArrayX with a, instead of adding it. To get something similar to the screenshot you posted, increase formationArrayX to something like 3. You also don't need offset2 then.

Also note, that your current code duplicates all objects you added before in each step. Only the last one created is offset, all others stay at the initial position. This is because the duplicate operator duplicates all selected objects and you don't un-select objects after translating

EDIT: This answer was only valid for an earlier version of the opening question. Code has been changed since then.

import bpy
from mathutils import Vector
scene = bpy.context.scene

agents = 24
half_agents = agents // 2
offset = 1.5

empty = bpy.data.objects.get("Empty")
plane = bpy.data.objects.get("Plane")
cube = bpy.data.objects.get("Cube")
# put offset between each cube
offset_x = (cube.dimensions.x + offset)
# make each cube offset * dimensions apart
#offset_x = offset * cube.dimensions.x

location = Vector((empty.location.x,

for a in range(half_agents):

    cube = cube.copy()    
    cube.location = location
    location.x -= offset_x
  • $\begingroup$ Not working for me. My code is github.com/johnroper100/CrowdMaster or specifically github.com/johnroper100/CrowdMaster/commit/… $\endgroup$ – John Roper Jul 19 '16 at 0:17
  • $\begingroup$ Does the code posted in q work for you? In that it makes 12 cubes in an array, spaced from empty.xy plane.z 1.5 bu apart? In your code you have changed how location is being set, I am decrementing it in the loop, whereas you are setting it to start in each loop. Set the initial location outside the loop. $\endgroup$ – batFINGER Jul 19 '16 at 11:15

The default cube has vertices that are 1.0 units from the object origin, that makes a total of 2.0 units from side to side, so you need to have the location of each cube more than 2.0 units apart to get a gap in between each cube.

You also want to add 1.0 to the planes z location to have the new cubes sit on the plane.

import bpy

spacing = 2.5

start = bpy.data.objects['Empty'].location
loc_z = bpy.data.objects['Plane'].location.z + 1.0

for x in range(7):
    newloc = (start.x-(x*spacing), start.y, loc_z)
    bpy.ops.mesh.primitive_cube_add (location=newloc)

For a more portable solution you may want to calculate the offsets from the objects dimensions property (assuming the object origin is in the centre).

spacing_x = src_obj.dimensions.x + gap
loc_z = floor.location.z + (src_obj.dimensions.z / 2)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.