[Closed] Nested "for" Loops & Using Variables for Parameters
I’m writing some very basic functions in effort to better understand how to author MaxScript. I’m doing something wrong with my nested “for” loops and/or parameter variables. Any help (as always) is greatly appreciated.
I create a box via script:
fn makeMyBox = (
if $myBox == undefined then (
myBox = box name:"myBox"
format "Created myBox.
"
)
else (
format "myBox has already been created.
"
)
)
makeMyBox()
Seems to work just fine. Now I want to change some or all of the box parameters:
fn updateMyBox l: w: h: = (
argArray = #(l,w,h)
paramArray = #("length","width","height")
for i in argArray do (
if i == unsupplied then (
format "New value for % unsupplied.
" i
)
else (
for i in argArray do (
for v in paramArray do (
myBox.v = i
)
)
)
)
)
updateMyBox l:10 w:20 h:30
I get the following error: “– Unknown property: “V” in $Box:myBox @ [0.000000,0.000000,0.000000]”
Any takers? Thank you in advance.
- Dave
If you say:
Box.v
It doesn’t know you want to use a variable.
Let’s say I have a variable: var = “hello”
and I could have a box.var
but it’ll look for box.VAR where the property is named “var” and maxscript assumes you literally mean box.var it’s not going to substitute a variable wherever you type it since the variable could be (if it’s a struct) structvar.integer it knows that you have a property of structvar called integer not that you want an integer.
You need to use the setproperty function:
setproperty box v i
Theoretically you could also say:
execute ("box."+v+" = "+i)
But that’s really sloppy and should be avoided unless absolutely necessary. (Very rare).
And… that all being said your script doesn’t do what it’s supposed to even with that bug fixed.
fn updateMyBox l: w: h: =
(
argArray = #(l,w,h)
paramArray = #("length","width","height")
for i = 1 to paramarray.count do
(
if paramArray[i] == unsupplied then
(
format "New value for % unsupplied.
" i
)
else
(
setproperty $mybox paramArray[i] argArray[i]
)
)
)
updateMyBox l:10 w:20 h:30
It was going to do a lot of wonkiness. Too many for loops and your width would have been assigned to the height etc etc.
EDIT: Whoops I typed “updateproperty” instead of “setproperty”. That didn’t work at all.
Fantastic! Thank you very much Gavin. I think I am now heading in the right direction. As you have the script rewritten, it seems to error out if one or more of the arguments is not specified. For example, running:
updateMyBox l:10 w:20
returns: “– Unable to convert: unsupplied to type: Float”
But if we swap argArray for paramArray and leave an argument unsupplied, there is no error. For example:
fn updateMyBox l: w: h: =
(
argArray = #(l,w,h)
paramArray = #("length","width","height")
for i = 1 to argArray.count do
(
if argArray[i] == unsupplied then
(
format "New value for % unsupplied.
" i
)
else
(
setProperty mybox paramArray[i] argArray[i]
)
)
)
updateMyBox l:10 w:20
returns: “New value for 3 unsupplied.”
Almost there. So now how can we supply the name of the argument that is unsupplied, instead of just its place in the array?
And again, thank you very much.
- Dave
Hey Paul. Thank you for your input, I really appreciate it.
Please know that i don’t mean to question your authority in the realm of 3DS Max. You’ve helped me more than I can convey. I just want to make sure that I am on the same page you are. The MaxScript reference defines “unsupplied” as:
“The initial value of all function keyword arguments. Keyword arguments are optional arguments to functions. If a keyword argument is not supplied by the function caller and the function definition does not specify a default value, MAXScript initializes the keyword argument to unsupplied. You can test for this value to see whether a caller has supplied a particular keyword.”
As I’ve been going through script authoring training materials, I got the impression “unsupplied” should be used in the case of function arguments, and “undefined” everywhere else. Should I be using “undefined” because of how the function is using the arguments? Does it not matter which is used when? What are your thoughts?
As always, thank you for your time.
- Dave
Change (i is the place in the loop):
format "New value for % unsupplied.
" i
To (argArray is the actual value in the array):
format "New value for % unsupplied.
" argArray[i]
Paul, heyitsdave is right in that unsupplied can be used, because he hasn’t defined a default value.
Keyword parameters have a ‘:’ (colon) after the name and an optional default value. The caller of the function can optionally supply keyword arguments in any order. Those not supplied will be set to the default value given, or the special value unsupplied if a default value is not given.
Hope that helps,
-Eric
There is a small tweak which I usually use just for clarity:
Normal:
fn testfunction A: B: C: = (if A==undefined then print "A is undefined" else print "A is not undefined")
Tweak:
fn testfunction A:undefined B:undefined C:undefined = (if A==undefined then print "A is undefined" else print "A is not undefined")
Personally I don’t like “unspecified” because it’s a different word to have to remember. And it results in me forgetting to code differently (as illustrated above).
Hi Eric,
Thank you for your reply; you’ve helped me to understand a few things better. With the combined help from everyone in this thread, I’ve come up with:
fn updateMyBox l: w: h: =
(
argArray = #(l,w,h)
paramArray = #("length","width","height")
for i = 1 to argArray.count do
(
if argArray[i] == unsupplied then
(
for c = 1 to argArray.count do
(
case of
(
(i == c) : format "-- % unchanged - new value unsupplied.
" paramArray[i]
)
)
)
else
(
setProperty mybox paramArray[i] argArray[i]
format "++ % set to %.
" paramArray[i] argArray[i]
)
)
)
calling the function as: (all arguments supplied)
updateMyBox l:10 w:20 h:30
returns:
++ length set to 10.
++ width set to 20.
++ height set to 30.
calling the function as: (height argument unsupplied)
updateMyBox l:10 w:20
returns:
++ length set to 10.
++ width set to 20.
– height unchanged – new value unsupplied.
It now seems to be working now as I originally intended; and to my untrained eyes seems reasonably efficient. Does anyone agree/disagree or have an even better approach? I know this is a simple task… I’m just trying to better understand MaxScript syntax as well as functions and variables in general.
Thanks again to everyone. Your contributions to these forums are invaluable.
Cheers,
Dave
Not sure why you added a for loop to loop until it == i instead of just using i it’s a useless loop.
I’m assuming you’re just practicing a bunch of different stuff so in that light another way to do the case is to say something like this:
for i = 1 to 3 where i == 2 do print i
I find it more readable and less confusing.