Notifications
Clear all

[Closed] Problem understanding structures

Hi!
I’m currently trying to get deeper into maxscript, having done only small snippets before here and there. And I’m having trouble understanding some concepts on maxscript. Mainly structures, the order of things, and how to get values from for example spinners updated on other functions.
I’m trying to create a script based on Paul Neales facial bone rig script .
I’d like to have a dialog with a size spinner on it and later ticking of the hierarchy depending how many parents you need, but first I’d just like it to work again

This is the script I have now:


try(DestroyDialog surfaceHelpers)catch()
struct surfaceHelpersStructure
(
   targetNode=$,
   controlSize=1,
   
   fn dialog=
   (
   
rollout surfaceHelpers "Surface Helpers" width:200 height:150
(
   spinner 'spn1' "" pos:[100,37] width:75 height:16 range:[1,100,1] type:#float scale:0.1 align:#left
   label 'lbl1' "Remember to select surface object" pos:[25,5] width:150 height:25 align:#left
   label 'lbl2' "Control size" pos:[25,38] width:75 height:15 align:#left
   button 'btn1' "Start Creation" pos:[25,70] width:150 height:70 align:#left
   on spn1 changed val do
   (
      
   )
   on btn1 pressed  do
(
   surfaceHelpersStructure.runTool()
   )
)
),
   
   fn makeControl hit=
   (
      if hit!=undefined do
      (
         print hit.pos
         print hit.dir
         
         pt=point box:true cross:false axisTripod:true centerMarker:false size:(controlSize/2.0) wireColor:red name:(uniqueName "PT_ControlRoot")
         Zv=hit.dir
         Yv=[0,0,1]
         Xv=normalize (cross yV Zv)
         Yv=normalize (cross Zv Xv)
         pt.transform=matrix3 Xv Yv Zv hit.pos
         
         pt2=point box:true cross:false axisTripod:true centerMarker:false size:(controlSize) wireColor:green name:(uniqueName "PT_ControlPos")
         pt2.transform=pt.transform
         pt2.parent=pt
         
         cnt=circle radius:(controlSize) wirecolor:blue name:(uniqueName "CNT_Face")
         cnt.transform=pt.transform
         cnt.parent=pt2
         
         xf=xForm()
         addModifier cnt xf
         xf.gizmo.pos.z=controlSize
         convertToSplineShape cnt
      )
   ),
   
   fn runTool=
   (
      tool mouseHit
      (
         on mousePoint clickNo do
         (
            if clickNo>1 do
            (
               r=(mapScreenToWorldRay mouse.pos)
               hit=intersectRay targetNode r
               makeControl hit
               
               if queryBox "Do you want to make a mirror control" title:"Well!" do
               (
                  hit=intersectRay targetNode (ray (r.pos*[-1,1,1])(r.dir*[-1,1,1]))
                  makeControl hit
               )
            )
         )
      )
      startTool mouseHit
   ),
   
)
if $ == undefined then   messagebox "Select surface object"
else createDialog surfaceHelpers pos:[1000,300] style:#(#style_titlebar, #style_border, #style_sysmenu, #style_minimizebox)

at this point the script does not work at all. The error I get is:


Syntax error: at ), expected member name or local function: 
--  In line: );

on line 79 on the forum code point I believe, so near the end.
I had it working somewhat on max 2019, got the dialog open and could create helpers, but the size spinner did not work as it should, I was not able to update the spinner value correctly.
Then I tried it on max 2016 and trying to fix it there seem to have broken it completely.
The controlSize is back to just 1 instead of surfaceHelpers.spn1.value, because it wasn’t working correctly with only that.

I’m quite aware I’m probably doing things in a weird order with the dialog and such? But trying to search the help and online I’m not finding any good help on how these things should be done.
If anyone could help with this, I hope I could learn how these things should work
Any help is greatly appreciated!

6 Replies

I haven’t seen the purpose of your script, just tryed to make it work.
Really too many mistakes. Is all this code from you?
You can make it work by:

  • Deleting the last coma ‘,’ in your last function
  • to use your struct, you have to create an instance of it (for example, myStructInstance = surfaceHelpersStructure())
  • to use any element of your struct (data or function) outside your struct, you have to use the ‘dot’ property method (for example, myStructInstance.dialog())
  • all the calls/uses of struct elements (data or functions) inside plugin clauses (as ‘on mousePoint clickNo do’) won’t be understood as members of the struct. So you have to call/use them as your instance members (dot property method, see above) and, probably, your instance should be created as global (or creating a local variable pointing to the struct).

Thank you very much for the help!
The purpose of the script is to create helpers on the surface of objects oriented correctly along the surface normal.
All the functions, except those concerning the dialog are from Paul Neales video I linked on the first post.
It’s just me messing things up with my dialog things
But I got it working thanks to your help.


struct surfaceHelpersStructure
(
   targetNode=undefined,
   
   fn makedialog=
   (
   
      rollout surfaceHelpers "Surface Helpers" width:200 height:150
      (
         spinner 'spn1' "" pos:[100,37] width:75 height:16 range:[1,100,1] type:#float scale:0.1 align:#left
         label 'lbl1' "Remember to select surface object" pos:[25,5] width:150 height:25 align:#left
         label 'lbl2' "Control size" pos:[25,38] width:75 height:15 align:#left
         button 'btn1' "Start Creation" pos:[25,70] width:150 height:70 align:#left
         on spn1 changed val do
         (
            
         )
         on btn1 pressed  do
      (
         controlSize=surfaceHelpers.spn1.value
         shInstance.runTool()
         )
      )
   ),
   fn usedialog=
   (
      try(DestroyDialog surfaceHelpers)catch()
      surfaceHelpers=makedialog()
      if $ == undefined then   messagebox "Select surface object"
      else createDialog surfaceHelpers pos:[1000,300] style:#(#style_titlebar, #style_border, #style_sysmenu, #style_minimizebox)
   ),
   
   fn makeControl hit=
   (
      if hit!=undefined do
      (
         print hit.pos
         print hit.dir
         
         pt=point box:true cross:false axisTripod:true centerMarker:false size:(controlSize/2.0) wireColor:red name:(uniqueName "PT_ControlRoot")
         Zv=hit.dir
         Yv=[0,0,1]
         Xv=normalize (cross yV Zv)
         Yv=normalize (cross Zv Xv)
         pt.transform=matrix3 Xv Yv Zv hit.pos
         
         pt2=point box:true cross:false axisTripod:true centerMarker:false size:(controlSize) wireColor:green name:(uniqueName "PT_ControlPos")
         pt2.transform=pt.transform
         pt2.parent=pt
         
         cnt=circle radius:(controlSize) wirecolor:blue name:(uniqueName "CNT_Face")
         cnt.transform=pt.transform
         cnt.parent=pt2
         
         xf=xForm()
         addModifier cnt xf
         xf.gizmo.pos.z=controlSize
         convertToSplineShape cnt
      )
   ),
   
   fn runTool=
   (
      tool mouseHit
      (
         on mousePoint clickNo do
         (
            if clickNo>1 do
            (
               r=(mapScreenToWorldRay mouse.pos)
               hit=intersectRay targetNode r
               makeControl hit
               
               if queryBox "Do you want to make a mirror control" title:"Well!" do
               (
                  hit=intersectRay targetNode (ray (r.pos*[-1,1,1])(r.dir*[-1,1,1]))
                  makeControl hit
               )
            )
         )
      )
      startTool mouseHit
   )
   
)
shInstance=surfaceHelpersStructure()
shInstance.targetNode=$
shInstance.usedialog()

I moved the controlSize variable to the button press so I got it updating correctly. Not sure if it’s the best way, but seems to be working
Still a few things I’d like to add to it, but I believe I can manage them now. Thank you again!

I’m glad I was helpful but… your code still doesn’t work. Try it restarting 3dsMax: it will throw errors.
You have problems with variables visibility due to their scope.
Edit: I’ll try to give you a working version with some explanations.

Yes, I noticed after trying on another version of max.
So still gotta do some changes
That controlSize with the spinner was the biggest problem for me anyway, so the fight continues.
Is it possible to define a variable for the whole structure that pulls a value from inside one of the functions? The controlSize variable in this case getting the value from the dialog spinner.
Or should I pull the value inside functions that need it? And how could I do that?

Not sure what is the best practice for this, or functional.

Here’s a code with three different methods of accessing the ‘controlSize’ value.

Thank you very much for this! Truly appreciate all of this
Really helps to understand how these things work.