Scripted_Behavior - superclass: ReferenceTarget; super-superclass:MAXWrapper - 4:0 - classID: #(716798510, 1784546452)
Introduction to the Crowd System
The crowd system works by assembling all of the force vectors and speeds for a delegate from its active force behaviors. Then, based upon the delegate’s motion parameters, these force vectors and speeds are averaged and integrated to create a velocity for the delegate. This velocity might then be modified if the delegate has an active constraint behavior or if it has an active default Avoidance behavior.
After the velocity is set, if there is an active orientation behavior, it is used to set the orientation of the delegate, otherwise the orientation is calculated from the default delegate parameters. Finally, the velocity is integrated and a new position is calculated.
The new position of the delegate is not set until all of the forces are calculated for all of the behaviors.
For a biped crowd, bipeds work off of goals and not forces when determining which direction they can go in. So, to create a force behavior that will work with a Biped, a goal position must be specified. No forces need to be integrated into velocities because the movement of the Biped is not based upon calculating velocities, but rather by selecting clips found in the motion flow graph.
Constructor
Scripted_Behavior ... ScriptedBehavior ...
Properties
<scripted_behavior>.name String Default: "Scripted"
<Scripted_Behavior>.scriptContextName String Default: "apply" Alias: Script_Context_Name
The script functions declared in the Edit MaxScript window are declared in a hidden MaxScript context. This textbox specifies the name of the context. Giving a unique name here avoids conflicts among different scripted behaviors.
<Scripted_Behavior>.type Integer Default: 0 Alias: Behavior_Type
One of the three behavior types: Force, Constraint, or Orientation.
Force: Behaviors of this type force the delegates to move in a particular direction, for example, Seek and Repel. Force behaviors work by returning a force vector in the direction that the behavior wants the delegate to go in, and in some cases the speed it must be traveling at and the goal at which it is trying to reach.
Constraint: Behaviors of this type restrict the position and velocity of a delegate, for example, SurfaceFollow. Constraint behaviors set the velocity and sometimes might even change the delegate’s position to meet the constraint. You might only have one active constraint behavior per delegate per frame.
Orientation: Behaviors of this type affect only the orientation of the delegates, for example, Orientation. These behaviors do not work with forces, but instead return an orientation that the delegate must be at, represented by a quaternion. Any active orientation behavior will override the default orientation of the delegate. The velocity determines the default orientation. Like a constraint behavior, you might only have one active orientation behavior per delegate per frame.
Though there are no avoid behavior types, a force or constraint behavior might be used to create an avoidance behavior.
We recommend to use the default Avoidance behavior because it is well integrated into the crowd solution pipeline.
<scripted_behavior>.script: string
This button "Edit MaxScript", in the Scripted Behavior Rollout opens a MAXScript editor window that can be used to enter a scripted behavior script. The editor window is similar to other MaxScript editor window, but is slightly customized for scripted behaviors.
The following elements in the File Menu work differently:
New: disabled as only one editor per scripted behavior can be open at any time.
Open: opens a file in the existing editor window. Any existing text will be lost.
Evaluate: evaluates the script and saves it into the behavior's paramblock.
Close: saves into the behavior's paramblock and closes the editor if no errors are found.
The scripted behavior script is implemented by defining a set of event handlers that get called by the crowd system when solving the simulation. The event handlers are automatically enclosed into a hidden MAXScript context. The name of the context is taken from the dialog’s Script Context Name text box or its equivalent . scriptContextName.
on execute do <expr>
Called whenever the script is evaluated. All initializing must be done here.
on setupDelegates <delegates> <behavior>do<expr>
<delegates>
an array of all the delegates after they are ordered participating in the simulation. All delegates listed in the Behavior Assignments pane of the Behavior and Team Assignment dialog are found in this list.
<behavior>
is the current behavior
Called before the simulation starts.
on display <behavior> <time>do<expr>
<behavior>
is the current behavior
<time>
is the current time of the simulation
Called every time the crowd system is redrawn. You can use the low level drawing functions from the gw struct Viewport Drawing Methods to have a custom display for the behaviors.
This handler gets called a number of times, so the system will slow down if implemented.
on behaviorStarted <delegate> <behavior> <time>do<expr>
<delegate>
is the delegate node the behavior is assigned to
<behavior>
is the current behavior
<time>
is the current time of the simulation
Called whenever a behavior becomes active for a particular delegate. This can occur at the beginning of the simulation for an assigned behavior or when a cognitive controller activates the behavior.
on initAtThisTime <behavior> <time>
This function is called for each behavior at the beginning of the frame.
on applyForce <delegate> <behavior> <time> <numSubSamples> <displayHelpers> <weight>do<expr>
If the behavior type is Force or Orientation, this handler is called every frame to move the delegate.
<delegate>
is the delegate node the behavior is assigned to
<behavior>
is the current behavior
<time>
is the current time of the simulation
<numSubSamples>
is the number of sub samples required per frame.
The <displayHelpers>
value is true/false depending on the <Crowd>.update
and <Crowd>.updateFrequency
as well as the current frame. If it is true, you must display any helper imagery you want using the display functions available from the delegates structure. For instance, most behaviors display their force if this is true, and pathfollow also displays its target. The delegates.lineDisplay
, .sphereDisplay
, .bboxDisplay
, and .textDisplay
are all functions which can be used to draw a graphic primitive for a particular delegate when the crowd simulation is being solved. See Viewport Drawing Methods for additional viewport drawing methods.
The graphic window functions gw.* described in Viewport Drawing Methods will not display correctly or at all while in Step Solve.
<weight>
is this behavior’s weight on the delegate
The event handler must return an array of the following type:
#(<int_flags>, <point3_force>, <point3_goal>, <float_speed>, <Speed_Weight_at_the_Goal>)
<int_flags>
sum of any of the following values:
0 - the return value is not used by the crowd system
1 - only force is affected
2 - only goal is affected
4 - only speed is affected
For example, a value of 5, (1+4), indicates that the force and speed are affected.
<point3_force>
is the force vector. It must be unit normalized and then multiplied by the delegate’s average speed. Modify this value, greater or less, to make the force stronger or weaker.
<point3_goal>
is the goal position in world space.
<float_speed>
is the net speed of the delegate. This value must be normalized to the average speed of the delegate. A value of 1.0 means go at the average speed.
<Speed_Weight_at_the_Goal>
will represent the speed that the delegate must be at when it reaches its goal. This value must be normalized by the average speed of the delegate so that a value of 1.0 equals its average speed.
<int_flags>
with a speed affected setting must ensure that a valid value is set for <float_speed>
and <Speed_Weight_at_the_Goal>
. Note that a goal does not need to be set for this to work. This is how the 'SpeedVary' behavior works with Biped. It does not explicitly set a goal, but still modifies the <Speed_Weight_at_the_Goal>
value.on constraint <delegate> <behavior> <time> <numSubSamples> <displayHelpers> <finalSet> <velocity> <speed> <pos>do<expr>
If the behavior type, <Scripted_Behavior>.type
is Constraint, this handler is called at least once every frame to constrain the delegate. The constraint behavior will override any other force behavior, the Avoidance Behavior, plus it will override any acceleration limits, speed limits, and others. So, it must be used with caution in a simulation.
The constraint behavior constrains the position that the delegate is moving towards by changing the current position that the delegate is already at, it's current velocity and current speed. These values are combined to get the next position, Next_position = Current_Position +Normalized(vel) * Speed. Changing the current position does not actually change where it is at, it just changes the position that is used to calculate its new position. This design allows the constraint to make the objects velocity change abruptly and keep its speed, thus conserving the energy of the delegate.
<delegate>
is the delegate node the behavior is assigned to
<behavior>
is the current behavior
<time>
is the current time of the simulation
<numSubSamples>
is the number of sub samples required per frame
The <displayHelpers>
value is true/false depending on the <Crowd>.update
and <Crowd>.updateFrequency
as well as the current frame. If it is true, you must display any helper imagery you want using the display functions available from the delegate. For instance, most behaviors display their force if this is true, and pathfollow also displays its target. The delegates.lineDisplay, .sphereDisplay, .bboxDisplay, and .textDisplay are all functions that can be used to draw a graphic primitive for a particular delegate when the crowd simulation is being solved. See Viewport Drawing Methods for additional viewport drawing methods.
<finalSet>
- whether or not this is the final time this behavior will be called during the current frame.
Currently, the constraint behavior's "on constraint" event handler is called twice per frame. The first call occurs before an existing Avoid_Behavior with the passed in parameter finalSet having a value of false . The second call occurs after the delegate’s limits and Avoid_Behavior are applied with the passed in parameter finalSet having a value of true. This evaluation order is done so that the delegate’s limits and the Avoid_Behavior can affect the changes that the constraint performs. The second call is made to make sure that the constraint is still being met.
One reason to check the state of finalSet is if internally something was cached and you did not want it to change. For example, the Surface_Follow constraint behavior keeps track of which triangle it is on and the barycentric coordinates of where it is at. The simulation will not change these values until finalSet is true.
<velocity>
is the current velocity of the delegate at this frame.
<speed>
is the current speed of the delegate at this frame.
<pos>
is the current position of the delegate at this frame.
After the last delegate's "on constraint" has executed for the last frame of the simulation, "on setupDelegates delegates behavior do" will be called with an empty array "#() ReferenceTarget:Scripted_Behavior". This is guaranteed and can be used by written constraint behaviors to clear out any internal caches.
The event handler must return an array of the following type:
#(<int_flags>, <point3_velocity>, <point3_pos>, <point3_goal>, <float_speed>)
<int_flags>
is the sum of any of the following values:
0 - the return value is not used by the crowd system
1 - the return value is used by the crowd system
<point3_velocity>
is the velocity.
<point3_pos>
is the modified current position that is used to calculate its new position. To meet a constraint this behavior is allowed to modify the current position of a delegate.
<point3_goal>
is the goal position in world space.
<float_speed>
is the net speed of the delegate. This value must be normalized to the average speed of the delegate.
on orient <delegate> <behavior> <time> <velocity> do <expr>
If the behavior type, <Scripted_Behavior>.type
is Orientation, this handler is called every frame. This handler is always called in conjunction with the applyForce handler.
<delegate>
is the delegate node the behavior is assigned to
<behavior >
is the current behavior
<time>
is the current time of the simulation
<velocity>
is the the current velocity of the delegate at this frame.
The event handler must return an array of the following type:
#(<int_flags>, quat_orientation)
<int_flags>
is the sum of any of the following values:
0 - the return value is not used by the crowd system
1 - the return value is used by the crowd system
<quat_orientation>
is the orientation of the delegate in quaternions.
The purpose of passing the crowd delegate and behavior to all of the event handlers is that you can call persisted global, saved with the scene, MAXScript functions that work for more than one crowd simulation.
EXAMPLE
The following is a pair of scripted behaviors called "FormationConstraint" and "FormationOrientation".
The "FormationOrientation" will constrain the orientation to a fixed location. In this case, it is based on the current delegate's orientation found at its first rotation keyframe. The entire scripted orientation behavior can be implemented with one event handler:
on orient delegate behavior time vel do ( #(1,delegate.rotation.keys[1].value as quat ) )
The "FormationConstraint" keeps a team of delegates in a given positional formation while maintaining the pace and direction of a designated leader named "FormationLeader". This is similar to a drum major and a marching band or like football blockers running in front of a running back who might dart in any direction. This person dictates how and where the formation will move. This "FormationLeader" is not using the scripted behavior.
This behavior will affect both the position and orientation of the delegate. The orientation is being calculated by the delegate’s velocity and the velocity is being set correctly.
on execute do( print" executed") on constraint delegate behavior time numsubsamples displayHelpers finalSet vel speed pos do ( leader_velocity = delegates.velocity $TheFormationLeader Normalized_Leader_Velocity= normalize (delegates.velocity $TheFormationLeader) magVel = speed*Normalized_Leader_Velocity temp_dis = (pos+leader_velocity)- magVel the_goal =temp_dis + magVel if displayHelpers== true then ( delegates.textDisplay delegate the_goal delegate.wirecolor delegate.name delegates.lineDisplay delegate pos (pos+leader_velocity) delegate.wirecolor true delegates.sphereDisplay delegate (pos+ (leader_velocity * $Crowd01.vectorScale)) 4 delegate.wirecolor ) #(1, Normalized_Leader_Velocity, temp_dis, the_goal, speed) )