[Closed] Newbie Questions – Where do I look?
Hello,
I’m a total newbie at both programming as a concept and MaxScript in particular. As many have suggested, I took a look at MaxScripting to improve my modeling pipeline, and I’m fascinated by the possibilities, but I’m stymied by my own limitations.
I looked around and found that the principal source for learning MaxScript is the MAXScript Reference manual that comes with Max. I’ve been reading through both the introductory sections as well as the little “HowTo” tutorials.
I’ve done a good half dozen of them, but I have started trying to make a tool that I actually might use. The locking mechanism from the first tutorial is interesting, but not particularly useful. I want to create a tool that lets me lock each axis individually for each transform type.
Not terribly complex, but I can’t figure out how to do it.
I’ve decided to use checkboxes for the interface, and I’ve even figured out that getTransformLockFlags requires a node designation to actually work, and that ‘selection’ is not a valid node designation (this took me quite some time, as I mentioned, I’m a hopeless newbie).
I’m stuck on two parts. I need some way of running a function when the selection changes. I want the checkboxes to update depending on what is your current selection is. I’m thinking that when you change your selection the function will grab the transformlockflags for the new node, and then run through a loop that will update the “checked” category of the checkboxes.
I’m also stuck on how to get the node designation of the current selection. The only way of getting a node designation I can find is “GetNodeByName” which is useless in this situation as I don’t want to have the user type in the name of the selection as that is both time consuming and ridiculous.
Could someone point me in the right direction?
Also: I’m interested in the “isEnabled” and “isChecked” body event handlers. They’re cool, but they also seem to work only on a script as a whole. Is there some way of having something similar effect multiple buttons in a single rollout?
I’m thinking that I would have to script the function of each button separately, save them as separate max scripts, and then… I don’t know. I don’t know how to add separate Max Scripts into a rollout.
Again, any help would be greatly appreciated.
As everybody said, you are generally doing the right thing.
Of course, from your perspective, it is difficult to tell which parts appear to be hard and which parts are REALLY too advanced.
I’m stuck on two parts. I need some way of running a function when the selection changes. I want the checkboxes to update depending on what is your current selection is. I’m thinking that when you change your selection the function will grab the transformlockflags for the new node, and then run through a loop that will update the “checked” category of the checkboxes.
‘Selection’ is an internal collection of objects that contains the currently selected objects. It is dynamically updated as selections change. You can snapshot the current selection so it does not update dynamically as the actual selection changes in the viewports by converting it to array and storing in a variable.
For example,
theSel = selection as array –returns an array of all selected scene objects
You can now use a for loop to “visit” each one and perform operations on them, EVEN if the operation would alter the scene selection in some way – the array will keep all the object references, unless you delete objects from the scene in which case there might be complications.
It is NOT a good idea to use $ because it morphs between a single node and a collection of nodes depending on how many are selected and can cause problems in your code if you haven’t ensured beforehand what $ really means at the current moment.
I’m also stuck on how to get the node designation of the current selection. The only way of getting a node designation I can find is “GetNodeByName” which is useless in this situation as I don’t want to have the user type in the name of the selection as that is both time consuming and ridiculous.
Could someone point me in the right direction?
Once you have an array of nodes, you can just say
for o in theSel do … – o will be assigned one object at a time each time the loop repeats.
Also: I’m interested in the “isEnabled” and “isChecked” body event handlers. They’re cool, but they also seem to work only on a script as a whole. Is there some way of having something similar effect multiple buttons in a single rollout?
I’m thinking that I would have to script the function of each button separately, save them as separate max scripts, and then… I don’t know. I don’t know how to add separate Max Scripts into a rollout.
Again, any help would be greatly appreciated.
As mentioned already, to get your script to update when the scene selection changed, you would need callbacks. These ARE advanced matter and I would suggest writing a simpler version of the script first where you have a button for getting the current states of salected objects – when you press it, the code will be executed. Later, when you get that part working, you could add a callback and make it run that same code automagically.
Striding in smaller steps is usually helpful, otherwise you might get overwhelmed by the advanced stuff and miss the simpler things…
Keep on asking questions, the best way to learn MAXScript is by trying things out. To echo the other posters, I have been writing MAXScript for 10+ years and actually wrote all the HowTo tutorials in the Help, but I STILL discover new things every day. (I hope this does not sound scary ;))
Hi there,
I’m just on my way out, but I wanted to respond to what I knew I could help with quickly from your question.
As far as getting the selection, you can assign your selection to a variable as such…
selection = $
In MaxScript the symbol $ represents whatever is currently selected.
I hope that helps atleast part of your problem.
TC:
PS I’m not sure what you mean by not being able to use getTransformLockFlags on a selection node. The following example code should demonstrate how get[font=Courier New]TransformLockFlags [font=Verdana][/font]will work on a selection.[/font]
testNode = $ -- gets current selection
setTransformLockFlags testNode #all -- sets all transform locks on
getTransformLockFlags(testNode) --returns an array of all locked axis (in this case all)
Hi Context! I’m going to start out by suppling a rather abstract answer to your questions, bascially because you’ve already started out doing all the right things…reading the docs and trial and error.
The first place you want to look for this is under the callbacks section of the documents. It basically allows you to attach a listener to max and be update when certain actions take place, like the selection changes…I’ll give you a hint, you will want “selectionSetChanged”
“selection” is an objectset, which you can access as if it were an array. Something like the following will loop through the selection and get each object in turn that is selected.
for obj in selection do (
-- the variable "obj" is the next node in selection, you would act upon this...
format "%
" obj.name
-- Put your code here
)
You could also use "[b]$[/b]" to get the currently selected object, but this will only return a single object, not the list...
That’s what these fantastic people do best
Short answer, no…long answer, kind-a. In cases like this, I tend to write a function that does the work I need it to and call that function from within each of the individual event handlers, passing in the required information via parameters. It’s still kinda messy, but it does the job.
Hay, we are thinking big! I love it! You use either "[b]include[/b]" or "[b]filein[/b]" to include the contents of other scripts into you own.
Each one works differently, so you will want to read the docs and decide which one is most useful to for your needs
Have fun
Shane
Thank you. A lot.
Both for the speed and the depth of your responses. They were amazingly helpful.
When I finally finish my silly little tool I’m sure I will have more questions. I have… the usual unrealistic newbie-dreams.
Also: I am entirely sure that I will have managed to construct the most bloated piece of code imaginable. Yay!
Thanks again.
I’ve been coding maxscript for just over 18 months and I’m still learning new ways to do old tricks!!
It’s the fun part
Shane
Bloated code or not, you’re trying and that’s all that matters!
Best of luck to you.
Hello again,
So I’ve pretty much finished my rediculous little tool. I have two more questions.
The first is fairly simple. I want to be able to call a function and have it change a variety of variables. This does not appear to be something functions can do, which confuses the heck out of me. I basically want to be able to trigger a section of code by calling a… something. Is this a function? If so, I’ll have more questions.
Second: I’ve got most of the code working so far, but I wanted to create a sort of stopgap for changing selection. I wanted to have the rollout close when you change selection. For some reason this returns an error of “>> MAXScript Callback script Exception: – Type error: closeRolloutFloater requires RolloutFloater, got: undefined <<”
Despite the fact that I -am- calling it on a floater. I am confused.
The code for my tool is here:
macroScript BigLock category: "Testing"
(
on isEnabled return
(
selection.count == 1
)
on execute do
(
global boomrollout = "closeRolloutFloater(big_lock_float)
"
boomrollout += "callbacks.removescripts id:#biglocks"
callbacks.addScript #selectionSetChanged boomrollout id:#biglocks
global keyhole = $
global lockarray = getTransformLockFlags (keyhole)
rollout lock_rol "Locks"
(
button lock "Lock All" width:77
button unlock "Unlock All" width:77
checkbutton posx "X" checked:lockarray[1] across:3 offset:[0,13]
on posx changed state do
(
lockarray[1] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton posY "Y" checked:lockarray[2]offset:[0,13]
on posY changed state do
(
lockarray[2] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton posZ "Z" checked:lockarray[3]offset:[0,13]
on posZ changed state do
(
lockarray[3] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton rotX "X" checked:lockarray[4] across:3 offset:[0,20]
on rotX changed state do
(
lockarray[4] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton rotY "Y" checked:lockarray[5] offset:[0,20]
on rotY changed state do
(
lockarray[5] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton rotZ "Z" checked:lockarray[6] offset:[0,20]
on rotZ changed state do
(
lockarray[6] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton scaleX "X" checked:lockarray[7] across: 3 offset:[0,20]
on scaleX changed state do
(
lockarray[7] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton scaleY "Y" checked:lockarray[8] offset:[0,20]
on scaleY changed state do
(
lockarray[8] = state
setTransFormLockFlags keyhole lockarray
)
checkbutton scaleZ "Z" checked:lockarray[9] offset:[0,20]
on scaleZ changed state do
(
lockarray[9] = state
setTransFormLockFlags keyhole lockarray
)
groupBox posbox "Position" pos:[10,57] width: 87 height: 42
groupBox rotbox "Rotation" pos:[10,103] width: 87 height: 42
groupBox scalebox "Scale" pos:[10,149] width: 87 height: 42
on lock pressed do
(
posx.checked=true
posy.checked=true
posz.checked=true
rotx.checked=true
roty.checked=true
rotz.checked=true
scalex.checked=true
scaley.checked=true
scalez.checked=true
setTransformLockFlags keyhole #all
)
on unlock pressed do
(
posx.checked=false
posy.checked=false
posz.checked=false
rotx.checked=false
roty.checked=false
rotz.checked=false
scalex.checked=false
scaley.checked=false
scalez.checked=false
setTransformLockFlags keyhole #none
)
)
big_lock_float=newrolloutfloater "Big Lock" 120 230
addrollout lock_rol big_lock_float
)
)
Any help would be greatly appeciated. Is this as hidiously bloated as I imagine it to be?
- Cheers *
The first is fairly simple. I want to be able to call a function and have it change a variety of variables. This does not appear to be something functions can do, which confuses the heck out of me. I basically want to be able to trigger a section of code by calling a... something. Is this a function? If so, I'll have more questions.
Okay, I’m confused, I think you might need to explain yourself a little further…
I think where you are getting stuck is that variables are been passed by reference only, this basically means that you can’t change the underlying “value” of the variable from within a function. You want to be able to pass by “value”…You need pefix your function parameter with “&” and the variable with “&” when passing the value…
fn test &aValue = (
-- This will change the "value" of the variable
aValue = 10
)
(
local aValue = 1
-- aValue is equal to 1
test &aValue
-- Will now print 10...
format "aValue = %
" aValue
)
Passing by value and passing by reference is a relative simple concept, but it can take some time to get your head around…
Second: I've got most of the code working so far, but I wanted to create a sort of stopgap for changing selection. I wanted to have the rollout close when you change selection. For some reason this returns an error of ">> MAXScript Callback script Exception: -- Type error: closeRolloutFloater requires RolloutFloater, got: undefined <<" Despite the fact that I -am- calling it on a floater. I am confused.
Ha, have the answer to this…
global boomrollout = "closeRolloutFloater(big_lock_float)
"
boomrollout += "callbacks.removescripts id:#biglocks"
.
.
.
big_lock_float=newrolloutfloater "Big Lock" 120 230
Okay, the first line is good. No real problems…
The last line is the actually issue! big_lock_float is only defined as local to the on execute event handler, therefore when max tries to run you call back script, it is not able to find the variable, because the callback is occuring outside of the execute event handler…it’s a scope issue…
At the top of the script add “global big_lock_float”…This will allow the callback mechanism to find it and it should close your rollout…
edt: Actually, put it at the top of the macro defination…
macroscript ... (
global big_lock_float
.
.
.
)
Keep it coming!!
Shane
Aha! It was a scope problem. I thought it might be something like that.
I tend to fail at communication. I want to do precisely what you are suggesting, but I don’t want to have to send the variables to the function.
basically I want to to something like this:
function newobject
(
keyhole = $
lockarray = getTransformLockFlags (keyhole)
posx.checked = lockarray[1]
...
...
scalez.checked = lockarray[9]
)
The problem is, of course, that the function can’t pass all those variables back to the rest of the script. Will it work if I pass all of the variables to the function, and use the “&” sign to send them all back?
Actually, yeah, that sounds like it should work. I’m going to go try that. If it doesn’t work, I’ll have more questions.
Thanks very much for the help.
You can access the controls in the rollout in 1 of 2 ways…
If you define a function within the rollout, the function will have scope to access the controls and modify them as required or for that fact, any variables you define within the context of the rollout…
rollout myRollOut ... (
local myVar -- I'm accessiable from within the context of the script...
button myButton ... -- I'm accessiable from within the context of the script....
fn myFun = (
myVar = "Something..."
myButton.text = myVar
)
)
Now, if you need to access them “outside” of the rollout, ie from within the macro script, you should be able to gain access via the rollout’s variable name…I’ve found this to be problem matic as changes to a rollout when it is not visible tend to get ignored…in my experience…
So using the example above…
myRollout.myFun() -- This is calling the function inside my rollout
myRollout.myVar = "Something new" -- This is accessing the variable inside the rollout
I don’t know if that helps any…
Cheers
Shane