Many of the values you work with in MAXScript are sequenced collections, notably arrays, wild-card pathname selections, and the built-in object sets.
In the manner of most operating system shell command languages, MAXScript will automatically apply appropriate operations to each of the members in these target collections. This is called a mapped operation.
EXAMPLES: | |
---|---|
hide $lights/key* |
Hide all the 'key' lights in the scene |
$box*.position = [0,0,0] |
Re-center all boxes |
delete dead_objects |
Delete all the objects in the array 'dead_objects' |
obj.pos.keys.intangent=#fast |
Set in tangent to fast for all obj's position keys |
lights.value *= 0.8 |
Turn down all the lights 20% |
MAXScript determines whether to perform a mapped operation by looking at the first argument to a function or the target in a property assignment to see if it is a sequenced collection. In the case of a function call, it also looks to see if the function is of the appropriate kind, evaluates all the other argument expressions only once.
MAXScript then calls the function on each of the members of the first argument collection passing along the other evaluated arguments. In the case of a property assignment, it evaluates the right-hand-expression only once and assigns the value to the named property of each of the elements in the target value collection.
This means that every element in the collection must be a valid target for the function or have the named property in question. If MAXScript comes across an inappropriate target it will report an error and stop the automatic operation.
Except for certain common properties, MAXScript currently only allows automatic collection mapping of property assignment one level deep.
EXAMPLE
the following will perform collection mapping across the objects ObjectSet:
objects.pos = [0,0,0] --move all objects to world center
If the last level specified is one of the following component names, the automatic collection mapping is performed on the preceding property:
.angle .b .blue .axis .controller .g .green .isAnimated .keys .r .red .track .x .x_rotation .y .y_rotation .z .z_rotation
EXAMPLE
the following will perform collection mapping across the objects ObjectSet:
objects.pos.z = 0.0 --move all objects to world XY plane
This behavior of calling a function on all the elements of a collection is known as mapping in computer science. In the description of each collection type, you will find those kinds of sequenced collections that can be mapped over identified as mappable.
In the descriptions of the various functions and operators throughout this document, those that act on each element in a collection are labeled mapped.
In general, the functions that are mapped are those that have some side-effect on the value they take, such as moves, and deletes and hides.
Others, like the test function isHidden()
, are not
mapped because it would be pointless since the result would not be able to represent the state of multiple objects.
All mapped functions defined by MAXScript, such as copy()
, delete()
, or move()
, take an optional last argument, #noMap
. This causes the functions not to be mapped when called on collection arguments such as arrays. When used with copy()
on arrays in particular, this will return a top-level copy of the array itself and not perform an individual copy()
on each element of the array.
You can make your own mapped scripted functions by preceding the function definition with the reserved word mapped
,
EXAMPLE
the following will perform collection mapping across the objects ObjectSet:
mapped function rand_color x = (x.wireColor = random black white)
This causes such functions to be automatically called repeatedly on the elements of a collection if a collection is given as the first argument to the function. The #noMap
argument is not applicable to user-written functions!
As described in For Loop, a for
loop can be set up to iterate through a collection set assigning successive elements in the collection to the loop value each time through the loop. For
loops can also be set up to return an array collection set as its result.
EXAMPLES:
-- sequence an array:
for item in table1 do x = x + item.height
-- you can sequence pathnames:
bigones = for obj in $box* where obj.height > 100 collect obj
-- collect the big boxes into an array
When iterating through a collection set using a for
loop, or when passing a collection to a mapped function, care must be taken not to reorder or remove elements in the collection set within the for
loop or function.
Take for an example a script that is supposed to convert all of the selected splines into NURBS curves.
TWO SCRIPTS THAT DO NOT EXECUTE PROPERLY ARE:
for obj in selection do ( convertToNURBSCurve obj)
convertToNURBSCurve selection
The reason neither of these lines execute properly is that the convertToNURBSCurve()
function clears the current selection. So only the first spline is passed to convertToNURBSCurve()
and converted. Since convertToNURBSCurve()
is a built-in function, there is no way to modify this behavior.
To get around this problem, you need to first "snapshot" the selection collection set as an array using the as
operator, or use the getCurrentSelection()
function, which returns the current selection set as an array.
TWO SCRIPTS THAT EXECUTE PROPERLY ARE:
for obj in (selection as array) do ( convertToNURBSCurve obj)
convertToNURBSCurve (getCurrentSelection())