PDA

View Full Version : MS noobquestion: passing a variable


le1setreter
03-26-2009, 08:22 PM
hi all,

from time to time i do some little maxscript with the help of the max-ms help and reading/googling into this forum and also into scriptspot. with some basic knowledge of js and php i have been able to make little scripts for some easy automated processes. its mostly try and error but at the end it always has been a great time saver.

right now a have done another little script and want to make it usable for other people without typing e.g. basic vars and object names into to script itself. it took some time to manage my first rollout but i have problems with passing the vars over to my functions.

can somebody help me on understanding how to do that? i know i should buy myself some good book and spend time on intense learning but i have to admit i only touch ms when it seems to be very important and the other time i try improving modelling and render skills.

anyway here is a cropped version of my problem. what do i have to do that the function
knows the object i selected earlier? Thanks in advance and sorry for bad english.



clearselection()
rollout varTest "varTest" width:240 height:80(

fn doIt = (
newObj = instance testObj
newObj.pos = [0,0,0]
)

pickbutton chooseObj "pick object" width:200
on chooseObj picked testObj do(
if testObj != undefined do(
chooseObj.text = testObj.name
)
)

button exeBtn "do it" width:200
on exeBtn pressed do (
doIt()
)


)
createdialog varTest

thatoneguy
03-26-2009, 10:31 PM
I always pass in the obj to the function. That avoids any and all scope issues. Most of my functions are in a global scope. So the variable can be passed to them even if it's created in a local function and doesn't have to be defined as a global variable itself. Even large scripts tend to only have 3 or 4 global variables max and use structs wherever possible.

fn doIt Obj = (
newObj = instance Obj
newObj.pos = [0,0,0]
)

SyncViewS
03-26-2009, 10:41 PM
Hi Horst,
MaxScript Reference is your best teacher. I slightly changed your code and pointed out the relative information in the Reference.


-- clearselection()
-- remove this or it will deselect anything before running the script

rollout varTest "varTest" width:120 height:30
(
-- use a regular button that triggers the action
button btInstance "Instance this!" width:110 align:#center

-- create a function and after its name, list the parameters you want to pass
-- to it. You will access the same variables inside the function body.
-- See MaxScript Reference "Creating Functions" and sub paragraphs
fn doIt objToInst instName instPosition =
(
newObj = instance objToInst
newObj.name = instName
newObj.pos = instPosition
)

on btInstance pressed do
(
-- the 'selection' ObjectSet stores references to the current selection
-- See MaxScript Reference "ObjectSet Values"

-- the .count is a property of ObjectSets and Arrays and stores
-- the number of elements in the set
-- See MaxScript Reference "Array Values"
local selCount = selection.count

-- test the number of currently selectled objects
-- See MaxScript Reference "Controlling Program Flow in Scripts"
if (selCount == 1) then
(
-- call the function 'doIt' and pass some values
-- selection[1] means the first element in the current selection set
-- See MaxScript Reference "Function Parameters"
doIt selection[1] "My New Instance" [10, 20, 30]
)
else if (selCount == 0) then
(
messageBox "Please pick an object" title:"Error"
)
else
(
messageBox "Too many objects selected" title:"Error"
)
)
)
-- create a dialog just a litter fancier, but not required :)
createDialog varTest style:#(#style_toolwindow, #style_border, #style_sysmenu)

- Enrico

Bobo
03-26-2009, 11:29 PM
The principle you have to remember is: You cannot access a variable if it has not been already declared. If your function looks for 'testObj', it won't find it anywhere, so a NEW local variable will be created automatically inside the function. That variable will be of course 'undefined' and this will cause an error.

The other problem is that the vartiable testObj passed to the event handler has a very short life expectancy - it is created as local to the even handler and destroyed right after the handler stops running. So testObj does not exist outside of the handler.

Even if testObj was defined inside the chooseObj event handler, the function would not "see" the variable because it comes up later in the code.

To fix this, all you have to do is pre-declare testObj as local in the beginning of the rollout BEFORE both the function and the even handlers, then make sure you assign the argument of the handler to that variable to preserve it beyond the life of the handler's scope.

This will initialize an empty undefined variable, then when the even handler picks an object, it will "see" that variable and will write into it instead of creating a new one implicitly. Then when the doIt function is called, it will also "see" the existing variable and use it instead of creating its own.

I also added some code to disable the second button and only enable it when you pick a valid object.

(
clearselection()
rollout varTest "varTest" width:240 height:80
(
local testObj
fn doIt = (
newObj = instance testObj
newObj.pos = [0,0,0]
)

pickbutton chooseObj "pick object" width:200
button exeBtn "do it" width:200 enabled:false

on chooseObj picked obj do(
if obj != undefined do(
testObj = obj
exeBtn.enabled = true
chooseObj.text = testObj.name
)
)
on exeBtn pressed do (
doIt()
)
)
createdialog varTest
)

le1setreter
03-27-2009, 09:48 AM
thatoneguy, SyncViewS and Bobo - many thanks for your replies and help.
sadly i can not read/understand your code and comments that easily so i have to work me through and this will take some time. but i will post feedback after i am finished.

besides you helped me with my problem i am very surprised and happy to see that there are still people out there willing to help and share knowledge without financial or other personal benefit. many thanks and a big karma point to all of you.

le1setreter
03-27-2009, 02:50 PM
ok, here we go. thanks for your explanations. i learned a lot and finally got my litte script to work (although i believe the code is not good).

anyway, i needed to create some ropes (of single elements) that have to be very editable so i came along the spacing tool, but after changing the spline i have to delete the instanced objects and reuse the spacing tool again. in my case an absolute time killer so a tried to make the script.

this script is for free and anybody may use it and/or create changes.

attached you will find a mini tut and the script itself.

also here is the code:




clearselection()

rollout ropeSim "obj2spl aligner" width:180 height:240
(

local origObj -- the object that should be instanced
local targetSpline -- the spline where the the instances are aligned to
local instanceCount -- the amount of instances
local instanceArray = #() -- array for new createt instance objects


-- selecting the object to clone/align:
pickbutton chooseObj "pick object" width:140 tooltip:"pick the object to be duplicated"

-- selecting the spline to align on:
fn validSpline spl = classof spl == Line
pickbutton chooseSpl "pick spline" width:140 filter:validSpline tooltip:"pick the line/spline for alignment of objects"

-- setting amount of duplicates/instances
spinner instCount "InstanceCount:" pos:[60,80] width:80 height:16 range:[2,1000,0] type:#integer

-- preview Button
button prevBtn "create" pos:[20,120]

-- cancel Button
button redoBtn "reset" pos:[90,120]

-- infobox
label lab10 ""
label lab11 "This script is for aligning" align:#left
label lab12 "object instances along a spline." align:#left
label lab13 "Beware to eventually change the" align:#left
label lab14 "object rotation to get desired result" align:#left


fn cloneAlign = (
for i = 0 to instanceCount do (

percentState = 100.0/instanceCount * i

-- oldObj = obj
-- spl = getnodebyname "Line02"

new_copy = instance origObj --instance the object
new_copy.name = uniquename (origObj.name+"_Instance") --rename it
append instanceArray new_copy
-- print instanceArray
new_copy.pos.controller = path follow:true path:targetSpline constantVel:true percent:percentState allowUpsideDown:on
new_copy.transform = origObj.transform --copy the TMatrix to orient correctly
)
-- print instanceArray
)

fn deleteInstances = (
for k = 1 to instanceArray.count do (
-- print instanceArray[k]
delete instanceArray[k]
)
-- empty array
instanceArray = #()

)



-- if object is picked:
on chooseObj picked obj do(
--see if the user did not cancel the picking...
if obj != undefined do(
--if he did not, make the box's wireframe red:
obj.wirecolor = red
origObj = obj
--and display the name of the object on the button:
chooseObj.text = obj.name
)
)--end on


-- if spline is picked:
on chooseSpl picked spl do(
--see if the user did not cancel the picking...
if spl != undefined do(
--if he did not, make the box's wireframe red:
spl.wirecolor = red
targetSpline = spl
--and display the name of the object on the button:
chooseSpl.text = spl.name
)
) --end on

-- if spinner is changed:
on instCount changed val do(
instanceCount = val
-- print val
) --end on

-- id preview button is pressed:
on prevBtn pressed do (
-- messagebox "do the action"
cloneAlign()
) --end on

-- if cancel button is pressed:
on redoBtn pressed do (
deleteInstances()
) -- end on

on ropeSim close do(
-- max undo
-- deleteAllChangeHandlers id:#ropeSim_handler
) --end on




)

createdialog ropeSim


thank you.

CGTalk Moderation
03-27-2009, 02:50 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.