Notifications
Clear all

[Closed] Detecting CA value changes

Hey there. I’m trying to get two objects to dynamically hide and unhide when a slider’s value is changed whilst a checkbox (in this case called AutoHide) is active:


 on AutoHide changed state do
 (
 	 if state == on then
 	 (
 		  TheSlider = $Object03.modifiers[#Attribute_holder].parameters[1]
 		  (
 			   if TheSlider.value > 50 then
 			   (
 					hide $Object01
 					unhide $Object02
 			   )
 			   else if TheSlider.value < 50 then
 			   (
 					unhide $Object01
 					hide $Object02
 			   )
 		  )
 	 )
 	 else if state == off then unhide #($Object01, $Object02)
 )
  

At this stage it works, but only when the checkbox is clicked, where I want it to do it when the slider is moved too. However, if I add an “on TheSlider changed sliderVal do” under the slider definition, I get a syntax error.
This checkbox code is in a custom attribute which is a seperate rollout from another CA that contains the slider. Do they need to be in the same rollout? What’s the solution?
:¬/

13 Replies

Are you trying to animate visibility?
why not add a ‘visibility track’ to the object in ‘track view’ ?

No, I don’t want animate the visibility, I actually want to set up a CA checkbox that – when activated – will literally hide certain objects and unhide others when a slider is set at certain amounts.
:¬)

In the past I have used something like this:

on spn_Hide buttonup do
(
if spn_Hide.value > 50 then ( hide $theobject) else ( unhide $theobject)
)

I hope it helps

Dan Lane

 PEN

Not sure that I follow Brad. Do you have two seperate CA definitions? or just two different rollouts in on CA def?

[Edit]
This uses two caDefs on one object. The second def stores a reference to the first but i couldnt’ get it to work both ways due to a dependancy loop issue. I did a work around though that got it to work.

Try this out Brad:


   sph=sphere()
   emptyMod=(EmptyModifier())
   addModifier sph emptyMod
   tea=teapot()
   
   def=attributes test
   (
   	parameters testP rollout:testR
   	(
   		hideIt type:#boolean ui:hideItCb
   		hideNode type:#node
   	--	test2Ref type:#maxObject --Will not allow me to do this in both directions
   	)
   	fn hideItFn val=
   	(
   		if hideIt then
   		(
   			print val
   			case of
   			(
   				(val<=50): hide hideNode
   				(val>50): unhide hideNode
   			)
   		)else
   		(
   			unhide hideNode
   		)
   	)
   
   	rollout testR "Test"
   	(
   		checkBox hideItCb "Hide It:"
   		on hideItCb changed state do
   		(
 		 --((refs.dependents this)[4]) is a work around for a dependancy loop problem is I try to
 		 	--store a reference in each of the CADefs of the other. I can do it one way but
   				--not both. 
 			if state==true and ((refs.dependents this)[4]).test2.theSlider<=50 then
   			(
   				hide hideNode
   			)
   			if state==false then unhide hideNode
   		)
   	)
   )
   
   def2=attributes test2
   (
   	parameters testP rollout:testR
   	(
   		theSlider type:#float ui:theSliderSl
   		testRef type:#maxObject --Store a reference to the first def
   	)
   	rollout testR "Test 2"
   	(
   		slider theSliderSl "Slider:"
   		on theSliderSl changed val do
   		(
   			testRef.hideItFn val
   		)
   	)
   )
   
   custAttributes.add emptyMod def
   custAttributes.add emptyMod def2
   
   emptyMod.test.hideNode=tea
   --emptyMod.test.test2Ref=emptyMod.test2
   emptyMod.test2.testRef=emptyMod.test
   select sph
   

Your script works really well, but I’m still getting my head around a few of the things you’ve done that are new to me (ie. the “case” definition and functions within CAs).
I have two sepearate definitions on the one object. It’s just how I prefer to work using your rigging utils. If I want to break it up into two CA scripts that I can use with your utils which one does the function go into? I guess I also need to have the relevant nodes stored in each CA script as I need to access the state of the sliders/checkbuttons in each one (although that refs.dependents bit could be a clever way around it…).
Being greedy, I’d also like to have it update when the timeslider is moved and when the slider’s keyframe value is changed, but I think I can figure that one out…
:¬)

case of is quite nice so you have to define a lot of if then else

bu in the case of using if :

if TheSlider.value > 50 then
(
hide $Object01
unhide $Object02
)
else if TheSlider.value < =50 then
(
unhide $Object01
hide $Object02
)

yo have to define a reaction when the value is equAl to 50 If not your script wil get an error when is exactly equal to 50

paul already done it in shis sample script ;).

Are the object gone to be defined by node or by name?

 PEN

Glad that you are learning from it Brad. There are a few things going on in the script that I don’t think many people know about.

The case statement as luigi as pointed out is a cleaner way of dealing with nested if statements. From what I can rememer is was also faster then a bunch of if statements but i could be wrong on that. It is usualy used with radioButtons where you could say case radioButton.state of and then list the integers that represent the different states of the radio button. I stepped it up a bit and instead of just an integer I placed an expression instead for each of the states of the case statement.

The next thing that I did was store a reference to the first definition in the second using maxObject. Using this method to means that you don’t have to refer to objects by name. You also don’t have to worry about the stack changing, the modifier the attributes are on chaning name or even the definition being moved somewhere else on the rig.

Using refs.depentents this is a great way to refer back to the object that the definition is on. It returns an array of depentents so you need to check which in the array that you need.

Using Functions inside of definitions is something that I use all the time. I often have definitions that are only functions and noting else. You can access these functions from else where in Max and use those functions. I will do this if I’m using script controllers and I have a bunch that are similar and need like functions. I will store the function in a ca def and access that def from the script controller. As you know you can also have a function inside of a rollout in the def and that is perfectly valid as well and can also be accessed if needed with theDef.theRollout.theFunction(). This can be a pain if you have a definition that has multiple rollouts that all use the same set of functions.

Brad, can I ask why you have multiple definitions and not just one with multiple rollouts?

OK…
So I decided to put the checkbutton inside the same rollout as the slider and it’s saved me some headaches. I’ve put the main calculation into a function and it works a lot cleaner now.
However, as I mentioned earlier, I wanted to have the hiding/unhiding update when scrubbing the timeslider, which I have achieved by adding a registertimecallback to the function when the checkbutton is true and unregistering it when it is false. So far so good…
Now it gets more complex as I have two objects with CAs that I want do the same thing in an interlinked sort of way. ie. the slider’s value is instanced and when one checkbutton is active, the one on the other object is active too. The problem comes when I activate the checkbutton on one object, select the other and turn it off. I’ve registered the callback with the first object but turning it off in the other doesn’t unregister it.
How can I access the function inside the CA of another object? Also, the function doesn’t work unless one of the objects is selected. Do I need to make it some sort of global function? Can I instance checkbuttons’ values without having them be animateable?
As an insight to my workflow, to store nodes, what I do is an old-fashioned node store of one object that has a position script controller on it. That script controller contains nicely named node variables of all the objects I want to store in the scene. That way, I can add and remove nodes with a more visual (ie. more intuitive for me) interface and don’t have any dependency loops troubles. From there I can access those nodes by name by doing something like this:
IK_ArmCtrl = this.Node_Storage.node.position.controller.getnode “IK_ArmCtrl”
It may look a long-winded, but it makes more sense to me.
One thing I also noticed in your example script Paul, is that you have the function between the parameters and rollout sections. I could only access it when it was within the rollout. Is it better to have the function outside of the rollout and if so, what CA code do I need to access it?
It seems as I get the answer to one question, five more are raised…

The reason I uses multiple definitions is because when I started using the PEN rigging utils, I didn’t know you could have multiple rollouts in the one CA, plus I like to see a list of the rollouts I have on an object in the edit attributes window. Once again, just something I’ve become used to. I guess as I get deeper into the script side of rigging I see I will probably have to change that method.

BTW, thanks Luis and Paul for the “case” description, I knew of it but as usual, I didn’t know the best situation to implement it.
:¬)

 PEN

Does that help?


 s=sphere()
 empt=emptyModifier()
 addModifier s empt
 
 
 def=attributes test
 (
 	parameters testP rollout:testR
 	(
 		someText type:#string UI:theSphereEt default:"Sphere"
 	)
 	
 	fn changeTheString str=
 	(
 		someText=str
 	)
 	
 	rollout testR "Test"
 	(
 		editText theSphereEt "The Sphere"
 	)
 )
 custAttributes.add empt def
 
 --Here I access the function that is in the def stored on the modifier
 empt.changeTheString "crap"
 --or
 $sphere01.modifiers[1].changeTheString "What Ever"
 
 select s
 max modify mode
 
Page 1 / 2