These settings control how character studio 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 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 whether the result of the test is successful (true, or 1) or unsuccessful (false, or 0).
character studio executes scripts 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, or none.
The closing section contains a necessary 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.
Testing 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 )
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 )
Testing 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.
Testing 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".
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.
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 the script tests for two conditions: 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 the two tests, the script returns true only if both are true.
Testing 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 uses a more complex scenario than the example described in the previous paragraph. Following is an overview.
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 ( --format "Set it true here !\n" 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 )
Sets the transition's precedence.
When more than one transition tests true, character studio 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.
The rate at which the transition ends. Default=0.5. Range=0 to 1.0.
Lower values cause a more abrupt transition, while higher values cause a more gradual transition.