The objectbase library contains the most basic objects users need to design their agents and swarms. It also serves, at present, as a repository for the probe machinery, which is provided for every SwarmObject. The way the classes in this library are to be used is varied. But, basically, it is provided so that the user will have something to subclass from for her own objects and Swarms.
The best way to explain how the library should be used is to walk through an example. So, using Heatbugs, we'll walk through the ways objectbase is used and discuss them. Since more documentation is usually better than less, I'm going to explain things at a low level so that those not familiar with Objective C will understand the discussion. If you already are familiar with Objective C, then you should skip this part.
First off, the basic elements of the Heatbugs simulation are the heatbugs, the model swarm (which bundles the heatbugs), and the observer swarm (which bundles the displays of the probes poking into the model swarm and the heatbugs). The interface files for each show what must be imported and the declaration syntax needed to subclass from SwarmObject.
We'll use Heatbug.h
for our discussion
here. The first part of the file shows the C-preprocessor
imports needed:
#import objectbase/SwarmObject.h #import space.h #import "HeatSpace.h" #import tkobjc/Raster.h
The #import objectbase/SwarmObject.h;
is included in order to subclass from
SwarmObject. However, to provide
backwards compatibility, we've placed this import in the
library interface file objectbase.h
as
well, which means one could subclass from
SwarmObject by simply importing the
objectbase.h
file. This is discouraged
in order to make the library interfaces as standard as
possible.
The next objectbase relevant piece of code in this file is:
@interface Heatbug: SwarmObject { double unhappiness; int x, y; HeatValue idealTemperature; HeatValue outputHeat; float randomMoveProbability; Grid2d * world; int worldXSize, worldYSize; HeatSpace * heat; Color bugColor; }
The @interface
keyword indicates that
you are beginning the definition of the part of an object (a
Heatbug in this case) that will be
visible to other objects. The Heatbug:
SwarmObject
indicates that you are calling this
object Heatbug and it is a subclass of
SwarmObject. What follows between the
curly braces ({}) are the instance variables defined for the
Heatbug class above and
beyond those inherited from the
SwarmObject class.
Inside this "agent," we have defined several parameters associated with either the agent, itself, or the space in which it sits. Any data that will need to be present throughout all the behavior and lifetime of the agent should be declared here. Also, anything declared here will be accessible to the probe machinery, and so will be capable of being manipulated and viewed from outside the agent.
Next come the message prototypes to which this agent will
respond. And it is worth noting again that these are
in addition to those declared in the
SwarmObject superclass. So, not only
will other objects be able to send messages to this agent that
are declared here, but other objects will be able to send all
the messages declared in the
objectbase/SwarmObject.h
imported
previously. The messages prototyped here will dictate what
the compiler thinks this object can respond to. Hence, if any
part of any of these prototypes differs from the corresponding
function definition in the Heatbug.m
file,
then the compiler will say something like Object:
aHeatbug does not respond to xyz
, where "xyz" is the
name of the message that is being sent to the
Heatbug
. A script is provided with the
Swarm distribution that fixes header file prototypes to match
the message declarations in the corresponding ".m" file. This
script should be in the $SWARMHOME/bin
directory and is called m2h
.
One more thing to notice about these prototypes is that
some of them are duplicates of what appears in the
objectbase/SwarmObject.h
file. This means
that when the message is called on a
Heatbug object, it will execute the
method defined here and not the one in the
SwarmObject class. In the
objectbase library, the following
messages are intended to be overridden, as necessry:
create:, createBegin:, createEnd, customizeBegin:,
customizeEnd, customizeCopy:, describe:, and
getInstanceName.
Each of these messages do specific
things that may change from subclass to subclass of
SwarmObject. In this case, however,
we're only overriding createEnd
. The
differences between we implement it in
Heatbugs and the default is not that
significant. But, it should be pointed out that when
overriding certain messages, like
createBegin:
and
createEnd
, the new method should call the
superclass' version of the message, as well. This is done
using the default pointer to the superclass, designated
super. The syntax in the
Heatbugs case is:
[super createEnd];
The reasons for doing this are related to the object phase protocols used by defobj. If you would like more info on that, see the .
Finally, the @end
keyword signifies the
end of the interface definition. GNU Objective C allows one
to leave this off; but, it is not good practice.
And that's it. Of course, there're a few tricky aspects to using the objectbase library that weren't mentioned here. Some of them will be mentioned in the Advanced Usage Notes and the Implementation Notes; but, the best way to learn is to examine the way the demo applications do it and try to make some changes yourself.
Subclassing from the Swarm class works very similar to subclassing from SwarmObject.
The ActivityControl object provides much more finely grained control over the execution of an interactive simulation. It addresses both the problems of not being able to stop the simulation at any given point in any given activity and provides an initial step towards a Swarm debugger.
An activity controller can be attached to
any activity that is created in a Swarm
simulation, including those that are created for use only by
the Swarm kernel. The controller then provides the basic
activity manipulation messages on that activity, which are:
run, stop, next, step, stepUntil,
and
terminate
.
The presence of the ActivityControl
object might cause some confusion about what role the
ControlPanel should play in the
controlled execution of the various schedules. The
ControlPanel should still be used for the
top-level control of any simulation that is running in a
context where random interference is expected
(like under a GUISwarm where the user may click a button at
any time). The reason this is true is because the
ControlPanel sends pseudo-interrupts to
the infinite loop we use to perpetuate execution of the top
level Swarm (which can only be seen in the form of the
go
message on a
GUISwarm at present). This type
of control may change in the future! But, for now, it
is how we monitor the control state of the simulation.
Now, having said that, the
ControlPanel should no longer be used to
run the simulation. It should only be used to instantiate the
control context and quit the entire simulation. That means
that sometime in the future, the Go
and the
Stop
buttons will be removed from the
ControlPanel display. They have been
left in for backwards compatibility so that applications that
do not use the new ActivityControl will
retain their (albeit handicapped) controllability. Also, the
current Time Step
button will be renamed to
Start
to be consistent with it's new
purpose.
In order to use the new control mechanism, you must place code like the following in the top-level Swarm. (This code was taken from a modified mousetrap demo app.)
observerActCont = [ActivityControl createBegin: [self getZone]]; observerActCont = [observerActCont createEnd]; [observerActCont attachToActivity: [self getSwarmActivity]]; [probeDisplayManager createProbeDisplayFor: observerActCont];
This creates an ActivityControl and
attaches it to the top-level activity (in this case an
observerSwarm
). It also creates a display
for the controller. (The probe map for the
ActivityControl class is designed within
the ActivityControl, itself. This is
done because all of these objects are expected to look the
same to any outside object.) With this activity controller,
you will then be able to run, stop, next, step,
stepUntil,
and terminate
that
activity.
There are some tricky aspects to successfully using an ActivityControl object that the Advanced Usage Notes will cover.