State Transition Dialog

Create panel > Helpers > Object Type rollout > Crowd > Setup rollout > Cognitive Controllers > Right-click a transition line.

Select a Crowd object. > Modify panel > Setup rollout > Cognitive Controllers > Right-click a transition line.

These settings control how the software effects a transition from one state to another when using a cognitive controller. For more detailed information, see To set up and use a cognitive controller.

The Transition Script

The most important element of the transition is the MAXScript conditional script. This is a script associated with the controller that is executed once per frame, and can test any aspect or aspects of the scene and cause a transition or not, depending on the result.

Scripts are executed once per frame per assigned delegate, so objects and effects can be animated and still let delegates react with accuracy.

All scripts used in transitions use the following structure:

fn [FunctionName] del t = (
[MAXScript code]
if [MAXScript conditional] then 1
else 0
)

The opening section contains "fn" (function) followed by the function name, which also must appear in the State Transition dialog, and then the input parameters "del t", and lastly "= (". Following this there can be any MAXScript code.

The closing section contains a MAXScript conditional, and then "then 1 else 0". This means: If the result of the conditional is true, then return 1 (that is, the transition is to take place), or if the result of the conditional is false, then return 0 (that is, the transition is not to take place). You could reverse the order of the numbers 1 and 0 ("then 0 else 1") so that the conditional being true would cause no transition to take place, and vice-versa. Lastly, the function must end with a close parenthesis: ")".

Following are some examples of scripts that can be used in cognitive controllers, along with brief explanations. These are presented for you to modify and use in your own scenes.

To test a particle system parameter

This sample script tests the number of particles emitted by particle system Spray01, and returns positive if the number equals 100.

fn TestParticles del t = (
if (particleCount $Spray01) == 100 then 1
else 0
)

Note that, in testing for an equality, MAXScript uses a double = to signify that it's not an assignment.

To test an object position

This sample script tests the location of the object named Sphere03, and returns positive if its position is (X>=150, Y>=0, Z>=70).

fn PositionCheck del t = (
if ($sphere03.pos.x >= 150
and $sphere03.pos.y >=0
and $sphere03.pos.z >=70) then 1
else 0
)

To test an atmospheric property

This sample script tests the Density parameter of a fog effect, and returns positive if it equals 50.

fn TestAtmos del t = (
atmos_fog = getAtmospheric 1
print atmos_fog.density -- to:debug
if (atmos_fog.density == 50) then 1
else 0
)

Note the second line, which assigns the fog atmospheric to a variable named "atmos_fog". This is necessary only for atmospheric effects; with most standard objects, you simply use the object name preceded by a $, as in the two previous examples. The "1" following the getAtmospheric command refers to the atmospheric's position in the Rendering Effects dialog > Effects list.

Once you've executed this assignment, you can obtain a list of the atmospheric's properties by entering this command in the MAXScript Listener:

ShowProperties atmos_fog

Also, the third line in the sample script isn't necessary for the cognitive controller; it simply prints the result of the test in the Listener window for debugging purposes.

To test the distance between two objects

This sample script uses MAXScript's Distance function to obtain the distance between a delegate and a scene object, and returns positive if the result is less than 30.

fn TestDist del t = (
get_dist=distance $sphere01.pos $delegate02.simpos
print (get_dist)
if get_dist < 30 then 1
else 0
)

As in the previous example, a variable is used; this time, just to keep the script simple. In the second line, the Distance function is used to obtain the distance between a sphere and a delegate, and the result is assigned to the variable "get_dist". If you wanted to test all delegates that use the cognitive controller instead of a specific one, you'd replace "$delegate02.simpos" with "del.simpos".

Note: The special property "simpos" is used to determine a delegate position during a simulation solution. This is necessary because newly calculated delegate positions aren't available to MAXScript via the standard "[node].pos" property during a simulation. To get other transformation data calculated during a simulation solution, such as rotation, use the simTransform property. The simTransform property is documented in the MAXScript reference.

In the third line of the script, the calculated distance is printed to the Listener window, for debugging purposes. This line is not necessary for the simulation and can be deleted. Lastly, the value is compared with the constant 30, and if it is less, the script returns a 1, indicating that the transition is to take place.

You can draw on this script to create a cognitive controller that uses multiple Seek behaviors/states to move delegates along a path among any number of objects. As soon as the delegate is within a given distance of a specified object, the transition takes place and the delegate starts using the next Seek state, thus moving toward the next object. Because the transition is tested at each frame, the target objects can be moving in any way you like, resulting in a seemingly dynamic animation.

To test a modifier parameter

This sample script checks the Angle parameter of a Bend modifier applied to a cylinder, and returns true if it is between 70 and -70, inclusive.

fn TestBend del t = (
if ($cylinder01.bend.angle <= 70 and $cylinder01.bend.angle >= -70 )
then 1
else 0
)

Note that the If statement in the second line uses parentheses around the text because two conditions are checked: whether the angle is less than or equal to 70, and whether the angle is greater than or equal to -70. Because of the "and" between them the script returns true only if both are true.

To test another delegate's behavior

You might want to determine in a transition script which behavior is currently influencing a certain delegate. Crowd provides a MAXScript-based method for doing this. You can even check whether a particular delegate is specified as a target within that behavior. An example would be a cocktail party scene in which Betty avoids Harry if Harry is seeking Sally. But if Harry is avoiding Sally, then Betty will seek Harry.

The following example script is taken from the sample file party.max, which you can find in cstudio\tutorials\tutorial_8 directory in your 3DS MAX path. The scene uses a more complex scenario than the example described in the previous paragraph. Following is an overview, but to fully understand the setup, you should examine the scene. Study, in particular, the behavior assignments and cognitive controllers, which use a total of eight different transition scripts.

Six delegates are confined in a "room" defined by four grids, using a Wall Repel behavior. Delegates 1, 2, 3, and 5 simply wander at random during the simulation. However, delegate 4 uses a cognitive controller (cc1) that tells it to start wandering, and then switch to one of three Avoid behaviors if members of one of three arbitrary pairs of delegates come within 50 units of each other. Each of the Avoid behaviors targets a different group of three delegates, two of which include delegate 2. Delegate 6 is assigned a second cognitive controller (cc2) that uses the following script to tell it to switch to an Avoid behavior if delegate 4 is avoiding delegate 2. The heart of the script is this line in function transfunc4:

(isDelAvoid = isDelegateAvoiding the_current_behavior.name "$Delegate04" "$Delegate02"

Load the file, press F11 to open the Listener window, and then solve. The Listener window displays a message whenever delegate 4 is found to be avoiding delegate 2.

You can use this script as is in your own simulations to check for whether one delegate is avoiding a second by substituting the delegates' names in the above line, and also substituting the names of your Avoid behaviors in the list in transfunc4, adding or deleting lines as necessary.

The example script illustrates a second important point: Cognitive controller transition scripts can contain multiple functions. Crowd first executes the function specified in the State Transition dialog > Transition Condition field, and that function calls one or more additional functions in the script, which, of course, can also call functions. In this case, transfunc4 calls the first function, isDelegateAvoiding, passing it three parameters.

Lastly, the script contains a special function, getBehaviorType, that compares an input behavior against a list of known behaviors, and on a match, returns the known behavior. In this case, transfunc4 runs through the list of behaviors currently influencing Delegate04, testing each with getBehaviorType, and if an Avoid behavior is in effect, proceeds to check whether Delegate02 is an obstacle of that Avoid behavior. Use of this function is more efficient and flexible than testing for specific behaviors, especially if your scene contains many behaviors of the same type, or you're constantly editing behavior settings. You can see the returned behaviors by removing the comment (double hyphen) from the beginning of the following line in transfunc4.

  -- format "Return Behavior: %\n" return_behavior

    

fn isDelegateAvoiding theCurrentBehavior theCogDelegate theAvoidingDelegate   = (

    

  the_return = 0  

  counter = 1

  for the_assignments in $Crowd01.assignments do 

  (

   if the_return == 1 then exit

   

   if the_assignments.delegate != undefined then 

   (

      if theCogDelegate == "$"+the_assignments.delegate.name then 

     (

        if the_assignments.cogcontrol != undefined then 

        (

          for the_cogcontrol_state in the_assignments.cogcontrol.states do

           (

             if the_return == 1 then exit

   

             for the_cogcontrol_state_behavior in the_cogcontrol_state.behaviors do 

              ( 

                 if the_return == 1 then exit

     

                 if the_cogcontrol_state_behavior.name == theCurrentBehavior then

                (

                  for the_obstacle in the_cogcontrol_state_behavior.obstacles do

                   (

                     if the_return == 1 then exit 

      

                     if "$"+the_obstacle.name == theAvoidingDelegate then 

                     (

                        the_return = 1

                     )

                   )

               )

            )

          )

        )

    )

   )

   counter = counter + 1 

 )

 the_return

)

    

fn getBehaviorType val = 

(  if not iskindof val MAXRefTarg do return undefined 

    

     theBehaviors = #( Speed_Vary_Behavior ,Orientation_Behavior ,Scripted_Behavior ,

      Wander_Behavior ,Surface_Arrive_Behavior ,Path_Follow_Behavior ,

                        Seek_Behavior ,Avoid_Behavior ,Wall_Seek_Behavior ,

                        Space_Warp_Behavior,Wall_Repel_Behavior,Surface_Follow_Behavior ,

                        Repel_Behavior )

      

               val_classID = val.classid

      

               for behav in theBehaviors do 

               ( local behav_classid = behav.classid 

                 if val_classID[1] == behav_classid[1] and val_classID[2] == behav_classid[2] do 

                (

                    return behav 

                )

            ) 

    undefined 

    

    

fn transFunc4 del t = (

    

another_the_return = 0 

counter = 1 

    

for the_current_behavior in $Delegate04.behaviors do 

(

  if another_the_return == 1 then exit 

  

  return_behavior = getBehaviorType the_current_behavior

  -- format "Return Behavior: %\n" return_behavior

  if return_behavior == Avoid_Behavior  then 

   (

      isDelAvoid =  isDelegateAvoiding the_current_behavior.name "$Delegate04" "$Delegate02" 

   

      if isDelAvoid == 1 then 

    (

          format "$Delegate04 found to be Avoiding $Delegate02\n"

          format "              Starting Transition in frame %:\n" t

          another_the_return = 1

      )

  )

  

  counter = counter + 1 

another_the_return

)

                  

Interface

Priority: Sets the transition's precedence.

When more than one transition tests true, the software uses the Priority setting to determine which transition occurs. It performs the transition with the lowest Priority setting. Thus, for example, a transition with a Priority setting of 0 takes precedence over one with Priority 1, and so on.

Duration: The number of frames the software takes to effect the transition between states.

Ease In: The rate at which the transition begins. Lower values cause a more abrupt transition, while higher values cause a more gradual transition. Default=0.5. Range=0 to 1.0.

Ease Out: The rate at which the transition ends. Lower values cause a more abrupt transition, while higher values cause a more gradual transition. Default=0.5. Range=0 to 1.0.

Note: The sum of the values for Ease In and Ease Out must be less than or equal to 1.0. The software won't let you set a value for either parameter that would cause the sum to exceed 1.0. To increase the value of one parameter when its value equals 1.0 minus the other parameter, decrease the other parameter first.

Transition Condition: The name of the MAXScript function that specifies when/how the transition is to occur. This name must also appear at the beginning of the main function in the script, after "fn". The script can contain additional functions that are called by the main function and each other.

Edit MAXScript: Opens an editor window for editing, saving, and loading the transition's MAXScript script.

 

 

 


Comments