0
$\begingroup$

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
                scene.objects.link(obj1)
                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.

$\endgroup$
3
  • 1
    $\begingroup$ The script isn't usable on its own. Could you make a small self contained example? $\endgroup$
    – ideasman42
    Jul 16, 2016 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, 2016 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, 2016 at 19:27

3 Answers 3

2
$\begingroup$

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.

$\endgroup$
1
$\begingroup$
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,
                   empty.location.y,
                   plane.location.z))

for a in range(half_agents):

    cube = cube.copy()    
    cube.location = location
    scene.objects.link(cube)
    location.x -= offset_x
$\endgroup$
2
  • $\begingroup$ Not working for me. My code is github.com/johnroper100/CrowdMaster or specifically github.com/johnroper100/CrowdMaster/commit/… $\endgroup$
    – John Roper
    Jul 19, 2016 at 0:17
  • 1
    $\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, 2016 at 11:15
1
$\begingroup$

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)
$\endgroup$
1
  • $\begingroup$ lol, came across this searching for something else. God knows why the DV. Such a joy to answer some users questions. $\endgroup$
    – batFINGER
    Jul 22, 2020 at 13:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .