Notifications
Clear all

[Closed] Script Controller update based on spline change

I have searched this forum high and low for a solution to this and none of them seem to work. I am writing a scripted plug-in that currently distributes an array of objects along a curve using position_script(). Everything works fine except the objects don’t update unless the frame slider is moved. This is really annoying and I remember running into it before.

I have tried a couple different things in the position script:

fn updateScript ev nd = (self.pos.script.update)
 callbackItem = NodeEventCallback mouseUp:true geometryChanged:updateScript 
when geometry thePath changes do (self.pos.script.update)

In both cases self is a reference to the node the script controller is on, and in both cases I get the following error:

Runtime error: Code block not created, unable to access code block local or parameter: self

Does anyone have any ideas? I’ve seen other scripts using the path constraint but because I want to add some other things I’m trying to avoid that.

Thanks!!
-Steve

6 Replies
 PEN

Well the script controller that is on each of the objects long the path should have a variable added, lets call it path, and is should hold reference to the splines node. Any changes to the spline will result in the script controller being fired.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

I absolutely agree with PEN. If you add path object as a node to a script controller any geometry change of the path has to fire the script controller update event.

By the way:

  1. if you want to use “when” construction it’s better to use it with unique id, and delete its handler before calling next time.
  2. “notify dependents” for the path has to fire the script controller update .

PS. I don’t have MAX on tap now, and I can’t double-check it.

Hey Paul,

Thanks for the reply. When updating the transform of the spline, yes, this works in realtime. However, making any changes to the splines CVs requires a move of the time slider to get the scripts to update. How annoying! So I’m trying to force an update of the script but I keep getting that error.

OK so I have managed to separate out the callback so that I’m A) not creating a crapload of them inside each position script and B) able to actually call an update to the script without it throwing that error. The problem I am now having is that the update method that I’m calling on each script doesn’t actually do anything. According to the docs update() should reevaluate the expression on the script when called, this doesn’t appear to be happening:

 when geometry myPath changes do
       (
       updateScripts()
       )
fn updateScripts = 
       ( 		  
        try
        (			   
         print "updated scripts"			
         for i = 1 to myArray.count do
         (					   
          myArray[i].position.controller.update						
         )
        )	   
        catch
        (
         print "updateScripts error"
        )
      )
  The listener is printing "updated scripts" but the actual objects aren't changing position. Is this the correct method to invoke to update a script?

AHA!

myArray[i].position.controller.Update()	

Updating the PRS of the path updates the scripts just fine, but when altering CVs of the path they don’t update. I tried using notifyDependents thePath instead of running through and manually updating each script, and it also didn’t work. Am I missing something?

Here is my script as it currently stands. Right now I am creating a scripted helper plug-in and I’m adding the when construct on selection of the path. It works ok for a while but after manipulating the curve for a while max crashes. I will look into the ID and also removing the handler, but where would I add it again? Also if you are running this script the only way I’m calling the assignScripts() function is by changing the copies spinner.

plugin Helper curveArray 
   	name:"Curve Array" 
   	category:"Scripted Array"
   	classID:#(0x48bf698a, 0x4ec80c97)
   	extends: Dummy
   (
   	--local nodes
   	local myPath
   	local myObj
   	local myArray = #()
   	--local functions
   	local calcPos
   	--local rollouts
   	local params
   	
   	parameters main rollout:params
   	(
   		
   		choosePath type:#node ui:choosePath subAnim:true
   		
   		chooseObj type:#node ui:chooseObj subAnim:true
   		
   		numObjs type:#Integer ui:numObjs
   		
   	)
   	
   	fn updateScripts = 
   		(
   			
   			try
   			(
   				
   				for i = 1 to myArray.count do
   					(
   						
   						myArray[i].position.controller.Update()
   						
   					)
   
   			)
   			
   			catch
   			(
   				
   				print "updateScripts callback error"
   				
   			)
   			
   		)
   		
   		fn deleteObjs =
   		(
   			
   			if (myArray.count > 0) do
   			(
   			
   				for i = 1 to myArray.count do
   				(
   					
   					if (isValidNode myArray[i]) then delete myArray[i]
   					
   				)
   			
   			) 
   			
   			myArray = #()
   			
   		)
   	
   	rollout params "Instance Parameters" width:162 height:99
   	(
   
   		fn shape_filt obj = isKindOf obj Shape
   
   		fn obj_filt obj = isKindOf obj GeometryClass
   
   		pickbutton choosePath "Select Path" pos:[12,7] width:140 height:21 filter:shape_filt
   		
   		--checkbox followSpline "Follow Path" pos:[69,33] width:79 height:15 
   		
   		spinner numObjs "Copies:" pos:[24,53] width:120 height:16 range:[1,1000,0] type:#integer
   
   		pickbutton chooseObj "Select Object" pos:[11,74] width:140 height:21 filter:obj_filt 
   		
   		fn assignScripts =
   		(
   		 
   			if(myObj != undefined and myPath != undefined) do
   			(
   				 
   				deleteObjs()
   						
   				for i = 1 to numObjs.value do
   				(
   					ctrl = position_script()
   					myInst = instance myObj
   					myInst.pos.controller = ctrl
   					ctrl.addNode "thePath" myPath
   					ctrl.addNode "self" myInst
   					ctrl.addConstant "numObjects" (numObjs.value - 1)
   					ctrl.addConstant "ID" (i-1)
   					ctrl.script = "lengthInterp thePath (ID/numObjects as float)"
   					append myArray myInst
   				)
   				 
   			)
   			 
   		)
   		
   		--If the user picked an object, then
   		
   		on choosePath picked obj do
   		( 
   		
   			 if obj != undefined do
   		
   			 (
   				 
   				myPath = obj
   		
   				choosePath.text = obj.name
   				 
   				 when geometry myPath changes do
   				 (
   					 updateScripts()
   				 )
   		
   			 )
   		
   		)--end on
   		
   		on chooseObj picked obj do
   		( 
   		
   			 if obj != undefined do
   		
   			 (
   
   				myObj = obj
   		
   				chooseObj.text = obj.name
   		
   			 )
   		
   		)--end on
   		
   		on numObjs changed obj do assignScripts()
   		
   	)
   	
   	 tool create 
   	 ( 
   		 on mousePoint click do 
   		 (
   			 case click of
   
   			  (
   
   				1: coordsys grid (nodeTM.translation = gridPoint)
   				2:  (#stop)
   
   			  )
   
   		 )
   
   	 ) 
   	 
   	 on getDisplayMesh do
   	 (
   		 if (meshObj == undefined) do 
   
   			(
   
   			meshObj = createInstance box length:5 \
   
   			width:5 height:5 mapCoords:false \
   
   			)
   			
   			meshObj.mesh
   
   	 )
   
   	on deleted do
   	(
   		
   		deleteObjs()
   
   	)
   	
   	on update do
   	(
   	   
   		deleteObjs()
   		
   	)
   	
   	
   )