Distributing random objects to helpers.

So here’s  a quick problem from CGTalk which is a classic example of how just a simple bit of MaxScript knowledge can help:

Hey whats up guys,

Working on an interesting project where we’re modeling a parking lot environment, but the vehicles are aligned along a curve (not nice straight rows.)

So far we’re using the Spacing Tool to clone and align a car model along a path that follows the contour of the spaces.

But here’s the issue, ultimately we’d like to use a small array of cars (5 cars with 3 colors each) and distribute them “randomly” within the parking spaces.

So imagine the spacing tool solution, except instead of using just one object, its distributing random cars along the path.

Any know of a method, work-around, or perhaps another script that can make this happen?

My worst case solution is to just duplicate a cube (with the approximate scale of the cars) along the paths, and then just click and align the car models manually. However, with hundreds of cars, this could be quite tedious.

Any time and assistance is much appreciated,
Ryan

So lets break this down into the issues.

  • We can get the spacing and alignment using the ‘Spacing Tool’
  • Spacing tool only distributes one object

We could write some complicated tool which mimics the spacing tool but lets be efficient (lazy) and use the spacing tool to distribute some dummy objects.

Now we have a list of object helpers we can use to distribute a selection of cars too. In this example I’ve just made some boxes, but you can use any object, it’s important to note for this example it needs to be one whole object, and you’ll need to make sure the pivot is in a logical and consistant place on all the cars.

So once we’ve got a group of cars, we want to define that as a group, we then want to go through every Point helper, and for each Point helper we need to choose a random car, create an instance of that random car, then set it’s position and orientation (Transform, another tutorial…)  Lets look at the script… funny enough looks very similar to what I just wrote, not too far off english really.

thecars = selection as array

for o in $Point* do
(
    r = random 1 thecars.count

    thecar = instance thecars[r]
    thecar.transform = o.transform

)

Quick, simple and it works… not a complex script and might require some tidy up later and maunal tweaking but sometimes writing a maxscript isn’t about making a complete tool, it’s just about writing something to help you with your day and get a repetative task done quicker.  Lets break this down then…..

thecars = selection as array

We’re creating a new variable here which is an array (think list) of objects that we currently have selected. We can then refer to this list later on using the index system… thecars[1] will return the first item in the list. We can get the total number of items in this list by asking it’s count. thecars.count which will return 6 if you had 6 objects selected when you run the script.

for o in $Point* do
(
)

For loops are a way of asking the code to go through a sequence of task…. you can say

for i = 1 to 5 do print i

and you’ll get

1
2
3
4
5

..printed in your Maxscript listener.

T’ve tried to explain for o in blah loops before and it’s complicated to a non-codey person. It confused me for quite a while before I understood it. So here goes…

$Point* – This is a quick and dirty way of getting all the objects that are called $Point01, $Point02, into an array (think list). The reason we have to put a $ symbol before it is to tell max that we’re talking about a node… and by node we mean something in the max viewport we can see, not necessarily an object, but any class of thing in the viewport.

We have therefore a list we can process, we could say….

for i = 1 to $Point*.count do print $Point*[i] which will print the node entry into the maxscript listener, but it’s a bit messy, what is better is if we can just refer to each item by a temporary value.

for o in $Point* do print o

It’s saying for ‘every item x’  in the list do print x, we can call this ‘o whatever we like, it’s a variable we’re declaring just for this loop…. for example…

for cabbage in $Point* do print cabbage

Works exactly the same.

I real-life world example… imagine you have a desk full of objects, you need to clean all the items on your desk, they’re al numbered. Your boss comes over to give you your orders… he could say…

“You have 5 things to clean on your desk,
clean deskitem 1
clean deskitem 2
clean deskitem 3
clean deskitem 4”

Ok that might seem a slightly alien way of talking, but stay with me… or he could say.

“For every item on your desk,
clean item
clean item
clean item
clean item
clean item”

The difference might seem subtle but sometimes it can make the difference between writing loads of code and not a lot of code, similarly, sometimes when you need to know the index of the item you’re working on you need to use the for i = 1 to 10 version. These should become clearer with more tutorials.

Back to the script

r = random 1 thecars.count

This line defines a new variable I’m calling r, that we’ll use in a moment, we’re using the Random() function to get a number between 1 and the number of items in our thecars list.

thecar = instance thecars[r]

Now we’ve got a random number we can create a new variable which refers to the node that the instance function returns, Instance() does much as you expect, instances an object just like you do in max normally. It’s a function that needs an argument passed to it, in this case it wants to know what it needs to instance, so we pass it one item from our list.  thecars[r] r is defined as a random number between 1 and thecars.count, at this point r will be defined, it won’t be random again, but as we’re in a loop every time the loop runs r will change value. thecar now returns a node in the scene, so we can reference and control this new node.

thecar.transform = o.transform

We now need a new car to assume the position and orientation of the Point helper. Orientation.. direction…rotation… translation and transform is worth of a massive blog post so won’t got too heavily into this now. Transform is a vector direction, and contains the position and scale, so by assigning the transform we’re setting the position and orientation in one line.

Advertisements

About davewortley

Somewhere between an artist and a programmer, I like technical things, but being creative. I love problem solving and coming up with elaborate solutions. This blog is where I shall share ideas, tips, tutorials and anything that amuses me.
This entry was posted in MaxScript. Bookmark the permalink.

3 Responses to Distributing random objects to helpers.

  1. sharfy says:

    this is simple and very nice script. i am facing a similar problem except width of cars is not same so they will intersect with each other if using spacing tool with point helpers and using this script. is there a way which take into consideration width of different cars and place point helpers on spline accordingly and then place cars on point helper. thanks

    Like

  2. Cladi says:

    very usefull thank you for the little tutorial! hard to find though, you should put it on scriptspot

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s