Notifications
Clear all

[Closed] loops not evaluating until successful?

hey guys,
i have an interesting problem here that i’m hoping someone with more mxs experience can clue me in on:

i have a for loop that creates linear_position and linear_rotation controllers on bones. further down in the for loop, i try to wire those controllers weights to other nodes in the scene. however, when it goes to evaluate the paramWire.connect, it errors out saying that “no sub anims exist.” if i use the debugger, i can see that the controllers aren’t actually created yet (the controller.count is incorrect), even though they are specified earlier in the loop. if i comment out the paramwires and just leave the controller creation in there, the script runs fine and the controllers are created, which leads me to believe that they aren’t created until the for loop successfully evaluates.

i’m hoping someone more familiar with mxs can verify whether my guess is correct or not, and maybe even suggest a workaround to force the controllers’ creation before the paramWire step?

5 Replies
 JHN

Well without seeing the real code, I can’t be sure. But you can always add a “with redraw on” context in which you create the constraints. Or you can do 2 for loops, one creating the constraints and a second on creating the wiring. You can store the controllers and some other data perhaps in a big array in the first loop and wire in the second.

Just some thoughts, maybe showing an piece of example code will help us debug.

-Johan

i don’t feel too comfortable posting much, as i guess this would be considered company property, but here’s a short excerpt that hopefully gives an idea:

		
  For obj in BoneList do
  (
 	 for CurShape in ShapeArray do
  	 (
  		if abs tmp.x + abs tmp.y + abs tmp.z > 0.0001 do
  		(
  		obj.Node.position.controller.Available.controller = linear_position ()
  		PosIndex = obj.Node.position.controller.count
  		obj.Node.position.controller.setName PosIndex CurShape.name
  		obj.Node.position.controller[PosIndex].value = CurShape.positions[i]
  		DoPos = true
  		)
  
  ... other stuff
  
  		 if finditem d1Ctrls ctrlName != 0 then
  		 (
  		 ctrl = getnodebyname ctrlName
  		 curTrack = ctrl.pos.controller[#Y_Position].controller[#Limited_Controller__Bezier_Float]
  					
  		  if doPos do
  		  paramWire.connect curTrack obj.Node.position.controller[#Weights][("Weight__" + ctrl.name)] ("if "+ curTrack.name  +" < 0 then 0 else " + curTrack.name)
  		  )
  	 )
  )

i thought about putting the first controller creation step into an external function which would get called, which maybe might work(?), but there are a lot of variables to pass and i was hoping to find a way to deal with it within the local scope of that loop. the same problem exists with creating another for loop. there are lots of array indices to store to access data.

Certain blocks of code create a single Undo record when evaluated. If an error occurs during the evaluation of that block, the whole block is undone to prevent getting Max into a bad state, so that’s probably what you are seeing.

One way to avoid this would be to enforce your own Undo record creation so that each controller creation causes a separate Undo record to be stored. Thus, when an error occurs, only the last Undo record would be taken back but the rest of your work would be there.

That being said, it would be better to avoid the error by either fixing the code or trapping the error in a try()catch() (the latter not really recommended, but possible).

 JHN

Somethings I notice in a first glance is you assign the controllers in a direct manner, I usually store a controller in a variable do stuff by referencing the variable. No need to skim the subanims that way.


  For obj in BoneList do
  (
	  for CurShape in ShapeArray do
	   (
		  if abs tmp.x + abs tmp.y + abs tmp.z > 0.0001 do
		  (
		theList = obj.Node.position.controller
		theNewController = linear_position()
		theList.available.controller = theNewController
		theIndex = theList.count
		theList.setName theIndex CurShape.name	
		theNewController.value = CurShape.positions[i]
		  DoPos = true
		  )
  
		   if finditem d1Ctrls ctrlName != 0 then
		   (
		/* Sounds like you're storing names as references, maybe look at weak references!? */
		  ctrl = getnodebyname ctrlName
		
		  curTrack = ctrl.pos.controller["Y_Position"].controller["Limited_Controller__Bezier_Float"]
					  
		  if doPos do
			paramWire.connect curTrack theList["Weights"][("Weight__" + ctrl.name)] ("if "+ curTrack.name  +" < 0 then 0 else " + curTrack.name)
			)
	   )
  )

I have not tried the code above, as I don’t have all the variables, just added some suggestions.
I have seen some errors with using # as name variable in a controller, that’s why all my names are as strings. I think there is an error somewhere in your code, but I cannot test it, and I see Bobo posted a related issue which makes sense then.
My guess is that in the naming of the tracks something goes wrong.

-Johan

thanks guys, it looks like this might have been one of those situations where the error message thrown wasn’t actually the error. it looks like it was indeed a logic error.

if you don’t mind, i have one other question about the paramWire.connect stuff…

if i put a limit controller on an object, the subanim that i want to wire becomes “Limited_Controller__Bezier_Float.” however, if i store that subanim in a variable (call it tmp) and then try to make the wire expression

“if ” + tmp.name + ” >0 then ” + tmp.name

i get an error along the lines of “Limited Controller: Bezier Float” not being a valid wireable parameter. tmp.name doesn’t return a string in the format that is usable by the expression. i’ve tried casting it in various ways (tmp as string, tmp as name, tmp.name as string) but i can’t get it in the proper format. any clues?

update: was able to get this in the format i needed by doing the following:

getsubanimname tmp 1 as string