In general, the selection contains the objects in the order in which they have been selected. For example, if you have the 5 boxes and none is selected and you hold Ctrl and start clicking them in a specific order, says 3,4,1,5,2, the array will be sorted in that order.
When using the window/crossing methods, it most probably depends on the internal order in which MAX figures out what is in the selection. I haven’t seen that code, so I cannot explain why the results are what they are, but there isn’t much you can do about that part.
What you can do though it reorder the array after the selection has been done, depending on what order you expect to get. You could reorder the objects into their order of creation, you could sort them alphabetically by name, or you could sort them by their X coordinate in screen space to get them left-to-right regardless of where your viewpoint is.
One easy way to reorder them in the order of creation would be to run through the objects list of the scene and collect them again. For example,
theSel = selection as array --this is the original selection array
theSel = for o in objects where findItem theSel o > 0 collect o --this is in creation order
Note that parenting (linking/unlinking) objects changes their order in the objects list. Unlinking a parented object always drops it at the end of the list.
You can reorder the objects alphabetically by name using the sort() or qsort() functions. You cannot apply this to the objects themselves, but you can sort the names. In the case of sort(), you can collect the names of the objects, sort them, then convert the names back to scene nodes. For example
theSel = selection as array
theNames = for o in theSel collect o.name
sort theNames
theSel = for o in theNames collect getNodeByName o
The trouble with this approach is that if you have two objects with the same name, the first one found in the objects list will be resolved by getNodeByName, which might give you the wrong one… But you shouldn’t have duplicated names in your scene anyway.
For using qsort(), you can perform an indexed sort as described in the Help. Collect an array of indices. Then sort it by sending the names of the objects to a sorting function, and at the end recollect the selection array in the order of the sorted index array. This method does not use getNodeByName(), so it won’t be affected by eventual duplicated names. But it is the most complex to understand.
For example,
theSel = selection as array --original selection array
theIndices = for i = 1 to theSel.count collect i --index list from 1 to 5
--comparison function - gets two indices to sort and the array of objects
fn compareFN v1 v2 valArray: =
( --it will swap the order if the first object has a greater name than the second
if valArray[v1].name > valArray[v2].name then 1 else -1
)
qsort theIndices compareFN valArray:theSel --sort the indices using the fn and the array
theSel = for i in theIndices collect theSel[i] --recollect the objects in the order of sorted indices
Similarly, instead of qsorting using the names, you can qsort by the positions of the objects in any coordinate system. In your case, you would have to convert the position of the object into view space, compare the X coordinate and sort by that.
For example,
theSel = selection as array
theIndices = for i = 1 to theSel.count collect i
fn compareFN v1 v2 valArray: =
(
local theTM = viewport.getTM()
local val1 = valArray[v1].pos * theTM
local val2 = valArray[v2].pos * theTM
if val1.x > val2.x then 1 else -1
)
qsort theIndices compareFN valArray:theSel
theSel = for i in theIndices collect theSel[i]
If you rotate your view at 180 degrees and look from behind the row of boxes, they will be sorted 5,4,3,2,1. If you are looking from the front, you will get 1,2,3,4,5.
Hope this helps.