[Closed] Accessing objects in a for-loop
Hi everyone,
I’m quite new to maxscript and would appreciate any help in the following.
I’m creating a script that uses the the ProCutter function. The function uses the intersection of randomly oriented boxes to create new objects. Thus the number of newly generated boxes varies. Sometimes it is more than ten. Othertimes it is less.
I would like my script to take each newly created box and reposition it at some interval along the x axis. I am trying to use a for-loop at the end of the script to cycle through the boxes in the scene. It starts at 3 since I don’t need to move the first box and the second box is deleted in the script.
I am stuck, however, because I don’t know how to integrate the for-loop index (‘boxcounter’) into the variable name when applying my ‘move’ function. In other scripting languages, I could use the character “&” and “” to concatenate names and variables. That doesn’t seem to work here. I’ve tried several combinations but have run out of ideas.
Also, I just realized that the numbers of the created boxes start with 0 for single digits (box01, box02,box03 etc) but when they get to double digits, they drop the zero (box10, box11, box12). So how can I accommodate this into the script using a loop index approach?
Any help is appreciated.
Thanks!
Carlo
OriginalBox = box length:10 width:10 height:10
move OriginalBox[0,0,-5]
AdditionalBox1= box()
random
s1= random 0.2 0.6
s2= random 0.2 0.6
s3= random 0.2 0.6
scale AdditionalBox1 [s1,s2,s3]
m1= random -3 3
m2= random -3 3
m3= random -3 3
move AdditionalBox1 [m1,m2,m3]
r1= random 0.0 180.0
r2= random 0.0 180.0
r3= random 0.0 180.0
rotate AdditionalBox1 (eulerAngles r1 r2 r3)
AdditionalBox2= box()
random
s1= random 0.2 0.6
s2= random 0.2 0.6
s3= random 0.2 0.6
scale AdditionalBox2 [s1,s2,s3]
m1= random -3 3
m2= random -3 3
m3= random -3 3
move AdditionalBox2 [m1,m2,m3]
r1= random 0.0 180.0
r2= random 0.0 180.0
r3= random 0.0 180.0
rotate AdditionalBox2 (eulerAngles r1 r2 r3)
AdditionalBox3= box()
random
s1= random 0.2 0.6
s2= random 0.2 0.6
s3= random 0.2 0.6
scale AdditionalBox3 [s1,s2,s3]
m1= random -3 3
m2= random -3 3
m3= random -3 3
move AdditionalBox3 [m1,m2,m3]
r1= random 0.0 180.0
r2= random 0.0 180.0
r3= random 0.0 180.0
rotate AdditionalBox3 (eulerAngles r1 r2 r3)
ProCutter.CreateCutter #(AdditionalBox1,AdditionalBox2,AdditionalBox3)3 True True False True True
ProCutter.AddStocks AdditionalBox1 #(OriginalBox) 1 1
delete $box02
counter = 1
For boxCounter = 3 to (objects.count+1) do
(
move $boxboxCounter [30counter,0,0]
counter = counter+1
print counter
)
The first two things that come to my mind are:
- Rename the boxes as you create them, or
- Add the boxes to an array as you create them, then select them from the array. For example, after you create the box, you could do: append selArray $, then in your for-loop you could do: select selArray[x], then move the object.
Hi Carlo,
Here are some bits of code to help you out. Clearly you’re familiar with other scripting concepts, so I’ll dive in.
There are a few different for loops in max, with various functionalities
(
numBoxes = 10 -- Integer, stores how many boxes the loop will create
myBoxArray = #() -- Empty array, able to store any type of info at any index
for i = 1 to numBoxes do (
b = box pos:[(random 1 10),0,0] -- creates a box with a random x position
append myBoxArray b -- stores the box object in an array "myBoxArray", for changing later
)
)
Now suppose you want to do something else to the boxes after some user input, you can use the
for b in myarray do
b.wirecolor = (color 255 0 0) -- changes all the boxes you created wirecolor to red
for loop to iterate through each box, alternatively you could iterate through the array you created above that stores the boxes via an indexed method like this
for i = 1 to myarray.count do
myarray[i].name = "BoxNumber"+(i as string) -- Renames all the boxes you created with the index
Hope that helped,
Colin
Hey guys, thanks for your replies!
Tanasoo: The problem I see with your aproach is that when I use the ProCutter function, the resulting boxes are created all at once. I don’t know if they is a way to isolate the boxes for renaming as they are being created. I assume this has to happen after the fact.
MoonDoggie: Thanks for the examples. I think the last section was exactly what I was looking for!
Carlo
As long as you don’t have any other objects named Box*, then you could select all of the box*s and add the whole selection to your array. I think its something like: append arrayName ($ as array)
And if you DO have other box*s in your scene, then before you make the operation, you could add those to another array, and then remove them from the final array.
Hey guys,
Two steps forward, one step back. Don’t you love scripting?
So I’ve figured out how to group the created objects and how to assign unique names using the for loop index as per your example above, although I’ve avoided using arrays (they give me nighmares). I’ve also nested this in a second loop, so the whole process will create several groups. These groups are assigned the name “Element” so I end up with “Element1”, “Element2”, “Element3” etc.
Now, I can move each group individually by using the following:
[color=lemonchiffon]move $Element1 [20,0,0]
In order to cycle through many different groups, I thought I could replace the numeral “1” in the object’s name with the index from a loop as follows…
For j= 1 to 2 do(
move $Element+(j as string) [20,0,0]
)
Instead I get the error message
[color=#ff0000]– Error occurred in j loop
– No ““move”” function for undefined
Why is it Undefined? Am I not referencing the index properly? Am I missing syntax?
Below is the revised code. And BTW, how do you place text into a scrollable window to make it neat and tidy?
TIA.
Carlo
[color=white]For i=1 to 2 do
(
OriginalBox = box length:10 width:10 height:10
move OriginalBox[0,0,-5]
AdditionalBox1= sphere radius:5 segs:60
random
s1= random 0.5 1.5
s2= random 0.5 1.5
s3= random 0.5 1.5
scale AdditionalBox1 [s1,s2,s3]
m1= random -3 3
m2= random -3 3
m3= random -3 3
move AdditionalBox1 [m1,m2,m3]
r1= random 0.0 180.0
r2= random 0.0 180.0
r3= random 0.0 180.0
rotate AdditionalBox1 (eulerAngles r1 r2 r3)
AdditionalBox2= sphere radius:5 segs:60
random
s1= random 0.5 1.5
s2= random 0.5 1.5
s3= random 0.5 1.5
scale AdditionalBox2 [s1,s2,s3]
m1= random -3 3
m2= random -3 3
m3= random -3 3
move AdditionalBox2 [m1,m2,m3]
r1= random 0.0 180.0
r2= random 0.0 180.0
r3= random 0.0 180.0
rotate AdditionalBox2 (eulerAngles r1 r2 r3)
AdditionalBox3= sphere radius:5 segs:60
random
s1= random 0.5 1.5
s2= random 0.5 1.5
s3= random 0.5 1.5
scale AdditionalBox3 [s1,s2,s3]
m1= random -3 3
m2= random -3 3
m3= random -3 3
move AdditionalBox3 [m1,m2,m3]
r1= random 0.0 180.0
r2= random 0.0 180.0
r3= random 0.0 180.0
rotate AdditionalBox3 (eulerAngles r1 r2 r3)
ProCutter.CreateCutter #(AdditionalBox1,AdditionalBox2,AdditionalBox3)3 True True False True True
ProCutter.AddStocks AdditionalBox1 #(OriginalBox) 1 1
delete $sphere01
delete $sphere02
For o in objects do
(
o.wirecolor = color 255 0 0
)
group $sphere*
$group*.name=“Element”+(i as string)
)
For j= 1 to 2 do
(
move $Element+(j as string) [20,0,0]
)
[/color][/color][/color]
execute ("move $Element" + (j as string) + " [20,0,0]")
It’s a very annoying element of maxScript, but the only way to access an object by a concatenated string is with the execute command. Watch out because all variables in execute are global, not local.
A couple of other things. Do your best to not have that much repeated code. I’d put all the “additional” box making into a function that looks like:
fn makeAdditionalBox = (
ab = sphere radius:5 segs:60
s1 = random 0.5 1.5
s2 = random 0.5 1.5
s3 = random 0.5 1.5
scale ab [s1,s2,s3]
m1 = random -3 3
m2 = random -3 3
m3 = random -3 3
move ab [m1,m2,m3]
r1 = random 0.0 180.0
r2 = random 0.0 180.0
r3 = random 0.0 180.0
rotate ab (eulerAngles r1 r2 r3)
return ab
)
Then you call this function 3 times with:
pcArr = #()
for n = 1 to 3 do (
append pcArr makeAdditionalBox()
)
This gives you an array with 3 boxes in it. Now you can send that array to procutter:
ProCutter.CreateCutter pcArr 3 True True False True True
ProCutter.AddStocks pcArr[1] #(OriginalBox) 1 1
Now this is problematic:
for o in objects do (
o.wirecolor = color 255 0 0
)
You’re setting the wirecolor of every object to red every time you step through this script. You only need to do this once.
Lastly, when you group your spheres, you can just move them right there. No need to worry about the names.
g = group $sphere*
g.name = "Element" + i as string
move g [20,0,0]
It would be helpful to see how you’re creating the spheres too as I bet you won’t have to group them by name (a bad idea because if you have any other spheres in your scene, your script breaks).
Hope some of this helps.
focomoso,
Thanks for your tips. I really like how elegant a custom function can be.
Your examples raised some questions for me.
If I try to run the function as follows…
fn makeAdditionalBox = (
ab = sphere radius:5 segs:60
s1 = random 0.5 1.5
s2 = random 0.5 1.5
s3 = random 0.5 1.5
scale ab [s1,s2,s3]
m1 = random -3 3
m2 = random -3 3
m3 = random -3 3
move ab [m1,m2,m3]
r1 = random 0.0 180.0
r2 = random 0.0 180.0
r3 = random 0.0 180.0
rotate ab (eulerAngles r1 r2 r3)
return ab
)
pcArr = #()
for n = 1 to 3 do
(
append pcArr makeAdditionalBox()
)
I get an error message that says
– Error occurred in n loop
– Frame:
– n: 1
– Argument count error: append wanted 2, got 3
OK
As far as I can tell, I’m only giving append two arguments… pcArr and makeAdditionalBox(). I’ve tried calling the function by taking “makeAdditionalBox()” out of the loop and it works fine, so it looks like I’m missusing the loop somehow.
I then tried to continue with your examples and added the ProCutter funtion as follows…
OriginalBox = box length:10 width:10 height:10
move OriginalBox[0,0,-5]
fn makeAdditionalBox = (
ab = sphere radius:5 segs:60
s1 = random 0.5 1.5
s2 = random 0.5 1.5
s3 = random 0.5 1.5
scale ab [s1,s2,s3]
m1 = random -3 3
m2 = random -3 3
m3 = random -3 3
move ab [m1,m2,m3]
r1 = random 0.0 180.0
r2 = random 0.0 180.0
r3 = random 0.0 180.0
rotate ab (eulerAngles r1 r2 r3)
return ab
)
pcArr = #()
for n = 1 to 3 do
(
append pcArr makeAdditionalBox()
)
ProCutter.CreateCutter pcArr 3 True True False True True
ProCutter.AddStocks pcArr[1] #(OriginalBox) 1 1
Max really dosen’t like this.:sad: I get a nasy looking error box ‘warning- the software has encountered a problem’ when I try to run it. The program usually crashes then.
Any suggestions?
Thanks!
Carlo