When designing a ProbeMap for a given (subclass of) SwarmObject, inclusion of instance variables or messages defined in the super class might be desirable. The normal ProbeMap design code might look like (this code was taken from the tutorial app called "hello-world"):
probeMap = [CustomProbeMap createBegin: [self getZone]]; [probeMap setProbedClass: [person class]]; probeMap = [probeMap createEnd]; [probeMap addProbe: [probeLibrary getProbeForVariable: "room" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "party" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "name" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "stillhere" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "listOfFriends" inClass: [person class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "myColor" inClass: [person class]]]; [probeLibrary setProbeMap: probeMap For: [person class]]; [probeDisplayManager createProbeDisplayFor: person];
where room, party, name, stillhere,
listOfFriends,
and myColor
are
instance variables declared in the interface to the
Person subclass. And
Person is a subclass of
Agent2d, which is a subclass of
SwarmObject.
Now let's say that there are two variables declared in
Agent2d that you want to put into this
custom probe in addition to the ones you've picked out of
Person. Call them x
and y
. The way to add them to the
probeMap
is to add the following two lines
of code to the above.
[probeMap addProbe: [probeLibrary getProbeForVariable: "x" inClass: [Agent2d class]]]; [probeMap addProbe: [probeLibrary getProbeForVariable: "y" inClass: [Agent2d class]]];
And that's it! The two superclass-declared variables, which are, in fact, instance variables of the instance of the subclass, are now included in the probe.
In addition, a convenience message has been added to the CustomProbeMap interface to compress the above rather cluttered mechanism into one message. This convenience message can be used in the usual case where a ProbeMap will consist of variables and messages from the same class. For example, the first part of the custom probe creation above can be shortened to:
probeMap = [CustomProbeMap create: [self getZone] forClass: [person class] withIdentifiers: "room", "party", "name", "stillhere", "listOfFriends", "myColor", NULL];
And if the user wanted messages in the probe as well, it could be extended to:
probeMap = [CustomProbeMap create: [self getZone] forClass: [person class] withIdentifiers: "room", "party", "name", "stillhere", "listOfFriends", "myColor", ":", "setWorld:Room:Party:", "setPerson:Topic_array:ShowSpeech:", NULL];
At present, this message doesn't search the superclasses for the message names listed here. But, that will soon be rectified.
It is completely reasonable to assume that explicit control can be had over all the activities in a simulation. However, at present, this control is limited because the context in which an activity runs determines how it behaves. To understand how an ActivityControl is to be used, we will have to explore the behavior of activities in context. (For a more complete explanation of the behavior of activities, see the activity library documentation.)
There are two ways to get an activity started, one can
activate the activity in nil
or in some
other activity. So called "top-level" activities are
activated in nil
and are intended to be
independent of the sophisticated scheduling activity that
dictates the execution of actions in any other context in the
simulation. I.e. the only activities that should be activated
in nil
are those sets of events that are
expected to preserve the same behavior no matter what goes on
in any other part of the simulation.
The other type of activity, those activated in some other activity, is intended to be an integral part of its owner activity. However, this doesn't mean that it must depend on the outcome of actions happening in the owner activity. In fact, an ActionPlan can be designated as containing actions that are capable of being processed in parallel, via code like the following:
[anActionPlan setDefaultOrder: Concurrent];
But these activities are still intended to be meshed with their owner activities. In other words, they are part and parcel of the same model or simulation.
Now, the operational effect of activating an activity in
nil
is that it will not be meshed with the
rest of the Swarm activity structure. This gives the user (or
process) complete control over the execution of that activity.
A run
on that activity will run either to
completion or until a stop flag is set by a sequence of events
purely internal to that activity. Or, one can stop it from
the outside with a message from something like an
ActivityControl.
What all this means is that, while one can attach an
ActivityControl to any
activity, only the "top-level" activities (those having been
activated in nil
) are going to respond well
to it. Any sub-activity will respond half-heartedly, if at
all. For example, in the Mousetrap demo
distributed with Swarm, an
ActivityControl has been placed on both
the ObserverSwarm and the
ModelSwarm activities. Now, if one sends
a run
message to the
ActivityControl that is attached to the
observerSwarm
's activity, the entire model
continues to run to completion, unless the user sends a
stop
message. However, if the sim is
stopped at some point, a run
message to the
modelSwarm
's activity will have no effect
at all. (Note: If you do this via the
activity controllers, you see the
currentTime
variable get updated; but, the
actual run
message to the activity, itself,
has no effect.)
So, the rule of thumb, for the present, is to attach ActivityControl objects only to "top-level" activities, like the ObserverSwarm.