Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
SimBionic
version 2.1
650-931-2700
Fax:
650-931-2701
Web:
www.simbionic.com
Table of Contents
Introduction........................................................................................................................................................................ 1
What is SimBionic? ........................................................................................................................................................ 1
Why is SimBionic needed?............................................................................................................................................. 1
SimBionics features....................................................................................................................................................... 1
What's New in Version 2.1?............................................................................................................................................ 2
Getting Started .................................................................................................................................................................. 3
Installing SimBionic ........................................................................................................................................................ 3
Installing SimBionic from a CD.................................................................................................................................... 3
Installing SimBionic from a downloaded file ................................................................................................................ 3
SimBionics system requirements ............................................................................................................................... 3
Understanding SimBionic ............................................................................................................................................... 3
Starting a new project..................................................................................................................................................... 4
Opening an existing project ............................................................................................................................................ 5
Touring the editor ........................................................................................................................................................... 5
The menu bar ............................................................................................................................................................. 6
The toolbars................................................................................................................................................................ 7
The status bar............................................................................................................................................................. 7
The Project windows Catalog..................................................................................................................................... 7
The Project windows Descriptors pane ...................................................................................................................... 8
The Canvas ................................................................................................................................................................ 9
The Output window................................................................................................................................................... 10
Saving your work.......................................................................................................................................................... 11
Printing the Canvas...................................................................................................................................................... 12
Exiting SimBionic ......................................................................................................................................................... 13
Updating SimBionic...................................................................................................................................................... 13
Working with the Catalog ................................................................................................................................................. 15
What is the Catalog? .................................................................................................................................................... 15
Working with Actions and Predicates............................................................................................................................ 16
Understanding the core actions ................................................................................................................................ 16
Understanding the core predicates ........................................................................................................................... 18
Declaring an action ................................................................................................................................................... 20
Declaring a predicate................................................................................................................................................ 22
Working with AP Modules ......................................................................................................................................... 25
Importing AP Modules............................................................................................................................................... 25
Working with Behaviors................................................................................................................................................ 26
Declaring a behavior................................................................................................................................................. 26
Setting a behavior's execution mode......................................................................................................................... 29
Setting a behavior to run uninterrupted ..................................................................................................................... 29
Understanding the Main behavior ............................................................................................................................. 30
Importing a behavior (BTN)....................................................................................................................................... 30
Managing Catalog Items .............................................................................................................................................. 31
Renaming a Catalog item ......................................................................................................................................... 31
Organizing Catalog items.......................................................................................................................................... 31
Deleting a Catalog item............................................................................................................................................. 32
Editing a parameter in the Catalog............................................................................................................................ 32
Working with the Canvas ................................................................................................................................................. 33
What is the Canvas? .................................................................................................................................................... 33
Table of Contents
Navigating behaviors.................................................................................................................................................... 34
Quick-Zoom ................................................................................................................................................................. 34
Introducing the Canvas Elements................................................................................................................................. 34
Creating and editing actions on the Canvas .............................................................................................................. 34
Creating and editing invoked behaviors .................................................................................................................... 37
Creating and editing compound actions .................................................................................................................... 40
Setting a rectangle as initial ...................................................................................................................................... 43
Setting an action as final........................................................................................................................................... 43
Creating and editing conditions................................................................................................................................. 44
Creating a connector ................................................................................................................................................ 48
Changing a connectors priority................................................................................................................................. 49
Managing Canvas Elements......................................................................................................................................... 50
Copying a Canvas element....................................................................................................................................... 50
Moving a Canvas element ........................................................................................................................................ 51
Deleting a Canvas element....................................................................................................................................... 52
Searching the Canvas............................................................................................................................................... 52
Replacing text in behaviors ....................................................................................................................................... 54
Undoing your most recent change(s) ........................................................................................................................ 56
Documenting your Behaviors ....................................................................................................................................... 56
Commenting on a Canvas element ........................................................................................................................... 56
Placing a reminder on a Canvas element.................................................................................................................. 57
Changing the label for a Canvas element ................................................................................................................. 57
Adding text to the Canvas......................................................................................................................................... 58
Working with Variables .................................................................................................................................................... 59
Understanding variables............................................................................................................................................... 59
Local variables.......................................................................................................................................................... 59
Global variables........................................................................................................................................................ 59
Choosing a data type ................................................................................................................................................... 60
Integer ...................................................................................................................................................................... 60
Float ......................................................................................................................................................................... 60
String........................................................................................................................................................................ 60
Vector ....................................................................................................................................................................... 61
Boolean .................................................................................................................................................................... 61
Entity ........................................................................................................................................................................ 61
Array......................................................................................................................................................................... 61
Table ........................................................................................................................................................................ 62
Data.......................................................................................................................................................................... 62
Any ........................................................................................................................................................................... 62
Invalid ....................................................................................................................................................................... 62
Enumerated Types ................................................................................................................................................... 62
Classes..................................................................................................................................................................... 62
Checking for invalid values........................................................................................................................................... 63
Creating and Editing Variables ..................................................................................................................................... 63
Creating and editing local variables .......................................................................................................................... 63
Creating and editing global variables ........................................................................................................................ 65
Creating and editing constants.................................................................................................................................. 67
Understanding Expressions.......................................................................................................................................... 69
Understanding expressions....................................................................................................................................... 69
Using operators in expressions................................................................................................................................. 70
ii
Table of Contents
iii
Table of Contents
iv
Table of Contents
Introduction
What is SimBionic?
SimBionic is a powerful, flexible, and highly intuitive software program that lets you create the artificial intelligence for
virtually any simulation or game you wish to develop.
Artificial Intelligence, or AI, is a critical component of all simulations and games. AI establishes the psychology and
physics of your virtual world, setting up numerous rules for how people and things within that world behave. For
example, its the AI portion of a simulation that determines what standard procedures a battleship follows when an
unidentified plane starts flying towards it; or what tactics a terrorist might use to smuggle a weapon past security; or
how a dragon reacts when its lair is invaded by elves.
In addition, AI typically furnishes users with guidelines on how they should behave. For example, its your games AI
that will establish whether your players are punished or rewarded under a particular scenario for negotiating with an
enemy, firing a missile, stealing a magic ring, etc.
AI therefore provides your virtual world with depth, substance and a responsiveness that mimics reality. And by
rewarding users for certain actions and punishing them for others, AI imbues that world with a sense of meaning and
values.
In other words, AI offers your audience the opportunity to make visceral real-time decisions within scenarios you
design and then experience the consequences of those decisionsand to also relive any given scenario by making
different decisions, until the scenario is mastered.
SimBionic is the ideal tool for creating such AI-based worlds. SimBionic consists of an exceptionally intuitive visual
editor that makes composing and editing AI code easy, even for non-programmers. SimBionic also provides a
sophisticated run-time engine that (working in conjunction with your simulation or game) brings your AI code to life.
Why is SimBionic needed?
Most complex programs today are created via standardized high-level tools that developers can become experts in
reusing from project to project. Among the few holdouts to this trend have been the AI programmers who must code
the program logic and complex behaviors that form the backbone of successful military simulations, commercial
simulations, and commercial games. Until now, these developers have traditionally created their authoring tools from
scratch for each new project they take on. However, this tool-building consumes an enormous amount of time and
energy that could otherwise be devoted to more creative activitiessuch as enhancing the simulation or game itself.
In addition, such on-the-fly authoring tools are more likely to generate subtle bugs, since little time is available for
polishing and testing them. And such tools often create communication and maintenance problems, as no one other
than the AI person who developed them is likely to fully understand them.
The reason usually given for this inefficient approachwhich frequently leads AI developers to spend more than half
of their programming time building special-purpose toolsis that the logic of each simulation or game is unique, and
so it isnt possible to create an AI authoring tool that can be applied to a broad range of such programs. And, until
recently, its true that no such general-purpose tool existed.
Over the past decade, though, the academic AI community has made a number of breakthroughs in artificial
intelligence theory that are directly applicable to the behaviors found in virtually all simulations and games. As a result,
Stottler Henke (an AI software consulting company) decided to take advantage of current AI research and create a
powerful yet intuitive program that simulation and games developers could adopt as a standard AI authoring tool. That
program is SimBionic.
SimBionics features
SimBionic is composed of two basic componentsa visual editor for authoring AI programs, and a state-of-the-art runtime engine for executing those programs.
SimBionics editing system makes it a breeze for you to specify all of your virtual worlds entitiesthat is, all the beings
and objects that perform actions in that world (e.g., enemy soldiers, guided missiles, hungry dinosaurs, enchanted
swords).
The editor also makes it simple for you to articulate each entitys behavior via four programming constructs: actions,
which define all the different actions an entity can perform; other behaviors youve previously created (SimBionic lets
any behavior invoke any other behavior, allowing you to build up a library of behaviors and efficiently reuse your work);
conditions, which set the conditions under which each action and behavior will happen; and connectors, which control
the order in which conditions are evaluated, and actions and behaviors take place. These four constructs allow you to
create AI behavior that mimics the behavior we experience in the real world.
SimBionic lets you create your programming code with exceptional ease by drawing it as flow-chart diagrams on the
right side of your editing window. Specifically, actions are represented as rectangles, behaviors as boldfaced
rectangles, conditions as ovals, and connectors as lines. You can attach as many variable assignments, complex
expressions, and explanatory comments as you like to any of these elements.
This highly intuitive visual approach allows you to see your programs logic at a glance, and quickly spot potential bugs
or other difficulties. The visuals also make it a snap for you to show and discuss your work with other members of your
development teamincluding typically non-technical members such as conceptual designers and illustrators. In fact,
SimBionics editor is so easy to learn that it can even be used by those without heavy-duty AI or programming
experience.
When youre ready to try out your work, you can compile your code with a mouse click. You can then test it using
SimBionics interactive debugger, which will load SimBionics run-time engine and execute your code step by step,
helping you to uncover and fix any subtle problems.
When your code is in great shape, another few mouse clicks will generate a header file that provides information for
hooking your SimBionic program to your simulations or games main program (which will typically be written in C++ or
Java, and include such key interface elements as graphics and sound). Youor a programmer on your development
teamcan then use a set of commands designed for SimBionics run-time engine to precisely control when the engine
starts; how it allocates resources; when and how it executes each step, or clock tick, of your SimBionic program for
each entity; and when it terminates and is unloaded from memory. SimBionic directly supports both C++ and Java
code by including both C++ and Java versions of its run-time engine.
Other notable features of SimBionics sophisticated engine, which is the brains driving the behaviors of the entities
youve created, include:
Impressive speed, helped by a load-balancing scheduling system for controlling large numbers of entities
without sapping the CPU.
Efficient use of memory, thanks to both a small footprint and the engines own memory management
system.
Built-in commands supporting communication between entities via both message queues (that allow
entities to join groups and exchange team messages) and virtual blackboards (that allow any entity to post
messages that can be read by any other entity).
Stack-based hierarchical execution, which lets any behavior invoke any other behavior, which in turn can
invoke any other behavior, ad infinitum, allowing you to construct sophisticated behaviors from simpler ones
and efficiently reuse your work.
Powerful API methods that let you precisely control when each entity is created, how often it executes,
which behaviors it executes, and how extensively its activities are recorded.
A thin API for easy integration with virtually any simulation or game.
Support for polymorphism, which lets you create subtle variations of behaviors for your entities (e.g.,
instead of just having a Sniper behavior, you can define behaviors for Rested Sniper, Sleepy Sniper, etc.).
SimBionics flexible editor and engine can help you create the AI for a wide variety of programs, ranging from visceral
interactive games (like Quake or Half-Life), to sophisticated strategy games (like Age of Empires or Civilization), to
military training simulations (e.g., fighting enemy tanks, tracking down terrorists), to military analysis simulations (e.g.,
analyzing what effect bombing a particular power station will have over a five-day period). To help demonstrate
SimBionics range, sample versions of Pac-Man (a simple arcade game) and Half-Life: Counter-Strike (a simulation
that pits players against terrorists) that weve created using SimBionic are included on your installation CD.
What's New in Version 2.1?
Version 2.1 of SimBionic introduces a number of powerful new features, including:
Enumerated types
Compound actions
This release also includes a wide range of other new features and enhancements. For details, see the file "version
history.txt" included in your installation.
Getting Started
Installing SimBionic
Before you can use SimBionic, the program must be installed. How you install SimBionic depends on whether you
downloaded it from Stottler Henkes Web site or received it on a CD. The first two sections of this topic cover both
installation methods.
If you encounter any problems using SimBionic, it may be because your PC doesnt meet one of the programs system
requirements. The third section of this topic provides a detailed list of these requirements.
Installing SimBionic from a CD
If you have SimBionic on a CD, insert the disc into your CD drive. After a few moments, you should see a dialog box
that provides you with installation instructions. Continue to follow the instructions that appear on your screen to
complete the installation.
Note: If the initial dialog box doesnt automatically appear, use Windows Explorer to view your CDs root folder and
locate a file named setup.exe. After you do so, double-click setup.exe to begin the installation process.
Installing SimBionic from a downloaded file
If you downloaded SimBionic from its Web site (www.simbionic.com), you should have saved a file named setup.exe
(or something similar) to your hard drive. The downloaded file is an archive, which means that it contains all the
components of the SimBionic program in compressed form. After you activate it, the file will automatically decompress
its components and copy them to the appropriate locations on your hard disk.
To activate the archive file, simply double-click it. A dialog box appears with initial installation instructions. Continue to
follow the instructions that appear on your screen to complete the installation.
SimBionics system requirements
If you have any difficulties making SimBionic run, it may be because your PC doesnt meet one of the programs
system requirements. Heres a list of the minimum features your computer system needs for SimBionic to operate
properly:
Operating system: Windows 98, Windows 98 Second Edition, Windows ME, Windows NT Workstation 4.0
with Service Pack 6 or later, Windows 2000 Professional, or Windows XP or later.
Hard disk space: 20MB (50MB of free space required for the installation process).
If your computer system meets all of the above requirements but youre still encountering some problem, please see
the Getting technical support topic.
After youve installed SimBionic, youre ready to start learning about it and using it. To begin, see the Understanding
SimBionic topic.
Understanding SimBionic
As explained in the What is SimBionic? topic, this artificial intelligence programming tool consists of two basic
components:
A run-time engine that executes the code you generate from the editor, and that you can hook into your
simulation or game (typically via C++ or Java code).
The relationship between these two components is illustrated by this diagram (which refers to the editor as Authoring
Tool):
Get an overview of the editor by reading the Starting a new project and Touring the editor topics.
Create the entity names and descriptors to which youll be assigning behaviors. For more information, see
the series of topics starting with Understanding descriptors.
Declare the variables and constants youll be using in your project. For more information, see the series of
topics starting with Understanding variables.
Declare the actions, predicates, and behaviors youll be using in your project. For more information, see the
series of topics starting with What is the Catalog?.
Visually create behaviors by drawing actions and invoked behaviors (represented as rectangles) and
conditions (represented as ovals) that you set to interact in both simple and complex combinations via
connectors (represented as arrow-shaped lines). For more information, see the series of topics starting with
What is the Canvas?.
Learn more about creating SimBionic programs by reading the series of topics starting with Exploring the
sample "Hello World" program.
Convert your visual program into code that will be understood by SimBionics run-time engine. For more
information, see the Compiling your project and Debugging your project topics.
Execute your program via the run-time engine. For more information, see the series of topics starting with
Understanding the C++ run-time engine or Understanding the Java run-time engine.
Tip: For a summary of SimBionic editor and run-time engine commands, see the SimBionic Editor Cheat Sheet and
SimBionic C++ Engine Cheat Sheet topics.
Starting a new project
A SimBionic project is created using SimBionics editor, which allows you to design behaviors using visual elements
such as rectangles (representing actions and invoked behaviors), ovals (representing conditions), and lines
(representing connectors). When youre ready to try out your behaviors, the editor lets you compile your work into
code that can be executed by SimBionics run-time engine.
You can launch SimBionic in any of the following ways:
Click the Start button on your Windows taskbar (in the bottom-left of your screen); click Programs from the
menu that pops up; click SimBionic from the list of installed programs that appears; and click SimBionic
Editor from the list of options that appears.
If you allowed a SimBionic icon to be created on your desktop, double-click the icon.
Open the SimBionic folder and double-click the program file SimBionic.exe.
After the SimBionic editor appears, you can use it to build your new project from scratch. This is the best option if you
and your development team have never worked with SimBionic before. To learn more about this powerful and flexible
visual programming tool, proceed to the Touring the editor topic.
Alternatively, if your development team has some experience with SimBionic, you may find it more efficient to make a
copy of a project your teams created previously and then use it as a foundation for building your new one. In this
case, read the next topic, Opening an existing project.
Getting Started
Tip: If you want to start a new project after youve already launched the editor (e.g., because youre done working for
the moment on your current project), first save your current project following the instructions in the Saving your work
topic; and then press Ctrl+N, or click the File menu and select the New option. Your current project is replaced in the
editor window by a new, blank project.
Opening an existing project
After a SimBionic project is saved to disk (as described in the Saving your work topic), you can reopen it at any time
by using SimBionic to specify the projects name and location.
Youll typically reopen a project on which youve previously been working, so that you can pick up where you left off.
Alternatively, though, you can open a SimBionic project that was created by someone else, either to learn from it, or to
use as a foundation for building your own new project (which can be easier than creating a project from scratch).
The names of the last four projects you opened in SimBionic are displayed in the lower portion of the File menu.
Therefore, if youve recently worked with the project you now want to reopen, simply click the File menu and then click
the name of the project from the menus list. After a few moments, SimBionic opens the project.
Alternatively, if the project you want isnt listed on the File menu, locate and open the project by following these steps:
1.
If the SimBionic editor isnt already running, launch it by clicking the Start button and selecting
Programs->SimBionic->SimBionic.
Alternatively, double-click the SimBionic icon from your desktop or from the SimBionic folder.
Click the File menu and select the Open option.
An Open dialog box like this appears:.
2.
3.
Click Open.
The project stored in the folder and under the name you specified appears in the SimBionic editor window.
You can now work with the project.
Tip: If you want to make changes to a project without affecting the original filefor example, if youve opened
someone elses project to use as a foundation for your own new projectsave the current project under a different
name and/or folder location immediately after opening it. For instructions on how to save a project, see the Saving
your work topic.
To learn more about the SimBionic editor, proceed to the next topic, Touring the editor.
Touring the editor
When you launch the SimBionic editor (as described in the Starting a new project topic), you see a window like this:
The window is made up of several components, including a menu bar and two rows of toolbars at its top; a status bar
at its bottom; and a Project window, Canvas, and Output window in its middle. The following sections describe each of
these components.
The menu bar
At the top of SimBionics editor window is a menu bar that let you adjust aspects of the editor and/or affect program
elements on the Canvas (the large work area on the right side of the window), as shown here:
File: Lets you start a new project; open an existing project; save your work; import action and predicate
declarations from an existing project; create a C++ header file or Java header file; create skeleton code for
your SimBionic interface in C++ or Java; create HTML documentation for your project; export your project in
XML format; print the contents of the Canvas; preview your printout; and exit the editor.
Edit: Lets you undo or redo your most recent changes on the Canvas; move Canvas elements; copy
Canvas elements; delete Canvas elements; select all the elements on the Canvas so you can copy, move,
or delete them as a group; search for a Canvas element or text sequence; and replace a text sequence.
View: Lets you hide or display the toolbars; hide or display the status bar; hide or display the Project and
Output windows; hide or display the Breakpoint List; resize the Canvas; zoom out on the Canvas; display
the previous or next behavior on the Canvas; and display the previous or next compile error in the Build
pane.
Build: Lets you compile your project and debug your project.
Help: Lets you launch SimBionic Help; view tips on using SimBionic effectively; and check the version of
SimBionic you're using.
You can view any menus options by clicking its name on the menu bar. You can then activate any listed option by
selecting (i.e., clicking) it.
Getting Started
For more information about a particular menu option, click its description above, which will display a topic detailing
how to use the option.
The toolbars
Below the editors menu bar are two rows of toolbars that display information about program elements and house
buttons you can click to quickly access program commands, as shown here:
Standard: Provides buttons to start a new project, open an existing project, and save your work (as shortcut
alternatives to the File menu options); move Canvas elements, copy Canvas elements, and undo or redo
your most recent changes on the Canvas (as shortcut alternatives to the Edit menu options); comment on a
Canvas element; place a reminder on a Canvas element; hide or display the Project and Output windows
(described below); and print the contents of the Canvas.
Navigate: Provides buttons to display the previous or next behavior on the Canvas (as shortcut alternatives
to the View menu options).
Connector: Provides buttons to create and adjust a connector, or set a connector to interrupt a behavior.
Also provides a button to add text annotations to the Canvas.
Initial/Final: Provides buttons to designate a behaviors initial rectangle and final actions.
Variables: Provides buttons to display local variables, global variables, constants, and parameters for
behaviors.
Expression: Displays, and provides a button for editing, the expression of the selected Canvas element.
Bindings: Displays, and provides a button for editing, the attached bindings of the selected Canvas
element.
For more information about a particular toolbar button, click the buttons description above.
Tip: If you want to create slightly more room within the editor window, you can hide all the toolbars on a row by clicking
the View menu, selecting the Toolbars option, and then selecting the name of a toolbar (which turns the checkmark to
the options left off). You can repeat this step to hide all the toolbars on the same row, in which case the row
disappears. To bring back any hidden toolbar, simply repeat the previous step; selecting the toolbars option for the
second time turns the checkmark to its left back on and makes the toolbar visible again.
The status bar
At the bottom of the editor window is a status bar like this:
The status bar displays messages about SimBionics status (e.g., Ready, Compiling). It also displays a brief definition
of any menu option or toolbar button you point to with your mouse.
Tip: If you want to create slightly more room within the editor window, you can hide the status bar by clicking the View
menu and selecting the Status Bar option (which turns the checkmark to its left off). To bring back the status bar,
simply repeat this step; selecting the Status Bar option again turns the checkmark to its left on and makes the status
bar visible again.
The Project windows Catalog
The sub-window that runs across along the left side of the SimBionic editor is called the Project window. It houses two
panes, called the Catalog and the Descriptors pane, that you use to set up all the actions, predicates, behaviors,
global variables, constants, and descriptors that appear in your project. Only one of the panes can be displayed at a
time; to switch between the panes, simply click the Catalog or Descriptors tab at the bottom of the Project window.
When the Catalog is selected, the Project window looks something like this:
The Catalog stores the declarations for every action, predicate, behavior, global variable, and constant used in your
project. You must declare these program constructs before you can successfully compile any SimBionic project, as the
declarations ensure SimBionic can identify each construct you refer to on the Canvas and associate it with the
appropriate parameters and/or data type.
In addition, the Catalog allows you to click any declared program construct and, while holding down your mouse
button, drag a copy of the construct to the Canvas, which makes creating behaviors relatively quick and easy. The
pane therefore effectively provides you with a catalog of program constructs you can select among to build any
behavior.
If you need to refresh your memory about the meaning of a particular item in the Catalog, simply hover your mouse
cursor over its name. After a moment, a tooltip with the description of that item will appear.
For more information, see the What is the Catalog? topic.
The Project windows Descriptors pane
When the Descriptors pane is selected, the Project window looks something like this:
Getting Started
In SimBionic, a descriptor is an identifier or attribute that you can associate with behaviors to define polymorphisms. A
descriptor can be any term you want to use to describe the state of an entityfor example, attributes such as happy,
sad, healthy, armed, or hungry. A descriptor can also refer to the fundamental characteristics of an entity, such as its
role on a team (e.g., leader, scout, medic) or its nationality (e.g., Russian, Australian, American). Descriptors therefore
help you execute a variety of behaviors under different conditions to add nuance and complexity to your virtual worlds.
For more information, see the Understanding descriptors topic.
Tip: If you want to temporarily create more room for other sections of the editor, you can hide the Project window by
clicking the View menu and selecting the Project option (which turns the checkmark to its left off). To bring back the
Project window, simply repeat this step; selecting the Project option again turns the checkmark to its left on and makes
the window visible again.
The Canvas
The Canvas is the large white area on the right side of the editor window. It takes up the most space in the editor,
because its the place where youll do most of your work.
Specifically, the Canvas allows you to visually create behaviors by drawing actions and invoked behaviors
(represented as rectangles) and conditions (represented as ovals) that you set to interact in both simple and complex
combinations via connectors (represented as arrow-shaped lines). The Canvas also allows you to assign expressions,
bindings, and comments to these elements.
When you create a behavior on the Canvas, it looks something like this:
10
Build: Displays the results of your instructing SimBionic to compile your project (i.e., convert your work on
the Canvas into executable code). For more information, see the Compiling your project topic.
Debug: Displays the results of your instructing SimBionic to debug your project (i.e., uncover and fix
program errors). For more information, see the Debugging your project topic.
Getting Started
Find: Displays the results of your instructing SimBionic to search the Canvas for a particular action,
predicate, behavior, variable, or constant; or for a specified text sequence. The results of replace operations
are also displayed here. For more information, see the Searching the Canvas and Replacing text in
behaviors topics.
Tip: If you want to temporarily create more room for other sections of the editor, you can hide the Output window by
clicking the View menu and selecting the Output option (which turns the checkmark to its left off). To bring back the
Output window, simply repeat this step; selecting the Output option again turns the checkmark to its left on and makes
the window visible again.
After youve created any work in the editor, you should preserve your project changes to disk. How to do so is covered
in the next topic, Saving your work.
Saving your work
To preserve the work you create in SimBionic, you must periodically save your project to disk.
We recommend that you save your work every 10 minutes or so, so that if something goes wronge.g., your PC
freezes up, or the power cord accidentally gets yanked outyoull lose no more than 10 minutes of work.
At bare minimum, though, you must save your work before ending a work session and exiting SimBionic. (The only
exception is if you regret all the changes youve made to your project since the last time you saved, in which case you
can exit without saving. For more information, see the Abandoning project changes topic.)
Saving can also useful for creating copies of your project stored at different locations and/or under different names.
For example, you can back up your project by saving it to a different folder and/or different disk, optionally using a
slightly different name for each version you save (e.g., Project1, Project2, Project3, etc.). As another example, you can
save a completed project under a different name, and then use the copy as the foundation for your work in creating an
entirely new project (which can sometimes be easier than starting a new project from scratch).
If youre saving a new project for the first timeor if you want to save an existing project under a different name and/or
to a different disk locationfollow these steps:
1.
2.
3.
Click Save.
Your project is saved in the folder and under the name you specified.
For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.
Alternatively, if youre saving changes to a project that youve already saved previously, follow these steps:
1.
Click the File menu and select the Save option, or press Ctrl+S.
Your project is saved in the folder and under the name you previously specified.
2.
11
Tip: If you want to create a backup copy of your project and/or rename your project, see the Copying and/or renaming
a project topic.
Printing the Canvas
If a behavior youve created on the Canvas becomes too large to view at a glance on your screen, or if you simply
want to study your work away from your PC, you can print the current behavior on the Canvas onto paper. To do so,
follow these steps:
12
1.
Make sure your printer is on and online, and has paper in its paper tray.
2.
Click the File menu and select the Print option, or press Ctrl+P.
A Print dialog box like this appears:
3.
If the printer you need isnt selected, click in the Name box and select the appropriate printer from
the list that appears.
4.
If you want to print a select range of pages, double-click in the From: box and type the first page
number of the range, and then double-click in the To: box and type the last page number of the
range.
For example, if you want to print only the second and third pages, youd enter 2 in the From: box and 3 in
the To: box. The default is to print all the pages, starting with page 1.
5.
If you want to print more than one copy of each page, double-click in the Number of copies box and
type the appropriate number.
Alternatively, you can click the up and down arrows to the right of the Number of copies option to adjust the
number in the box. For example, if you want to print three copies of each page so you can share the printout
with two colleagues, click the up arrow twice so that 3 appears in the Number of copies box. The default is 1
copy per page.
6.
If you want to save the printout to a file instead of paper, click the Print to file option.
This option is useful if youre away from your printere.g., on an airplane with your laptopbut want to
create a file that youll be able to print later on. If you select this option, youll also need to specify a folder
and filename for storing the file.
7.
If you need to adjust any other print settings, click the Properties button.
This button offers you such options as printing from the last page to the first page (rather than front to back),
printing in landscape mode (rather than portrait mode), etc. For more information, see the Adjusting print
settings topic. When youre done adjusting settings, click OK to close each additional dialog box you
opened.
8.
Make sure that your printer is on and online, and contains enough paper.
9.
Getting Started
Tip: If you want to check on how your pages will look before you actually print them, click the File menu and select the
Print Preview option. SimBionic displays how the contents of the Canvas will appear when printed. If youre satisfied
with what you see, click the Print button near the top of the window to print immediately. Alternatively, click the Close
button (to the far right of the Print button) to close the window and make any necessary adjustments before printing.
Exiting SimBionic
When youre done using the SimBionic editor, you can exit it by following these steps:
1.
Click the File menu and select the Exit option, or press Alt+F4.
If you havent made any changes since the last time you saved your project, the editor window closes and
SimBionic removes itself from your PCs memory, freeing up space for other programs. Otherwise, a dialog
box asks whether you want to save your project changes.
2.
If you want to preserve the revisions to your project, click the Yes button. If you want to abandon
your most recent changes, click the No button.
If you clicked Yes, all the revisions youve made to your project are saved, and SimBionic exits. If you
clicked No, all the changes youve made since the last time you saved your project are abandoned, and
SimBionic exits.
Note: If you try save a project that hasnt been previously saved, SimBionic first prompts you to specify a the folder
name and filename for storing your project. For more information, see the Saving your work topic.
Tip: If you want to abandon your recent changes to a project, you dont have to exit SimBionic to do so. Instead, you
can select File->New, and click the No button when asked if you want to save your changes. SimBionic closes your
project but remains open. You can then click the File menu and select your projects name (listed on the lower portion
of the menu) to reload your project; only the changes made since the last time you saved the project will appear.
Updating SimBionic
Stottler Henke is continually working to make SimBionic the best AI programming tool possible. As a result, SimBionic
is frequently updated. To keep track of whats happening with SimBionic, visit its Web site at www.simbionic.com.
If you see a notice about a new version of SimBionic being available but arent sure what version you already have,
click the SimBionic editors Help menu and select the About option; the version of SimBionic youre currently using is
displayed. When youre done with the dialog box, click its OK button to close it.
You will need to uninstall your current version of SimBionic before installing a new version. Follow these steps to
uninstall your current copy of SimBionic:
1.
Move any projects you may have stored in your SimBionic folder to a different folder.
This ensures that you dont accidentally lose any of your work when your SimBionic folder is deleted.
2.
Click the Start button on the Windows taskbar (in the bottom-left corner of your screen), and select
Programs->SimBionic->Uninstall.
An uninstaller program is launched.
3.
Follow the instructions that appear on your screen to complete the uninstall.
When youre done, all of SimBionics components are removed from your hard disk.
To proceed by installing the latest version of SimBionic, see the Installing SimBionic topic.
13
The Catalog houses the declarationsi.e., specifications of the names and characteristicsof every action, predicate,
behavior, global variable, constant, enumerated type, and class used in your project. You must declare these program
constructs before you can successfully compile any SimBionic project, as the declarations ensure SimBionic can
identify each construct you refer to on the Canvas and associate it with the appropriate parameters and/or data type.
In addition to storing declarations, the Catalog allows you to click most declared program constructs (i.e., action,
predicate, behavior, global variable, or constant) and, while holding down your mouse button, drag a copy of the
construct to the Canvas, which makes creating behaviors relatively quick and easy. The pane therefore effectively
provides you with a catalog of program constructs you can select among to build any behavior.
The following are the program constructs in SimBionic that can be declared in the Catalog and the topics that tell you
how to declare them:
Global variable: See the Creating and editing global variables topic.
Enumerated type: See the Creating and editing enumerated types topic.
SimBionic comes with certain actions and predicates already built-in, and so the declarations for these actions and
predicates are inserted into the Catalog of every project for you automatically. To learn more, see the Understanding
the core actions and Understanding the core predicates topics.
In addition, there may be action, predicate, and/or behavior declarations that have been created in previous projects
that youd like to copy to and reuse in your current project. To learn how to do so, see the Importing AP Modules and
Importing a behavior topics.
After you declare your Catalog items, you can rename, reorganize, or delete any item with a few mouse clicks. For
more information, see the Renaming a Catalog item, Organizing Catalog items, and Deleting a Canvas element topics.
Finally, to learn more about dragging Catalog declarations over to the Canvas, see the Creating and editing actions on
the Canvas, Creating and editing invoked behaviors, and Creating and editing conditions topics.
Tip: If you want to temporarily hide the Project window that houses the Canvas (e.g., to create more room for the
Canvas and Output window), you can do so by clicking the View menu and selecting the Project option (which turns
15
the checkmark to its left off). To bring back the Project window, simply repeat this step; selecting the Project option
again turns the checkmark to its left on and makes the Project window visible again.
Working with Actions and Predicates
Understanding the core actions
SimBionic is designed to let you (and/or programmers on your development team) create actions custom-tailored to
your particular simulation or game. However, certain actions are so commonly used by virtually all simulations that
SimBionic includes them as part of every project.
These actions are stored in the Catalog in the Core AP module, and organized by subfolders named Arrays and
Tables (for actions that let you use array and table structures to manipulate data), Blackboards (for actions that let
entities communicate via shared virtual blackboards), Entities (for actions that let you manipulate entities), and
Messages (for actions that let entities communicate via their individual message queues). The declarations of these
actions are loaded from a special APD file named base.dat, and the corresponding code for the actions is built into
SimBionics engine.
The names, descriptions, and parameters of these built-in actions are as follows:
16
ArrayAddEntry: Adds an element to the end of the specified array. Format: specified_array: array [in/out],
element: any [in]. For more information, see the Using arrays topic.
ArrayAppend: Appends the elements in one array to the end of another array. Format: source: array [in],
destination: array [out]. For more information, see the Using arrays topic.
ArrayDelete: Deletes the element at the specified position of the specified array. Each subsequent element
in the array moves forward by one (i.e., position n becomes n-1), and the arrays size is decreased by one.
Format: specified_array: array [in/out], element_position: integer [in]. For more information, see the Using
arrays topic.
ArrayInsert: Inserts an element at the specified position of the specified array. Each subsequent element in
the array moves back by one (i.e., position n becomes n+1), and the arrays size is increased by one.
Format: specified_array: array [in/out], element_position: integer [in], element: any data type [in]. For more
information, see the Using arrays topic.
ArraySet: Sets the value of an element of the specified array. Format: specified_array: array [in/out],
element_position: integer [in], value: any [in]. For more information, see the Using arrays topic.
ArraySetMinSize: Enlarges the array if it is smaller than the specified minimum size, creating new entries of
type Invalid. If the array is already the minimum size or larger, it is not changed. Format: specified_array:
array [in/out], minimum_size: integer [in]. For more information, see the Using arrays topic.
ArraySetSize: Sets the array to exactly the specified size. If the array is currently larger, the extra entries
will be destroyed. If it is smaller, it will be expanded with new entries of type Invalid. If the array is already
the specified size, it is not changed. Format: specified_array: array [in/out], new_size: integer [in]. For more
information, see the Using arrays topic.
CreateBBoard: Lets an entity create a virtual blackboard specified by a particular name, making it easy for
any entity to share information with any or all other entities in your program. Format: bboard_name: string
[in]. For more information, see the Communicating via virtual blackboards topic.
DestroyBBoard: Eliminates a named virtual blackboard, freeing up the memory taken up by the board and
all the information stored on it. Alternatively, an entity can "erase" the information on a blackboard by
destroying the board with this action and then immediately creating a new blank board with the same name
via CreateBBoard. Format: bboard_name: string [in]. For more information, see the Communicating via
virtual blackboards topic.
DestroyEntity: Destroys the specified entity in the run-time engine, removing it from SimBionics control.
Format: entity_id: entity [in].
DestroyGroup: Dissolves a named group, which has the same effect as each member of the group quitting
it at the same time. As a result, no entity receives any subsequent messages directed at the group.
However, each entitys message queue continues to store whatever messages were previously received
from the group until the entity accesses and explicitly disposes of those messages. Format: group_name:
string [in]. For more information, see the Communicating via group messages topic.
JoinGroup: Lets an entity join a named group of entities. If the group doesnt already exist, this action
creates it using the specified name and then makes the entity its first member. After joining, the entity
receives any message sent to the group, along with every other member of the group. Format: group_name:
string [in]. For more information, see the Communicating via group messages topic.
NextMsg: Lets an entity discard the top message of its message queue so it can access the next message
in the queue. Format: no parameters. For more information, see the Communicating via group messages
topic.
PostBBoard: Lets an entity place information in a named section of a named virtual blackboard. The
information can then be read by any entity that "knows" the names of the blackboard and section. The
information remains available until its either replaced (via another PostBBoard action) or the board is
destroyed (via the DestroyBBoard action). Format consists of the boards name, followed by a key-value pair
identifying board sections name and the data to be stored: bboard_name: string [in], key: string [in], value:
any [in]. For more information, see the Communicating via virtual blackboards topic.
QuitGroup: Lets an entity belonging to a named group of entities resign its membership so that it stops
receiving messages sent to that group. Format: group_name: string [in]. For more information, see the
Communicating via group messages topic.
Resume: Causes execution to resume at the rectangle in the current behavior where the exception was
thrown without attempting to retry execution of that rectangle. Resume is typically invoked when it is not
possible to fix the error condition (so retrying the offending action or predicate would be fruitless), but it is
still possible to clean up after the error and continue with the behaviors normal course of execution. For
more information, see the Understanding error handling topic.
Rethrow: Rethrows the current exception down the stack to the current behaviors invoking behavior and
then terminates the current behavior just as if a final rectangle had been executed. The invoking behavior
then becomes the new current behavior and must attempt to handle the exception exactly as if it had been
thrown in that behavior. Rethrow is called when a behavior is unable to recover from an error and needs to
pass responsibility for error recovery on to another behavior. For more information, see the Understanding
error handling topic.
Retry: Causes behavior execution to jump to the rectangle where the exception was thrown in the current
behavior, executing that rectangle exactly as if it had just become the current rectangle in normal fashion.
Retry is generally invoked after attempting to diagnose and fix whatever error condition caused the
exception to be thrown, in the hopes that the second attempt will be more successful. For more information,
see the Understanding error handling topic.
SendMsg: Lets an entity send a message and number code to a named group of entities. Format consists
of the name of the group, which is of data type entity; the number code, which is of data type integer; and
the actual message, which can be any data type: group: string [in], number code: integer [in], msg: any [in].
For more information, see the Communicating via group messages topic.
SetBehavior: Pops all execution frames currently on the specified entity's stack and then reinitializes the
entitys behavior using the specified parameters. However, SetBehavior leaves the entitys message queue
and global variables unchanged. Use this action to change an entitys current behavior. Format: entity_id:
entity [in], behavior_name: string [in], parameters: array [in].
SetEntityGlobal: Sets the value of the specified global variable for the specified entity. For example, you
can use this method to assign the entity a different descriptor value, thus setting the entity to perform a
different polymorphic behavior. Format: entity_id: entity [in], variable_name: string [in], value: any [in].
SetUpdateFrequency: Sets the minimum frequency with which you want an entity updated, specified via an
integer from -1 through 100. See the Controlling the entity scheduler topic for more information on the
update frequency parameter. Format: entity_id: entity [in], new_frequency: integer [in].
SetUpdatePriority: Sets the update priority you want to assign an entity within any given clock tick,
specified via an integer from 0 on up through the highest integer allowed by your compiler. See the
Controlling the entity scheduler topic for more information on the update priority parameter. Format:
entity_id: entity [in], new_priority: integer [in].
TableAddCol: Adds the specified new column to the right-hand side of the specified table. Note that the
new column must have the same number of rows as the table. Format: table: table [in/out], new_column:
array [in]. For more information, see the Using tables topic.
TableAddRow: Adds the specified new row to the bottom of the specified table. Note that the new row must
have the same number of columns as the table. Format: table: table [in/out], new_row: array [in]. For more
information, see the Using tables topic.
TableAppend: Appends the rows in one table to the bottom of a second table. Note that the two tables must
have the same number of columns. Format: source: table [in], destination: table [in/out]. For more
information, see the Using tables topic.
TableDeleteCol: Deletes the column at the specified position of the table. Each subsequent column in the
table moves forward by one (i.e., position n becomes n-1), and the tables column size is decreased by one.
Format: specified_table: table [in/out], column_position: integer [in]. For more information, see the Using
tables topic.
TableDeleteRow: Deletes the row at the specified position of the table. Each subsequent row in the table
moves forward by one (i.e., position n becomes n-1), and the tables row size is decreased by one. Format:
specified_table: table [in/out], column_position: integer [in]. For more information, see the Using tables topic.
TableInsertCol: Inserts the specified column, with initial values of your choosing, in the specified position of
the table. Each subsequent column in the table moves back by one (i.e., position n becomes n+1), and the
tables column size is increased by one. Format: specified_table: table [in/out], column_position: integer [in],
new_column: array [in]. For more information, see the Using tables topic.
TableInsertRow: Inserts the specified row, with initial values of your choosing, in the specified position of
the table. Each subsequent row in the table moves back by one (i.e., position n becomes n+1), and the
17
tables row size is increased by one. Format: specified_table: table [in/out], row_position: integer [in],
new_row: array [in]. For more information, see the Using tables topic.
TableSetCol: Replaces one column of a table with the specified array. Note that the array must have the
same number of rows as the table. Format: specified_table: table [in/out], new_column: array [in]. For more
information, see the Using tables topic.
TableSetEntry: Sets the value of the specified element in the table. Format: specified_table: table [in/out],
row_position: integer [in], column_position: integer [in], value: any [in]. For more information, see the Using
tables topic.
TableSetMinSize: Enlarges the table if it is smaller than the specified number of rows and columns, creating
new entries of type Invalid. If the table is already the minimum size or larger, it is not changed. Format:
specified_table: table [in/out], minimum_rows: integer [in], minimum_columns: integer [in]. For more
information, see the Using tables topic.
TableSetRow: Sets the values in the specified row of the table to the values in the specified array. Format:
specified_table: table [in/out], row_position: integer [in], array_values: array [in]. For more information, see
the Using tables topic.
TableSetSize: Sets the table to exactly the specified number of rows and columns. If the table is currently
larger, its extra rows and columns will be destroyed. If it is smaller, it will be expanded with new entries of
type Invalid. If the table is already the specified size, it is not changed. Format: specified_table: table [in/out],
num_rows: integer [in], num_columns: integer [in]. For more information, see the Using tables topic.
Note: Because these actions are hard-coded in SimBionics engine and designed to be included in every project, you
cant edit or delete a core actions declaration in the Catalog. This is indicated by a small lock symbol in the upper-left
of each core actions icon in the Catalog.
SimBionic also includes built-in predicates that work in conjunction with the core actions. For more information, see the
Understanding the core predicates topic.
Understanding the core predicates
SimBionic is designed to let you (and/or programmers on your development team) create predicates custom-tailored to
your particular simulation or game. However, certain predicates are so commonly used by virtually all simulations that
SimBionic includes them as part of every project.
These predicates are stored in the Catalog in the Core AP module, and organized by subfolders named Arrays and
Tables (for predicates that let you use array and table structures to manipulate data), Blackboards (for predicates that
let entities communicate via shared virtual blackboards), Entities (for predicates that let you create and manipulate
entities), and Messages (for predicates that let entities communicate via their individual message queues), as well as
six miscellaneous predicates. The declarations of these predicates are loaded from a special file named base.dat, and
the corresponding code for the predicates is built into SimBionics engine.
The names, descriptions, and parameters built-in predicates are as follows:
18
ArrayCopy: Returns a copy of the specified array (which is useful if the arrays values periodically change
and you need to preserve its current values). Format: specified_array: array [in]. Returns value of data type
array. For more information, see the Using arrays topic.
ArrayGet: Returns the value of the element at the specified position of the specified array. Format:
specified_array: array [in], , element_position: integer [in]. Returns value of data type any (because the
element can be of any data type). For more information, see the Using arrays topic.
ArrayPop: Deletes the element at the end of the specified array (decreasing the size of the array by one)
and then returns the value of the element. Format: specified_array: array [in]. Returns value of data type any
(because the element can be of any data type). For more information, see the Using arrays topic.
ArraySize: Returns the number of elements in the specified array. Format: specified_array: array [in].
Returns value of data type integer. For more information, see the Using arrays topic.
CreateEntity: Creates a new entity in the run-time engine and places it under SimBionics control. (Along
with each entity, the engine creates a behavior stack, message queue, and set of global variables devoted
to the activities of that entity.) Format: entity_name: string [in], initial_behavior: string [in], parameters: array
[in], update_frequency: integer [in], update_priority: integer [in]. Returns value of data type entity.
CreateInstance: Creates an instance of the specified Java class, calling the constructor with the given
arguments. Format: class_name: string [in], constructor_args: array [in]. Returns the new instance, or null
on failure. For more information, see the Using classes topic.
GetEntityID: Returns the unique ID number of the current entity. SimBionic dynamically assigns this number
when creating the entity and uses it exclusively to refer to the entity while your program is running. Format:
no parameters. Returns value of data type entity. For more information on creating and referencing entities,
see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
GetMsgData: Lets an entity read the message thats at the top of its message queue. The message is
unaffected by being read, and will remain stored in the queue until the entity discards it (via the NextMsg
action) to access the next message in the queue. Format: no parameters. Returns value of data type any
(because a message can be any data type). For more information, see the Communicating via group
messages topic.
GetMsgSender: Lets an entity read who sent the message at the top of its message queue, which helps to
place the message in context (and might even determine whether the entity bothers to read the message at
all). The message is unaffected by having the identity of its sender read, and will remain stored in the queue
until the entity discards it (via the NextMsg action) to access the next message in the queue. Returns value
of data type entity. Format: no parameters. For more information, see the Communicating via group
messages topic.
GetMsgType: Lets an entity read a number code thats attached to the current message in its message
queue. (What meaning is ascribed to the number is up to you.) The message is unaffected by having its
code number read, and will remain stored in the queue until the entity discards it (via the NextMsg action) to
access the next message in the queue. Format: no parameters. Returns value of data type integer. For
more information, see the Communicating via group messages topic.
If: Takes an expression and two values; determines whether the expression is true or false; and then returns
the first value if the expression is true or the second value if its false. This predicate is most commonly used
for bindings; e.g., BabyPresent = If(gender=="boy",BluePresent,PinkPresent) would assign the BluePresent
value for a boy and the PinkPresent value for a girl. Format: expression: Boolean [in], Value1: any [in],
Value2: any [in]. Returns value of data type any (because both Value1 and Value2 can be any data type).
For more information on bindings, see the Attaching bindings to a Canvas element topic.
IsBBoard: Lets an entity verify that a named virtual blackboard existsi.e., was created previously via the
CreateBBoard action and hasnt been permanently eradicated via the DestroyBBoard action. If the board
with the name specified exists, IsBBoard returns a value of true; while if the board doesnt existeither
because it was never created or has subsequently been destroyedIsBBoard returns a Boolean value of
false. Format: name: string [in]. Returns value of data type Boolean. For more information, see the
Communicating via virtual blackboards topic.
IsDone: Checks on whether the current behavior has completed executioni.e., reached its final action
and then returns a value of true or false. This predicate is necessary because of the way SimBionic handles
its flow of execution. Format: no parameters. Returns value of data type Boolean. For more information, see
Checking for completed behaviors topic.
IsMsg: Lets an entity check whether it currently has any messages stored in its message queue. If the
queue contains at least one message, IsMsg returns a value of true; while if the queue is empty, IsMsg
returns a value of false. IsMsg should be used each time an entity has discarded the top message in its
queue (via the NextMsg action) to determine if there are any additional messages waiting to be accessed.
Also, after the entity has dealt with and discarded all its messages, it should use IsMsg periodically to find
out if any new messages have been received in its queue. Format: no parameters. Returns value of data
type Boolean. For more information, see the Communicating via group messages topic.
IsNull: Checks whether a variable of a class type contains a null value. Format: var: any [in]. Returns value
of type Boolean. See Using classes for more information.
IsValid: Checks on whether a value of type any is what was expected; or is instead invalid, indicating that
something went wrong. You can use IsValid to check on a predicate that has the potential of returning an
invalid value. For example, the ReadBBoard predicate normally returns data stored in a named section of a
named blackboard; but if either the blackboard or its named section doesnt exist, ReadBBoard will instead
return a value of invalid. If you then use IsValid, it will return a Boolean value of false to indicate the
ReadBBoard value was not valid. Format: var: any [in]. Returns value of data type Boolean. For more
information, see the Checking for invalid values topic.
NullData: Returns a value of type data that is null, which is evaluated as falsei.e., the equivalent of a
Boolean value being false, an integer or float value being 0, a vector value being [0,0,0], or a string value
being "". Use NullData for situations when you need the option of returning a false result for a value of type
data. Format: no parameters. Returns value of data type data. For more information, see the Creating a
false value topic.
NullEntityID: Returns an entity ID value of null, which is evaluated as falsei.e., the equivalent of a
Boolean value being false, an integer or float value being 0, a vector value being [0,0,0], or a string value
being "". Use NullEntityID for situations when you need the option of returning a false result for a value of
type entity. Format: no parameters. Returns value of data type entity. For more information, see the Creating
a false value topic.
NumMembers: Lets an entity find out how many entities belong to a named group (created previously via
the JoinGroup action). NumMembers returns a value of zero if the group with the specified name either was
never created, or has been dissolved via the QuitGroup and/or DestroyGroup actions. Format: name: string
[in]. Returns value of data type integer. For more information, see the Communicating via group messages
topic.
ReadBBoard: Lets an entity access any virtual blackboard (created previously via the CreateBBoard action)
and read any information on the board (placed previously via the PostBBoard action) by specifying the
boards name and the section of the board storing the information. ReadBBoard therefore allows any entity
to obtain information from any other entity in your program. Format consists of the name of the board
19
followed by the name of the section storing the data: name: string [in], key: string [in]. Returns value of data
type any (because the information can be any data type). For more information, see the Communicating via
group messages topic.
TableColSize: Returns the number of columns in the specified table. Format: specified_table: table [in].
Returns value of data type integer. For more information, see the Using tables topic.
TableCopy: Returns a copy of the specified table (which is useful if the tables values periodically change
and you need to preserve its current values). Format: specified_table: table [in]. Returns value of data type
table. For more information, see the Using tables topic.
TableGetCol: Returns an array containing the values of the specified column of the specified table. Format:
specified_table: table [in], column_position: integer [in]. Returns value of data type array. For more
information, see the Using tables topic.
TableGetEntry: Returns the value of the element at the specified position of the specified table. Format:
specified_table: table [in], row_position: integer [in], column_position: integer [in]. Returns value of data type
any (because the element can be of any data type). For more information, see the Using tables topic.
TableGetRow: Returns an array containing the values of the specified row of the specified table. Format:
specified_table: table [in], row_position: integer [in]. Returns value of data type array. For more information,
see the Using tables topic.
TableRowSize: Returns the number of rows in the specified table. Format: specified_table: table [in].
Returns value of data type integer. For more information, see the Using tables topic.
Note: Because these predicates are hard-coded in SimBionics engine and designed to be included in every project,
you cant edit or delete a core predicates declaration in the Catalog. This is indicated by a small lock symbol in the
upper-left of each core predicates icon in the Catalog.
SimBionic also includes built-in actions that work in conjunction with the core predicates. For more information, see the
Understanding the core actions topic.
Declaring an action
The fundamental building blocks of a SimBionic project are its actions, which determine every step of its execution.
More specifically, an action is a mini-program that performs some small activity to help move your SimBionic program
forward. Examples of actions include making a calculation, sending a message, changing direction, firing a weapon,
etc.
An action consists of three basic components:
The underlying code (typically written in C++ or Java) that makes the action work, which youor a
programmer on your development teammust create and then include as part of your simulation or game.
For more information, see the Coding actions in C++ or Coding actions in Java topic.
The actions declaration in the Catalog, in which you specify the actions name; enter a brief description
of what it does; and enter any parameters the action will use to pass values to SimBionic and/or return
values from SimBionic (based on how the action is programmed to operate in your simulation or game).
The actions inclusion on the Canvas, which is represented as a rectangle, and tells SimBionic precisely
where in your program you want the action to be triggered. For more information, see the Creating and
editing actions on the Canvas topic.
You can create these three aspects of an action in any order you want. Before you can successfully compile a
SimBionic project, however, the name and parameters of every action you use must be specified, or declared, in the
Catalog.
To declare an action in the Catalog, follow these steps:
20
1.
2.
Notice that the dialog box contains sections for specifying the actions name, description, and parameters. In
addition, it contains buttons for inserting, editing, deleting, and repositioning parameters.
3.
Click in the Name box and type the name you want to give the action.
To ensure the readability of your program code, enter a name that clearly describes what sort of action will
be performed (e.g., Eat, Walk_Left, FireCannon).
4.
Click in the Description box, and type a brief description of what the action does.
This documentation helps ensure your action will be readily understood by other members of your team, and
is also useful for refreshing your own memory in case you need to return to your project months or years
later.
If your action has no parameters, then youve successfully declared it. In this case, skip to Step 12.
5.
Notice that the dialog box contains boxes for specifying the parameters name, data type, and value
handling (i.e., whether it can pass a value to SimBionic, return a value from SimBionic, or both).
21
6.
Click in the Name box and type the name you want to give the parameter.
To ensure the readability of your program code, enter a name that clearly describes the value that will be
transmitted by the parameter (e.g., HQCommand, Health_Rating, Ammunition_Count).
7.
Click in the Type box to display the available data types, and click the data type thats appropriate
for your parameter.
If you arent sure which option to click, read the Choosing a data type topic and then return to this step.
For example, the core action CreateBBoard creates a virtual blackboard with the name you specify.
Because CreateBBoard must transmit a name (i.e., a text string), this action is declared with a parameter of
data type string.
8.
Click in the Binding box, and click the option that best describes how you want your parameter to
handle values.
The three choices are in, meaning it can only pass a value to SimBionic; out, meaning it can only return a
value from SimBionic; or in/out, meaning it can both pass and return values.
For example, the core action CreateBBoard must pass a string value to SimBionics engine, but it doesnt
need to return any value from SimBionic. As a result, this action is declared with a parameter of value
handling type in.
9.
Click in the Description box, and type a brief description of what the parameter is for.
This documentation helps ensure your parameter will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the parameter in the
Catalog or any Edit dialog box.
22
The underlying code (typically written in C++ or Java) that makes the predicate work, which youor a
programmer on your development teammust create and then include as part of your simulation or game.
For more information, see the Coding predicates in C++ or Coding predicates in Java topic.
The predicates declaration in the Catalog, in which you assign the predicate a name; enter a brief
description of what it does; and enter any parameters the predicate will use to pass values to SimBionic
and/or return values from SimBionic (based on how the predicate is programmed to operate in your
simulation or game). Note: Predicates automatically return a single value, so parameters are necessary only
if a predicate also needs to pass one or more values to SimBionic and/or needs to return two or more values
from SimBionic.
The predicates inclusion on the Canvas as part of a condition, which is represented as an oval, and
determines the path along which your program executes. For more information, see the Creating and editing
conditions topic.
You can create these three aspects of a predicate in any order you want. Before you can successfully compile a
SimBionic project, however, the name and parameters of every predicate you use must be specified, or declared, in
the Catalog.
To declare a predicate in the Catalog, follow these steps:
1.
2.
Notice that the dialog box contains sections for specifying the predicates name and description. In addition,
it contains a box for specifying the data type of the predicates return value; and buttons for inserting,
editing, deleting, and repositioning parameters.
3.
Click in the Name box and type the name you want to give the predicate.
To ensure the readability of your program code, enter a name that clearly describes what sort of predicate
will be performed (e.g., GetOrders, Read_Headlines, CountAmmunition).
4.
Click in the Description box, and type a brief description of what the predicate does.
This documentation helps ensure your predicate will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
By definition, a predicate always returns a value from SimBionic. Since this is automatic, you dont have to
create a parameter for this task; but you do have to specify what type of data the predicate will be returning.
5.
Click in the Type box (between the Name box and the OK button) to display the available data types,
and click the data type thats appropriate for your predicates returned value.
If you arent sure which option to click, read the Choosing a data type topic and then return to this step.
For example, the core predicate NumMembers counts the number of members in a group with the name you
specify. The whole number value NumMembers returns is therefore declared to be of data type integer.
If all you require your predicate to do is return a single value, then you dont have to declare any parameters
and can now skip to Step 13.
However, if your predicate also needs to receive one or more values from SimBionic, and/or if it needs to
return more than one value to SimBionic, then you must create appropriate parameters for it. In this case,
proceed to Step 6.
23
6.
Notice that the dialog box contains boxes for specifying the parameters name, data type, and value
handling (i.e., whether it can pass a value to SimBionic, return a value from SimBionic, or both).
7.
Click in the Name box and type the name you want to give the parameter.
To ensure the readability of your program code, enter a name that clearly describes the value that will be
transmitted by the parameter (e.g., HQCommand, Latest_News, Bullets_Remaining).
8.
Click in the Type box to display the available data types, and click the data type thats appropriate
for your parameter.
If you arent sure which option to click, read the Choosing a data type topic and then return to this step.
For example, the core predicate NumMembers counts the members belonging to a group that has the name
you specify. Because NumMembers must transmit the groups name (i.e., a text string), this predicate is
declared with a parameter of data type string.
9.
Click in the Description box, and type a brief description of what the parameter is for.
This documentation helps ensure your parameter will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the parameter in the
Catalog or any Edit dialog box.
10. Click in the Binding box, and click the option that best describes how you want your parameter to
handle values.
The three choices are in, meaning it can only pass a value to SimBionic; out, meaning it can only return a
value from SimBionic; or in/out, meaning it can both pass and return values.
For example, the predicate NumMembers must pass a name to SimBionics engine. As a result, the
parameter passing the name is declared to be of value handling type in. At the same time, the single value
NumMembers receives from SimBionic is returned by the predicate automatically and so doesnt require a
parameter; but if it did, the parameter would be declared to be of value handling type out.
11. Click the OK button of the Insert Parameter dialog box.
The Insert Parameter dialog box closes; and the parameter youve just created is listed in the Parameters
box with the name, data type, and value handling you specified.
12. Optionally repeat Steps 6-11 to create additional parameters.
Repeat this step until youve created all of the necessary parameters for your predicate. When youre done,
all the predicates parameters are listed in the Parameters box.
13. Click the OK button of the Insert Predicate Declaration dialog box.
The Insert Predicate Declaration dialog box closes, and the predicate youve declared is saved and
displayed under the Predicates header in the Catalog.
24
If you ever change your mind about the name, description, and/or parameters of a declared predicate, you can edit the
declaration by either double-clicking it, or right-clicking it and selecting the Edit option from the menu that appears.
Doing so brings up an Edit Predicate Declaration dialog box. You can then revise the text in the Name and/or
Description boxes; and revise any listed parameter by clicking it in the Parameters box to select it and then clicking the
Edit button. You can also reposition a selected parameter in the Parameters box by clicking the Up and Down buttons;
or permanently remove it by clicking the Delete button.
Tip #1: You can also create a new predicate in the Catalog using the Ctrl-D shortcut.
Tip #2: You dont necessarily have to create all of your predicate declarations manually. If an existing SimBionic
project contains predicate declarations youd like to reuse, you can copy them directly into your current project. For
more information, see the Importing AP Modules topic.
In addition to declaring predicates, you must declare any actions and behaviors used in your project. To learn how,
see the Declaring an action and Declaring a behavior topics.
Working with AP Modules
In SimBionic, actions and predicates are organized into action-predicate (AP) modules, which are collections of
actions and predicates that can be shared across multiple SimBionic projects. AP modules enable you to take actions
and predicates that you created for one game and reuse them in other games later. The actions and predicates in an
AP module often share a common theme or purpose, but this is not required.
Every SimBionic project contains at least two AP modules: the Core module, which contains all of the core actions
and core predicates, and the Project module, which is provided as a default place for you to store your own actions
and predicates. If you dont have a lot of actions and predicates, or if youre not interested in reusing them across
multiple projects, then these two AP modules will probably suffice for you. If you wish to add additional AP modules to
your project, however, you can do it in one of two ways: you can import an existing AP module (see Importing AP
Modules), or you can create a new AP module from scratch as follows:
1.
2.
3.
You can rename an existing AP module, as described in the topic Renaming a Catalog item. You can also remove an
AP module from your project by deleting it (see Deleting a Catalog item). Note that this does not delete the AP
modules APD file, which may still be imported by other projects. Also note that you cannot delete the default Core or
Project AP modules.
To move an action or predicate from one AP module to another, simply left-click on the desired action in the Catalog
and drag it to the new AP module (or a folder within that AP module). The action or predicate will be removed from the
old AP module and added to the new one. Note that you cannot move actions or predicates from the Core AP module.
For information about using AP modules with the SimBionic run-time engine, see Managing AP modules in the C++
run-time engine and Managing AP modules in the Java run-time engine.
Importing AP Modules
When you save a SimBionic project, four types of files are generated. One has the name of your project followed by an
SBP extension (for SimBionic Project) and contains most of your projects data. The second type of file has a BTN
extension, and it contains a behavior declaration. The third type has a TPD extension and it contains enumerated
types and classes.
The fourth type of file has an APD extension, and it contains an AP module. AP modules are stored separately to give
you the option of loading them into any other SimBionic project so that you can instantly access existing action and
predicate declarations (as opposed to having to recreate your action and predicate declarations in each project from
scratch).
To import an AP module from another SimBionic project into your current project, follow these steps:
1.
Click the File menu and select the Import AP Module option.
An Open dialog box appears that allows you to browse your hard disk or network for APD files.
2.
Use the dialog box to locate the folder containing the APD file youre after, and then click the file.
The file is displayed in the Filename text box.
3.
4.
25
Note: The actions and predicates you declare in the Catalog function only as the front-end of your program; every
action and predicate must be supported by corresponding code in your teams simulation or game. If you arent adept
at C++ or Java, the code will typically be created by one of the C++ or Java programmers on your development team.
Working with Behaviors
Declaring a behavior
A SimBionic program is composed of behaviors, which are subprograms that dynamically determine every decision
made and action performed by the programs entities.
Each behavior is itself composed of four programming constructs:
Actions, which define all the different actions an entity can perform. (For more information, see the Creating
and editing actions on the Canvas topic.)
Other existing behaviors, which can be called up, or invoked, at any point in the current behavior. When
this occurs, SimBionic executes the invoked behavior until its either completed or aborted, and then returns
to executing the original behavior. (For more information, see the Checking for completed behaviors topic.)
Conditions, which set the conditions under which each action and invoked behavior will happen. (For more
information, see the Creating and editing conditions topic.)
Connectors, which control the order in which conditions are evaluated, and actions and invoked behaviors
take place. (For more information, see the Creating a connector topic.)
These four constructs allow you to program AI behavior that simulates the behavior we experience in the real world.
To create a behavior, you must first declare it in the Catalog, which opens a Canvas window devoted to that behavior.
You can then insert the elements described above onto the Canvas window. The types of actions, invoked behaviors,
and conditions you include, and how you choose to arrange them in relation to each other, uniquely define the
particular behavior.
Note: As explained in the Understanding the Main behavior topic, SimBionic declares an initial behavior named Main
for you automatically and assigns it a blank Canvas. However, you must explicitly declare any additional behaviors you
want in your project.
To declare a behavior in the Catalog, follow these steps:
26
1.
2.
Notice that the dialog box contains sections for specifying the behaviors name, description, parameters, and
execution mode. In addition, it contains buttons for inserting, editing, deleting, and repositioning parameters.
3.
Click in the Name box, and type the name you want to give the behavior.
To ensure the readability of your program code, enter a name that clearly describes what the behavior does
(e.g., FindBestPath, BuySupplies, AttackEnemy).
4.
Click in the Description box, and type a brief description of what the behavior does.
This documentation helps ensure your behavior will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the behavior in the
Catalog or any Edit dialog box.
If your behavior has no parameters, then skip to Step 12.
5.
27
Notice that the dialog box contains boxes for specifying the parameters name, description, data type, and
value handling (i.e., whether it can pass a value to SimBionic, return a value from SimBionic, or both).
6.
Click in the Name box and type the name you want to give the parameter.
To ensure the readability of your program code, enter a name that clearly describes the value that will be
transmitted by the parameter (e.g., HQCommand, Health_Rating, Ammunition_Count).
7.
Click in the Type box to display the available data types, and click the data type thats appropriate
for your parameter.
If you arent sure which option to click, read the Choosing a data type topic and then return to this step.
8.
Click in the Binding box, and click the option that best describes how you want your parameter to
handle values.
The three choices are in, meaning it can only pass a value to SimBionic; out, meaning it can only return a
value from SimBionic; or in/out, meaning it can both pass and return values.
9.
Click in the Description box, and type a brief description of what the parameter is for.
This documentation helps ensure your parameter will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the parameter in the
Catalog or any Edit dialog box.
28
Tip #2: You dont necessarily have to create all of your behavior declarations manually. If an existing SimBionic
project contains behavior declarations youd like to reuse, you can copy them directly into your current project. For
more information, see the Importing a behavior (BTN) topic.
In addition to declaring behaviors, you must declare any actions and predicates used in your project. To learn how,
see the Declaring an action and Declaring a predicate topics.
Setting a behavior's execution mode
By default, on each clock tick a behavior executes only a single rectangle. Sometimes, though, you may want a
behavior to do more during a clock tick for example, you might want the entire behavior to execute in a single clock
tick. You can control how much a behavior does in a clock tick by modifying its execution mode.
There are three types of execution modes available for behaviors:
Run multi-tick: During each clock tick, execute one rectangle (i.e., action or invoked behavior) of the
behavior, and then evaluate the connectors coming out of that rectangle. If the conditions on one of those
connectors evaluate as true, move to the rectangle at the end of that connector and then stop. Repeat this
cycle every clock tick until the behavior reaches a final action or is aborted or suspended by another
behavior.
This option is the default, because it allows you to abort or suspend a behavior when new circumstances
arise, and also provides SimBionic maximum flexibility in juggling the various demands on its execution time.
Run in one tick: Execute the entire behavior (i.e., from its initial rectangle to its final action) in a single clock
tick. However, after executing each rectangle of the behavior, evaluate the connectors at lower levels of the
execution stack in case at any point conditions are met that should cause the behavior to be aborted or
suspended.
This option is appropriate for a behavior that requires quick execution (e.g., reloading ammunition during a
battle).
Run until blocked: During each clock tick, execute one rectangle of the behavior, and then evaluate the
connectors coming out of that rectangle. If the conditions on one of those connectors evaluate as true, move
to the rectangle at the end of that connector and execute it in the same clock tick. Repeat this cycle until
none of the conditions leading out of the current rectangle evaluate as true, and then stop. Repeat every
clock tick until the behavior reaches a final action or is aborted or suspended by another behavior.
This option is appropriate for behaviors that are primarily driven by outside events (e.g., a gun turret that is
only active when an enemy is in view), since it effectively allows the behavior to switch between multi-tick
and one-tick mode depending on how much is going on in your application.
Note: Some of these modes take precedence over others: run until blocked mode overrides multi-tick mode, and onetick mode overrides both of the other modes. If a behavior with a higher-precedence execution mode invokes a
behavior with a lower-precedence mode, the invoked behavior will use the higher-precedence mode. For example, if a
one-tick behavior invokes a multi-tick behavior, the invoked behavior will execute in one tick as well.
2.
3.
For more information about behavior execution modes, see the Setting a behavior to run uninterrupted, Creating an
interrupt, Checking for completed behaviors, and Understanding SimBionic's flow of execution topics.
Setting a behavior to run uninterrupted
By default, a behavior can be aborted or suspended by behaviors below it on the execution stack, as discussed in the
topic Understanding SimBionic's flow of execution. In some cases, however, you may want a behavior to execute
without being interrupted by any other behaviors for example, if it is performing a critical task. You can control this
aspect of a behaviors execution by modifying its interruptibility mode.
There are two interruptibility mode options for available for behaviors:
Interruptible: Evaluate connectors and conditions in behaviors that are below this one on the execution
stack. If a condition on one of these lower-level connectors evaluates as true, abort this behavior (or
suspend it if the connector is an interrupt connector).
29
This option is the default, because it allows you to abort or suspend a behavior when new circumstances
arise. It is appropriate when a behavior may need to be overridden by a more urgent activity (e.g., evading
flying shrapnel).
Non-interruptible: Do not evaluate connectors and conditions in behaviors below this one on the execution
stack. This behavior thus cannot be aborted or suspended.
This option is appropriate for top-priority behaviors and/or behaviors that wont be effective if interrupted
(e.g., transmitting a critical message).
If youre declaring a new behavior in the Catalog, you can select which of these options you want via the Insert
Behavior Declaration dialog box. For more information, see the Declaring a behavior topic.
Alternatively, if the behavior already exists and you want to change the way it executes, follow these steps:
1.
2.
3.
For more information on these behavior execution options, see the Setting a behavior's execution mode, Creating an
interrupt, Checking for completed behaviors, and Understanding SimBionic's flow of execution topics.
Understanding the Main behavior
When you create a new project (as described in the Starting a new project topic), an initial behavior is always declared
for you automatically in the Catalog and assigned a blank Canvas. The default name for this behavior is Main, and
youll typically use it as your projects starting point. To indicate this, the editor doesnt allow you to delete the
behavior; places a "Home" icon to the behaviors left in the Catalog; and provides a Home button in the Navigate
toolbar that you can click at any time to instantly display the behavior on the Canvas.
It is common though not required to use Main as the initial behavior for your entities. The initial behavior forms the
foundation of your project becausedirectly or indirectlyit invokes all of your other behaviors. (More technically, its
assigned the bottom execution frame on the SimBionic engines stack and so is the only behavior that isnt called by
some other behavior.) The initial behavior therefore drives almost everything else that happens in your SimBionic
program.
Tip: You can optionally give the Main behavior a different name. To do so, double-click Main in the Catalog; type
another name in the Name text box; and press Enter. The "Home" icon remains to the left of the behaviors name to
remind you that its still your primary behavior.
For more information on declaring and editing behaviors, see the Declaring a behavior topic.
For more information on specifying an initial behavior, see the CreateEntity and SetBehavior commands in the
Declaring a behavior topic.
Importing a behavior (BTN)
When you save a SimBionic project, four types of files are generated. One has the name of your project followed by an
SBP extension (for SimBionic Project) and contains most of your projects data. The second type has an APD
extension, and it contains your projects action and predicate declarations. The third type has a TPD extension and it
contains enumerated types and classes.
The fourth type of file has the name of a behavior in your project followed by a BTN extension (for Behavioral
Transition Networks, an AI term thats basically a long way of saying behavior), and it contains both the declaration
and Canvas elements that make up that behavior (and all of its polymorphisms). Your project will thus have one BTN
file for each behavior in the project. The BTN files are saved separately to give you the option of loading them into any
other SimBionic project so that you can instantly access already-created behaviors (as opposed to having to recreate
your behaviors in each project from scratch), and also to make it possible for multiple authors to work on the same
project at once (as described in the topic Working with multiple authors).
To copy, or import, the contents of a BTN file from another SimBionic project into your current project, follow these
steps:
30
1.
2.
3.
Use the dialog box to locate the folder containing the BTN file youre after, and then click the file.
The file is displayed in the Filename text box.
4.
project are copied into the Catalog. (Behaviors from the imported file that have the same name as those in
your current project will be ignored to avoid unwanted duplication.)
5.
2.
3.
To rename a Catalog folder, an AP module, or a descriptor on the Descriptors pane, follow these steps:
1.
Right-click the item and select the Rename option from the menu that appears. Either way, the current
name is highlighted.
2.
3.
Right-click the header (e.g., Behaviors, Globals, or Constants) of the Catalog items you want to
organize.
For example, if you want to organize your actions, right-click on an AP module underneath the Actions
header at the top of your list of actions.
2.
Select the New Folder option from the menu that appears.
A yellow folder icon is added below the header youve clicked.
3.
Type a name that represents the sort of data youll be storing in the folder.
For example, if youll be placing actions dealing with combat into the folder, you might name it Combat
Actions.
4.
5.
6.
Repeat Steps 1-5 to create additional folders for storing other conceptually related Catalog items.
Tip #1: If you find you have too many items within a folder, you can further organize them by creating folders
within folders, called subfolders. For example, if you have a Combat Actions folder and want to create a
subfolder devoted to strategies, right-click the Combat Actions folder, select the New Folder option, and type
31
Combat Strategy Actions for the subfolder name. You can then click-and-drag all actions dealing with
combat strategies from the Combat Actions folder to the subfolder youve created.
Tip #2: If a folder becomes obsolete, you can remove it by moving any Catalog items you want to preserve
out of the folder, and then right-clicking the folder and selecting the Delete option. If the folder still contains
any items, youll be prompted to confirm the deletion by clicking a Yes button. After you do so, the folder and
all its contents are permanently removed. The Undo command does not work for Catalog operations, so
always think twice before deleting a folder.
Deleting a Catalog item
You can typically remove a Catalog itemi.e., an action, predicate, AP module, behavior, parameter, global variable,
constant, enumerated type, class, or folderby simply right-clicking it and selecting the Delete option from the menu
that appears. Alternatively, you can click the item to select it and then press the Del key. You can also delete multiple
items from the Catalog at once by holding down the Shift or Ctrl key, selecting the items you want to delete, and then
pressing the Del key.
There are some exceptions to this general rule, however. They are as follows:
Non-empty folders: If a folder contains one or more items (i.e., isnt empty), a dialog box appears asking
you to confirm that you want to delete both the folder and all of its contents. If you click the Yes button, the
folder and its contents are deleted.
Core actions and core predicates: SimBionic provides you with a group of built-in actions and predicates
that are stored in the Catalogs Core AP module (see Core Actions and Core Predicates). These items are
an integral part of SimBionic and can never be deleted. You can identify a core action or predicate by the
tiny "lock" symbol in the upper-left of its icon.
Core classes: SimBionic provides you with a group of built-in classes that are stored in the Catalogs Core
Classes folder. These items are an integral part of SimBionic and can never be deleted.
Main behavior: When you open a new project, SimBionic includes an initial blank behavior called Main that
always remains at the top of your behavior list and is considered your projects starting point. You can revise
the Main label to some other name more appropriate for your project, but you cant delete the behavior.
Tip: If you want to delete an item that youve already used in your project, first remove all references to the item. The
easiest way to accomplish this is to right-click the item in the Catalog, select the Find option, and then locate and
delete each occurrence listed in the Find pane. For more information, see the Searching the Canvas topic.
Warning: SimBionic currently doesnt support undoing a Catalog item deletion. Therefore, always think twice before
deleting any item from the Catalog.
Editing a parameter in the Catalog
One way to edit the parameters for an action, predicate, or behavior is via the Edit dialog for that Catalog item. You
can also edit, delete, or reorder parameters directly in the Catalog, however.
To edit a parameter in the Catalog, follow these steps.
1.
Find the item whose parameters youd like to modify in the Catalog.
2.
Click on the plus sign to its left to expose its parameters if theyre not already visible.
They will be displayed below the item with a pink rectangle icon.
3.
Find the item whose parameter youd like to delete in the Catalog.
2.
Click on the plus sign to its left to expose its parameters if theyre not already visible.
They will be displayed below the item with a pink rectangle icon.
3.
Find the item whose parameters youd like to reorder in the Catalog.
2.
Click on the plus sign to its left to expose its parameters if theyre not already visible.
They will be displayed below the item with a pink rectangle icon.
3.
Right-click on the parameter you wish to reorder and select Move Up or Move Down.
The parameter will be shifted up or down in the parameter list for the Catalog item.
32
An action, represented as a normal rectangle. For more information, see the Creating and editing actions on
the Canvas topic.
A behavior, represented as a boldfaced or double-bordered rectangle. For more information, see the
Creating and editing invoked behaviors topic.
A compound action, represented as two stacked rectangles. For more information, see the Creating and
editing compound actions topic.
A condition, represented as an oval. For more information, see the Creating and editing conditions topic.
A connector, represented as an arrow-like line. For more information, see the Creating a connector topic.
The elements you choose to include, the expressions that you assign them, and the way you decide to connect them
create a flow-chart-like structure on the Canvas that determines how your program will execute.
For example, heres what the Main behavior of the Pac-Man demo (described in the Exploring the sample Pac-Man
program topic) looks like on the Canvas:
This particular behavior is designed as an infinite loop, relying on the C++ code in the game to turn it on and off. More
typically, however, a behavior will include one or more final actionscolored red on the Canvasto terminate it. In
addition, every behavior must designate a particular rectangle (i.e., action or invoked behavior) as its starting point,
which is colored green on the Canvas. For more information, see the Setting a rectangle as initial and Setting an
action as final topics.
You can move, copy, delete, and search for any Canvas element with a few mouse clicks. For more information, see
the Moving a Canvas element, Copying a Canvas element, Deleting a Canvas element, and Searching the Canvas
topics.
You can also attach bindings and comments to Canvas elements. For more information, see the Attaching bindings to
a Canvas element and Commenting on a Canvas element topics.
In addition, you can place text directly on the Canvas to document your behaviors. For more information, see the
Adding text to the Canvas topic.
33
A behavior starts out with a single Canvas page, but you can additional onescalled polymorphismswith a couple of
mouse clicks. For more information, see the Understanding descriptors, Creating and revising descriptors, and
Creating polymorphisms topics.
Tip: If you need to make the Canvas larger or smaller, you can resize it by clicking the View menu and selecting the
Canvas Size option. Alternatively, you can click anywhere along the borders of the Canvas and, while holding down
your mouse button, dragging the border to resize the Canvas. The Project window and Output window will
automatically resize to fit the new amount of space youve allocated to them.
Navigating behaviors
Every behavior in your project can be viewed and edited via the Canvas. Since SimBionic supports only one Canvas,
you cant display more than one behavior at a time. A typical project consists of behaviors frequently invoking other
behaviors, however, which means you need to keep track of how your behaviors are interacting with each other. As a
result, SimBionic provides a number of different ways you can move from one behavior to another quickly and easily.
Specifically, you can use any of the following methods to make the Canvas display the behavior youre seeking:
In the Catalog, double-click the name of the behavior you want to view.
In the Navigate toolbar (directly below the menu bar and in the middle of the window), click in the drop-down
box to display a list of your projects behaviors and then click the name of the behavior you want to view.
In the Navigate toolbar, click the Back button (which looks like an arrow pointing left) to display the previous
behavior; the Forward button (which looks like an arrow pointing right) to display the next behavior; or the
Home button (which looks like a house) to jump to your initial behavior (which is named Main, unless you
chose to revise the default name).
Click the triangle button to the right of the Back or Forward button to drop down a history of your behavior
navigation, and then click the behavior you want to view.
Press Alt+Left Arrow to display the previous behavior (same as clicking the Back button) and Alt+Right
Arrow to display the next behavior (same as clicking the Forward button).
Click the View menu, select the Go option, and then select the Back option to display the previous behavior
or the Forward option to display the next behavior.
Double-click the rectangle of an invoked behavior to display the full behavior on the Canvas.
If youve created polymorphisms, click the tab at the bottom of the Canvas labeled with the combination of
descriptors youre after.
After you perform any of the above actions, the behavior you select is displayed on the Canvas.
Quick-Zoom
If you are working on a large and complex behavior (or your screen resolution is low), you may not be able to see the
whole behavior on the Canvas at one time. While you can always scroll the Canvas to view the rest of the behavior,
this can make it difficult to get a feel for the overall flow of the behaviors logic. The editor thus provides a Quick-Zoom
feature that permits you to zoom out from the Canvas so that you can see the entire behavior at a glance.
To use Quick-Zoom on the behavior that is currently displayed on the Canvas, select the View menu and then QuickZoom. Alternatively, you can hit the F8 key. The editor will instantly switch to a full-screen display of the Canvas that
shows the entire behavior. Clicking on any element in the behavior will restore the editor to the normal view and
reposition the Canvas so that the element you clicked on is in the center of the page. You can also exit Quick-Zoom by
hitting Esc.
Introducing the Canvas Elements
Creating and editing actions on the Canvas
The fundamental building blocks of a SimBionic project are its actions, which determine every step of its execution.
More specifically, an action is a mini-program that performs some small activity to help move your SimBionic program
forward. Examples of actions include making a calculation, sending a message, changing direction, firing a weapon,
etc.
An action consists of three basic components:
The underlying code (typically written in C++ or Java) that makes the action work, which youor a
programmer on your development teammust create and then include as part of your simulation or game.
For more information, see the Coding actions in C++ or Coding actions in Java topic.
The actions declaration in the Catalog, in which you assign the action a name; enter a brief description of
what it does; and enter any parameters the action will use to pass values to SimBionic and/or return values
from SimBionic (based on how the action is programmed to operate in your simulation or game). For more
information, see the Declaring an action topic.
The actions inclusion on the Canvas, which is represented as a rectangle, and tells SimBionic precisely
where in your program you want the action to be triggered.
You can create these three aspects of an action in any order you want. However, if you create an action on the
Canvas that doesnt correspond to an action already declared in the Catalog, your project wont compile properly.
34
Similarly, if you declare an action in the Catalog for which you havent created underlying code, then your program
wont run properly.
An action on the Canvas is itself made up of several components:
A rectangle with a normal border (as opposed to a behavior, which appears on the Canvas as a rectangle
thats either boldfaced or double-bordered).
Optionally, one or more bindings that are attached to the action. For more information, see the Attaching
bindings to a Canvas element topic.
Optionally, a comment and/or reminder thats attached to the action to document its purpose and/or
operation. For more information, see the Commenting on a Canvas element and Placing a reminder on a
Canvas element topics.
To create an action on the Canvas, you must first insert an action rectangle and then edit the rectangle to assign it an
action expression. The next two sections tell you how.
If the action you want has already been declared in the Catalog, click the action in the Catalog and, while
keeping your mouse button held down, drag the action to where you want it on the Canvas, and then
release your mouse button. The action appears on the Canvas as a rectangle that displays the actions
name inside it, followed by parenthesese.g., NextMsg(). If your selected action requires one or more
parameters, then an asterisk appears within the parenthesese.g., CreateBBoard(*)as shown here:
The asterisk is a placeholder indicating that you need to fill in one or more parameters to complete the
expression. To learn more, see the next section, "Editing an action rectangle."
If the action you want hasnt yet been declared in the Catalog, or if you want to create an action that does
nothing, then right-click the blank area of the Canvas where you want to create the action, and then click the
Insert Action option from the menu that appears. The action appears on the Canvas as a blank rectangle, as
shown here:
This is called a None action, and it does nothing except maintain the status quo for a clock tick. Its useful for
when you need to wait for another program event before performing additional actions; you want to devote a
clock tick to do nothing but execute bindings youve attached to the action; or you want to mark the end of a
behavior via a final action (i.e., an action that marks the end of the current behavior, and which must be a
None action with no bindings because execution of the behavior terminates as soon as the final action is
reached). For more information about the latter, see the Setting an action as final topic.
You can always change a None action to a different action, however. To learn more, see the next section,
"Editing an action rectangle."
Note: If the action youve created is the first rectangle in the current behavior, the action appears in green to indicate
its the initial action, i.e., the action SimBionic will execute in the behavior first, as in this example:
Every behavior must contain either an initial action or initial invoked behavior to provide SimBionic with a clear starting
point. However, you can always designate a different rectangle to be the initial one via a couple of mouse clicks. For
more information, see the Setting a rectangle as initial topic.
Tip: You can also create a new action rectangle on the Canvas using the Ctrl-R shortcut.
35
replace the asterisk placeholder with the appropriate parameters. As another example, if youve created the action by
right-clicking the Canvas and want anything other than the default None action, you need to specify the expression
you want to assign to the action.
Alternatively, you may sometimes change your mind about the expression you initially assigned an action. When this
occurs, you can use the same steps to revise the expression that you used to create it.
To edit an action on the Canvas, follow these steps:
1.
At the top is an Expression box that lets you enter the single expression you can assign the action.
Below it is an Action/Behavior List box that reminds you of the actions and behaviors available in your
project, in case you want to use any of them as components of your expression. Clicking an action or
behavior displays its parameters in the box directly below it, reminding you of the syntax needed. Doubleclicking an action or behavior enters its name into the Expression box.
Youre also provided with a Variable List box that lists all the local variables, global variables, and constants
available in your project. Double-clicking a variable or constant enters its name into the Expression box.
If you need to refresh your memory about the meaning of a particular action, behavior, variable, or other
Item in one of the list boxes, simply hover your mouse cursor over its name. After a moment, a tooltip with
the description of that item will appear.
2.
36
Use the Expression box to construct the expression you want to assign to the action.
For example, you can click in the Expression box and simply type the expression directly. Alternatively, you
can use the Action/Behavior List and Variable List boxes to help built an expression; double-clicking any
listed item will copy its name into the Expression box starting at your cursor position.
By default, the items in the list boxes will be filtered so that only those that match the type of the parameter
you are currently editing will be displayed. (If you are not editing a parameter, then all items are displayed.)
If you wish to turn off this filtering, uncheck the Filter by type box below the Variable List.
Tip: When you begin typing the name of an action, behavior, or method in the Expression box, the name is
highlighted in the Action/Behavior List. If you skip the rest of the name and just type a left parenthesis (or hit
the Tab key), SimBionic will understand that you want it to do the typing for you and will automatically enter
the full name of the action or behavior, followed by your left parenthesis. You can then proceed to enter the
necessary parameters (if any) and a right parenthesis to complete the action or behavior.
Similarly, after you begin typing the name of a variable or constant in the Expression box, the name is
highlighted in the Variable List. If you skip the rest of the name and either hit the Tab key or type whatever
operator you want to follow the variable or constant (e.g., + for addition, - for subtraction or negation, / for
division, * for multiplication, ! for Boolean negation, and so onfor more information, see the Using
operators in expressions topic), SimBionic will understand that you want it to do the typing for you and will
automatically enter the full name of the variable or constant, followed by the operator.
3.
Tip #1: You can include multiple copies of an action on the Canvas, which is useful if you wish to specify a variety of
conditions under which the action can be triggered. To learn how to create one or more copies of an action, see the
Copying a Canvas element topic.
Tip #2: You can quickly fill in the unspecified parameters in an action expression without opening the Edit Action
Expression dialog box. To do so, simply drag a global variable or behavior parameter from the Catalog, or a local
variable from the Local Variables palette, onto an action rectangle that contains one or more asterisks in its
expression. The variable will automatically replace the first asterisk in the expression. If all parameters in the
expression are already specified, dragging a variable onto the rectangle will create a new binding for that variable.
Tip #3: You can specify your own label for an action rectangle. For details, see the Changing the label for a Canvas
element topic.
Creating and editing invoked behaviors
A SimBionic program is composed of behaviors, which are subprograms that dynamically determine every decision
made and action performed by the programs entities.
Each behavior is itself composed of four programming constructs:
Actions, which define all the different actions an entity can perform. (For more information, see the Creating
and editing actions on the Canvas topic.)
Other existing behaviors, which can be called up, or invoked, at any point in the current behavior. When
this occurs, SimBionic executes the invoked behavior until its either completed or aborted, and then returns
to executing the original behavior. (For more information, continue reading this topic and also see the
Checking for completed behaviors topic.)
Conditions, which set the conditions under which each action and invoked behavior will happen. (For more
information, see the Creating and editing conditions topic.)
Connectors, which control the order in which conditions are evaluated, and actions and invoked behaviors
take place. (For more information, see the Creating a connector topic.)
These four constructs allow you to program AI behavior that simulates the behavior we experience in the real world.
To create a behavior, you must first declare it in the Catalog, which opens a Canvas window devoted to that behavior.
(For more information, see the Declaring a behavior topic.) You can then insert the elements described above onto the
Canvas window. The types of actions, invoked behaviors, and conditions you include, and how you choose to arrange
them in relation to each other, uniquely define the particular behavior.
As previously indicated, an invoked behavior is an existing behavior that you reference on the Canvas so it will be
executed as part of the behavior currently being created on the Canvas. An invoked behavior is made up of several
components:
A rectangle thats boldfaced or double-bordered (as opposed to an action, which appears on the Canvas as
a rectangle that has a normal border).
An expression that specifies the name of the behavior (i.e., the name with which its declared in the
Catalog).
Optionally, one or more bindings that are attached to the behavior. For more information, see the
Attaching bindings to a Canvas element topic.
Optionally, a comment and/or reminder thats attached to the behavior to document its purpose and/or
operation. For more information, see the Commenting on a Canvas element and Placing a reminder on a
Canvas element topics.
37
To learn how to create and edit invoked behaviors on the Canvas, read the next two sections.
2.
Click the behavior in the Catalog and, while keeping your mouse button held down, drag the
behavior to where you want it on the Canvas, and then release your mouse button.
The behavior appears on the Canvas as a rectangle that displays the behaviors name inside it, followed by
parenthesese.g., DoSomething(), as shown here:
The asterisk is a placeholder indicating that you need to fill in one or more parameters to complete the
expression. To learn more, see the next section, "Editing an invoked behavior."
Note: If the invoked behavior youve created is the first rectangle in the current behavior, it appears in green
to indicate its the initial rectangle, i.e., the rectangle SimBionic will execute in the current behavior first, as in
this example:
Every behavior must contain either an initial action or initial invoked behavior to provide SimBionic with a
clear starting point. However, you can always designate a different rectangle to be the initial one via a
couple of mouse clicks. For more information, see the Setting a rectangle as initial topic.
Tip: You can also create a new empty behavior rectangle on the Canvas using the Ctrl-R shortcut.
38
Press the Ctrl key and, while keeping it held down, double-click the rectangle.
Alternatively, right-click the rectangle and click the Edit Expression option from the menu that appears, or
select the rectangle and press Ctrl-E. You see an Edit Behavior Expression dialog box like this:
At the top is an Expression box that lets you revise the expression representing the behavior.
Below it is an Action/Behavior List box that reminds you of the actions and behaviors available in your
project. Clicking an action or behavior displays its parameters in the box directly below it, reminding you of
the syntax needed.
Youre also provided with a Variable List box that lists all the local variables, global variables, and constants
available in your project. Double-clicking a variable enters its name into the Expression box.
If you need to refresh your memory about the meaning of a particular action, behavior, variable, or other
item in one of the list boxes, simply hover your mouse cursor over its name. After a moment, a tooltip with
the description of that item will appear.
2.
Click in the right end of the Expression box (so that your cursor is placed to the right of the
behaviors closing parenthesis), and then press the Backspace key twice.
The closing parenthesis and asterisk placeholder are erased. At the same time, the appropriate parameters
for the behavior are listed in the Parameters box (at the bottom of the dialog box).
3.
Locate the variable or constant in the Variable List box that corresponds to the first parameter in the
Parameters box, and double-click the variable or constant.
After you double-click, the variable or constant is inserted into the Expression box, starting at your cursor
position. If this is the only parameter the behavior requires, skip to Step 5.
4.
Type a comma to separate the current parameter from the next one; and then locate the variable or
constant in the Variable List box that corresponds to the next parameter in the Parameters box, and
double-click the variable or constant.
Repeat this step until youve inserted all the necessary parameters into the Expression box. Make sure
theres no comma following the last parameter, as commas should appear only between parameters.
5.
39
6.
Tip #1: You can also type expressions directly in the Expression box. If you do so, you can use SimBionics
autocompletion feature to save you keystrokes. See Autocompleting an expression for more information.
Tip #2: You can quickly fill in the unspecified parameters in a behavior expression without opening the Edit Behavior
Expression dialog box. To do so, simply drag a global variable or behavior parameter from the Catalog, or a local
variable from the Local Variables palette, onto a behavior rectangle that contains one or more asterisks in its
expression. The variable will automatically replace the first asterisk in the expression. If all parameters in the
expression are already specified, dragging a variable onto the rectangle will create a new binding for that variable.
Tip #3: You can include multiple copies of an invoked behavior on the Canvas, which is useful if you wish to specify a
variety of conditions under which the behavior can be triggered. To learn how to create one or more copies of an
invoked behavior, see the Copying a Canvas element topic.
Tip #4: You can specify your own label for a behavior rectangle. For details, see the Changing the label for a Canvas
element topic.
Creating and editing compound actions
While SimBionic is designed especially to simplify the authoring of complex conditional logic, sometimes you may find
it necessary to write behaviors that contain linear sequences of action and behavior rectangles without any conditions
at all:
For such cases, SimBionic provides a special compound action construct that enables you to combine multiple action
and behavior invocations into a single rectangle. Creating a compound action is much faster than creating all of the
individual rectangles, and it also has the advantage of making your behavior more compact. The above example as a
compound action would look like this:
Two stacked rectangles (as opposed to a regular action, which appears on the Canvas as a single
rectangle).
Actions to be executed,
Optionally, a comment and/or reminder thats attached to the compound action to document its purpose
and/or operation. For more information, see the Commenting on a Canvas element and Placing a reminder
on a Canvas element topics.
When a compound action is executed, it steps through its list of expressions, executing each one in turn. All of the
expressions in a compound action are executed in a single tick, including any behavior invocations.
Tip: You can also use the Ctrl-M shortcut to create a new compound action on the Canvas.
40
The main portion of the dialog box consists of the Expression list, which displays all of the action
expressions, behavior expressions, and variable bindings that make up the compound action. To the right of
the list box are buttons enabling you to add new expressions, edit or delete existing expressions, and
reorder the list.
2.
3.
4.
Click Ok.
The dialog box will close, and your expression will be added to a new row at bottom of the Expressions list
box. Note that the Value column for this expression will display "(Action)" to indicate that it is not a variable
binding.
Tip: You can quickly add a new action or behavior expression to a compound action without opening the Edit
Compound Action dialog box. To do so, simply drag the desired action or behavior from the Catalog onto the
compound action, and a new expression will be added. The parameters of the new expression, if any, will be filled with
asterisk placeholders.
3.
41
See Attaching bindings to a Canvas element for more on creating variable bindings.
4.
Click Ok.
The dialog box will close, and your binding will be added to a new row at bottom of the Expressions list box.
The Value column will display the name of the bound variable, and the Expression column will list the
expression for the binding.
Tip: You can quickly add a new variable binding to a compound action without opening the Edit Compound Action
dialog box. To do so, simply drag the variable you wish to bind from the Catalog or Local Variables palette onto the
compound action, and a new empty binding will be added. Note that this will only work if all of the action and behavior
expressions in the compound action are completely specified (i.e., they contain no asterisk parameters).
Editing expressions
If you change your mind about any expression youve created in a compound action, you can revise it quickly and
easily by following these steps:
1.
2.
Click the expression you want to change in the Expressions list box.
The row is highlighted to show that its selected.
3.
4.
5.
Tip: You can quickly fill in the unspecified parameters in an action expression within a compound action without
opening the Edit Action Expression dialog box. To do so, simply drag a global variable or behavior parameter from the
Catalog, or a local variable from the Local Variables palette, onto a compound action rectangle that contains one or
more asterisks in its expressions. The variable will automatically replace the first asterisk in the expressions. If all
parameters in the expressions are already specified, dragging a variable onto the rectangle will create a new binding
for that variable.
Deleting expressions
If an expression ever becomes obsolete, you can quickly remove it from the compound action by following these
steps:
1.
2.
3.
4.
Optionally repeat Steps 2-3 to delete any other expressions that have become obsolete.
5.
Tip: If you change your mind about a deletion before you click the dialog boxs OK button, simply click the Cancel
button; all the revisions youve just made via the dialog box will be discarded. Alternatively, if you change your mind
after clicking the OK button, click the Edit menu and select the Undo option, or press Ctrl+Z; the changes youve just
made to the compound action will be reversed.
Reordering expressions
If you dont like the order in which expressions are displayed in the compound action, you can rearrange them. This
can have an effect on the execution of your behavior, since the expressions are evaluated in the order that you
specify. Remember that variable bindings can refer to variables bound by earlier bindings in the list!
To reorder expressions, follow these steps:
42
1.
2.
3.
Click the Up button or Down button (depending on the direction in which you want to move the
expression).
The expression shifts by one position in the list.
4.
Repeat Steps 2-3 until the expression is precisely where you want it to appear on the list.
5.
6.
Tip: You can specify your own label for a compound action rectangle. For details, see the Changing the label for a
Canvas element topic.
Setting a rectangle as initial
Every behavior in SimBionic must contain a particular action or invoked behavior thats designated as its initial
rectanglei.e., the rectangle that SimBionic will go to first when its instructed to begin executing the behavior. This
rectangle is marked as initial by being colored green, as in this example:
A behavior can have no less and no more than a single starting point. Therefore, precisely one green rectangle must
appear in any behavior.
SimBionic automatically makes the first action or behavior you create in a behavior the initial rectangle. However, you
can always designate a different rectangle to be the initial one with a couple of mouse clicks. To accomplish this,
follow these steps:
1.
2.
Click the action or invoked behavior you want to designate as the initial rectangle.
The rectangle is highlighted to indicate that its selected.
3.
Click the Initial button in the upper-right of the SimBionic editor window (the button that looks like a
small green rectangle).
Alternatively, right-click the rectangle and select the Initial option from the menu that appears.
Your specified action or invoked behavior turns green to indicate that its now the current behaviors initial
rectangle. At the same time, the previous initial rectangle turns white to indicate that its no longer the initial
rectangle.
Note #1: Before you can designate a rectangle to be initial, you must be able to create actions and invoked behaviors
on the Canvas. To learn how to do so, see the Creating and editing actions on the Canvas and Creating and editing
invoked behaviors topics.
Note #2: In addition to designating a starting point for a behavior, you must designate at least one endpoint for the
behavior. To learn more, see the Setting an action as final topic.
Setting an action as final
As explained in the previous topic, Setting a rectangle as initial, every behavior in SimBionic must contain precisely
one starting point.
A behavior can also contain one or more actions that are designated as a final actioni.e., an action that marks the
end of the behavior and terminates its execution.
While a behavior can have only one initial rectangle, it can contain an unlimited number of final actionsi.e., the
behavior must always start the same way, but it doesnt have to always end the same way. You can insert multiple
final actions to create a variety of execution paths leading to the behaviors termination.
Similarly, while a behavior must have an initial rectangle, it doesnt necessarily require a final action. If you create a
behavior with no endpoint, the behavior will execute in a continuous loop until terminated by your controlling simulation
or game. You may find this is actually the best approach for your projects top-level behavior, since its this primary
behavior that keeps your SimBionic program running.
That said, its generally most efficient to have lower-level behaviors terminate themselves via final actions. Further, if
you set a behavior to execute in one tick, then you must terminate the behavior via a final action; otherwise, the
behavior will execute nonstop within a never-ending clock tick that ultimately freezes your program.
When SimBionic encounters a final action, it doesnt attempt to evaluate the action, but simply accepts it as a "stop
sign" and immediately ends the behaviors execution. As a result, a final action must:
43
Have no expression assigned to it. This is indicated by the word None appearing on the actions
rectangle. Any expression would be superfluous, because a final action cant do anything other than
terminate execution.
Have no bindings attached. Since SimBionic ends execution upon encountering the action, the bindings
would be ignored anyway.
Be explicitly designated as a final action. This is accomplished via the Final button in the upper-right of
the editor window. After an action is designated as final, it appears as red on the Canvas.
Move to the behavior for which you want to create one or more endpoints.
If you arent sure how to do this, see the Navigating behaviors topic. After you move to the behavior, its
displayed on the Canvas.
2.
3.
4.
Click the Final button in the upper-right side of the SimBionic editor window (the button that looks
like a small red rectangle).
Alternatively, right-click the action and select the Final option from the menu that appears. The action turns
red to indicate that its now a final action.
5.
When youre done creating your final action(s), use one or more connectors to hook each final action into your
program (following the directions in the Creating a connector topic). However, make sure that connectors only lead
into any final action. No connector should emerge from a final action, because execution can never flow out of an
endpoint.
Tip: You can alternatively designate an existing action to be a final action. To do so, first remove any expressions
and/or bindings attached to the action; and then right-click the action and select the Final option from the menu that
appears. The action turns red to indicate that its been converted to a final action.
Creating and editing conditions
The primary building blocks of a SimBionic project are its actions and behaviors, which move execution forward.
However, your program must continually test various aspects of your simulated world to determine if and when to
trigger a particular action or behavior. These tests are called conditions, because each one is used to check whether
the right conditions exist for a certain action or behavior to take place. For example, a condition might check whether a
weapon has run out of ammunition, an entity has messages waiting, a behavior has finished executing, and so on.
A condition is made up of several components:
Optionally, one or more bindings that are attached to the condition. For more information, see the
Attaching bindings to a Canvas element topic.
Optionally, a comment and/or thats attached to the condition to document its purpose and/or operation.
For more information, see the Commenting on a Canvas element and Placing a reminder on a Canvas
element topics.
You can create a condition by first either dragging a predicate from the Catalog to the Canvas, or right-clicking the
Canvas and selecting Insert Condition from the menu that appears. In either case, an oval is inserted on the Canvas.
44
You can then double-click the oval to insert precisely one expression that results in a value of either true or false. Your
conditions expression can consist of variables, static values (e.g., numbers, strings, constants), operators, andmost
importantlypredicates, which are mini-programs that probe the status of various aspects of your SimBionic program.
Predicates and conditions are related in function, but they arent identical. A couple of key differences between
predicates and conditions are:
Before using a predicate, you must create underlying code for it in your simulation or game, and also
declare it in the Catalog. (For more information, see the Coding predicates in C++ or Coding predicates in
Java topic, and the Declaring a predicate topic.) To use a condition, you simply create it on the Canvas and
then enter into it whatever predicates, variables, static values, and operators are necessary to create the
expression you require. In other words, predicates are building blocks that you use to construct conditions.
A predicate can return one or more results consisting of any value(s), while a condition can only evaluate as
either true or false. For example, if X=1 and there are 5 members in the group GoodGuys, then a condition
with the expression X<NumMembers("GoodGuys") will evaluate as true, while a condition with the
expression X==NumMembers("GoodGuys") or X>NumMembers("GoodGuys") will evaluate as false. (For
more information, see the Understanding expressions and Using operators in expressions topics.)
If a condition evaluates as true, your SimBionic program will flow down the path directly following the condition; while if
the condition evaluates as false, your program will flow to the next available path. In either case, the next path can be
an action or behavior, which will then execute; or can be another condition, which will then in turn be evaluated.
You can set up a series of conditions that directly follow each other, in which case theyll all have to be true before the
rectangle they lead to can execute, as in this example:
Alternatively, you can set up a series of conditions on the same level that all stem directly from the same action or
behavior, in which case the action or behavior that executes will be the first one whose condition evaluates as true
(equivalent to an IF-THEN-ELSE statement in C++), as in this example:
45
If none of the conditions turn out to be true, SimBionic will stay within the originating action or behavior and evaluate
its conditions again during the next clock tick; and will repeat this cycle until at least one of the conditions coming out
of the action or behavior is true, allowing execution to flow forward. (For more information, see the Understanding
SimBionic's flow of execution topic.)
The next two sections detail how to insert a conditions oval on the Canvas and then assign it an expression.
If you want your condition to include a predicate thats been declared in the Catalog, click the predicate in
the Catalog and, while keeping your mouse button held down, drag the predicate to where you want it on the
Canvas, and then release your mouse button. The condition appears on the Canvas as an oval that displays
the predicates name inside it, followed by parenthesese.g., IsMsg(). If your selected predicate requires
one or more parameters, then an asterisk appears within the parenthesese.g., NumMembers(*)as
shown here:
The asterisk is a placeholder indicating that you need to fill in one or more parameters to complete the
expression. To learn more, see the next section, "Editing a condition."
Tip: You can alternatively create a condition that logically negates an existing predicate (i.e., converts a
returned Boolean value of true to false, or false to true). To do so, press the Ctrl key and, while keeping it
held down, drag the predicate (e.g., IsDone) from the Catalog to the Canvas. After you release your mouse
button, a condition is inserted with an expression that begins with the negation symbol (!) directly followed
by the predicate name (e.g., !IsDone()).
If the predicate youre after hasnt yet been declared in the Catalog, or if you simply want to create a
condition that doesnt use any predicates (i.e., thats based solely around static values and/or variables
interacting via operators), then right-click the blank area of the Canvas where you want to create the
condition, and then click the Insert Condition option from the menu that appears. The condition appears on
the Canvas as a blank oval, as shown here:
The blank oval is a reminder that your condition is currently empty and you need to assign it an expression.
To do so, see the next section.
Note: You can also create a new condition oval on the Canvas using the Ctrl-K shortcut.
Editing a condition
After youve created a condition on the Canvasthat is, inserted an oval to represent ityou typically need to edit the
conditions expression. For example, if you dragged a predicate that requires parameters from the Catalog, you have
to replace the asterisk placeholder with the appropriate parameters; while if youve created the condition by rightclicking the Canvas, the condition initially contains no expression at all and must be assigned one.
46
You may also sometimes change your mind about the expression you initially assigned a condition. When this occurs,
you can use the same steps to revise the expression that you used to create it.
To edit a condition, follow these steps:
1. Double-click the conditions oval.
Alternatively, right-click the oval and click the Edit Expression option from the menu that appears. You see
an Edit Condition Expression dialog box like this:
At the top is an Expression box that lets you enter the single expression you can assign the condition.
Below it is a Predicate List box that reminds you of the predicates available in your project, in case you want
to use any of them as components of your expression. Clicking a predicate displays its parameters in the
box directly below it, reminding you of the predicates syntax. Double-clicking a predicate enters its name
into the Expression box.
Youre also provided with a Variable List box that lists all the local variables, global variables, and constants
available in your project. Double-clicking a variable or constant enters its name into the Expression box.
If you need to refresh your memory about the meaning of a particular variable, predicate, or constant, simply
hover your mouse cursor over its name in the list box. After a moment, a tooltip with the description of that
item will appear.
2.
Use the Expression box to construct the expression you want to assign to the action.
For example, you can click in the Expression box and simply type the expression directly. Alternatively, you
can use the Predicate List and Variable List boxes to help built an expression; double-clicking any listed item
will copy its name into the Expression box starting at your cursor position.
By default, the items in the list boxes will be filtered so that only those that match the type of the parameter
you are currently editing will be displayed. (If you are not editing a parameter, then all items are displayed.)
If you wish to turn off this filtering, uncheck the Filter by type box below the Variable List.
47
Tip: When you begin typing the name of a predicate or method in the Expression box, the name is
highlighted in the Predicate List. If you skip the rest of the name and just type a left parenthesis (or hit the
Tab key), SimBionic will understand that you want it to do the typing for you and will automatically enter the
full name of the predicate, followed by your left parenthesis. You can then proceed to enter the necessary
parameters (if any) and a right parenthesis to complete the predicate.
Similarly, after you begin typing the name of a variable or constant in the Expression box, the name is
highlighted in the Variable List. If you skip the rest of the name and either hit the Tab key or type the
operator you want to follow the variable or constant (e.g., + for addition, - for subtraction or negation, / for
division, * for multiplication, ! for Boolean negation, and so onfor more information, see the Using
operators in expressions topic), SimBionic will understand that you want it to do the typing for you and will
automatically enter the full name of the variable or constant, followed by the operator.
3.
Tip #1: You can set a condition to evaluate as false using any of SimBionics supported data types. Specifically, for
the Boolean data type, use either the value 0 (zero) or any expression that evaluates as false; for the integer and float
data types, use the value 0; for the vector data type, use the value [0,0,0]; and for the string data type, use the value ""
(i.e., an empty string).
In addition, SimBionic supports three data types that can generate false values with the help of predicates.
Specifically, the NullData predicate will return a result of false for a value of type data; the NullEntityID predicate will
return a result of false for a value of type entity; and the IsValid predicate will return a result of false when passed a
value of type invalid. For more information, see the Choosing a data type and Understanding the core predicates
topics.
Tip #2: You can quickly fill in the unspecified parameters in a condition expression without opening the Edit Condition
Expression dialog box. To do so, simply drag a global variable or behavior parameter from the Catalog, or a local
variable from the Local Variables palette, onto a condition oval that contains one or more asterisks in its expression.
The variable will automatically replace the first asterisk in the expression. If all parameters in the expression are
already specified, dragging a variable onto the oval will create a new binding for that variable.
Tip #3: You can include multiple copies of a condition on the Canvas, which is useful if you wish to probe your
programs status in the same way at multiple points of your program. To learn how to create one or more copies of a
condition, see the Copying a Canvas element topic.
Tip #4: You can specify your own label for a condition. For details, see the Changing the label for a Canvas element
topic.
Creating a connector
To construct a SimBionic program on the Canvas, you use actions and behaviors, represented as rectangles; and
conditions, represented as ovals. To indicate how these elements interact with each other, however, you must also
use connectors, each of which is represented as a line leading from one Canvas element to another. These lines
specify the paths your program will follow when executing.
To create a connector, simply click the Canvas element from which you want the connector to originate; press the Ctrl
key and, while keeping it held down, drag your mouse to the Canvas element where you want the connector to
terminate; and release your mouse button.
Tip: Alternatively, you can click the Connector toolbars "+" button (which has the same effect as holding down the Ctrl
key), and then drag your mouse from the originating Canvas element to the target Canvas element.
After youre done, an arrow-like line appears that connects the two elements, with its originating point colored green,
and its terminating point colored red and pointing to the second element. (Note: If youve connected a line improperly,
one or both of its ends will display as yellow instead of green or red. If this happens, delete the connector and try
again.) When you click anywhere outside of the connector, its endpoint colors will disappear, because theyre
displayed only while the connector is selected.
You can create as many connectors between two Canvas elements as you want. This isnt a relevant option if your
first connector leads to an action or behavior, because your program will always flow directly to that rectangle, execute
it, and then continue flowing beyond the rectangle (equivalent to sequential execution, i.e., one line of code following
another).
If your first connector leads to a condition, however, your program will flow beyond the condition only if the condition
evaluates as true. Otherwise, if you have other connectors attached, your program will flow to the next connector, and
the cycle will repeati.e., if the second connector leads to an action or behavior, your program will execute it and then
continue flowing beyond the rectangle; while if it leads to a condition, the condition will be evaluated, and execution will
flow beyond it only if the condition is true. Otherwise, the program will flow to a third connector, if it exists; and so on.
(In other words, a set of connectors leading to conditions operates like an IF-THEN-ELSE statement.) This continues
until either your program encounters a rectangle; a condition evaluates as true; or there are no more connectors left.
In the latter case, the flow of execution remains within the originating rectangle for a clock tick, and your program then
tries the connectors one by one again during the next clock tick. (Specifically, if the rectangle is a behavior that hasnt
been completed, the behavior will continue executing during the next clock tick, and then its connectors will be
checked again; while if the rectangle is an action, or is a behavior that has been completed, then no execution will take
48
place in the rectangle during the next clock, but its connectors will still be checked again. For more information, see
the Understanding SimBionic's flow of execution topic.) This cycle continues until execution can proceed beyond one
of the connectors originating from the current rectangle.
Tip: If youd prefer that an action continue being executed over and over until one of its current connectors evaluates
as true (as opposed to doing nothing after the first clock tick), you can add a last connector that leads back to the
rectangle. To do so, press the Ctrl key and, while keeping it held down, click the rectangle and drag your mouse
outward until you see a green starting point, and then drag your mouse back to the rectangle until you see a red
endpoint. When you release your mouse button, the connector curves to both begin and end in the rectangle.
When you create multiple connectors, SimBionic automatically assigns and displays a priority number (1, 2, 3) for
each of them based on the order in which you made them. However, you can revise any connectors priorityi.e.,
change the order in which your program will flow to itby right-clicking the connector and selecting a different priority
number. For more information, see the Changing a connectors priority topic.
Tip: If you arent sure which connectors originate from a particular rectangle, click the rectangle to select it; all of its
connectors are displayed in green. Click anywhere outside of the rectangle to return its connectors to their default
color of black.
Labeling a connector
If the purpose of a connector (or any other Canvas element) isnt apparent, you can document it by adding a comment
as described in the Commenting on a Canvas element topic.
The first Elbow button is named Counter-Clockwise and looks like an L with an arrowhead at its bottom. The second
Elbow button is named for Clockwise and looks like a mirror image of the first Elbow button. Clicking either button will
change the shape of your selected connector, allowing it to be seen more easily. However, the connectors originating
point and termination point will remain the same.
You should use the Elbow buttons to change the shape of as many connectors are necessary to clarify the layout of
your connectors, in order to ensure that the logic of your program can be seen at a glance.
If you later want to revert a connector to its previous "non-elbow" shape, simply select it again and click the Straight
button (directly to the left of the Elbow buttons).
Creating an interrupt
If a connector coming out of an interruptible behavior leads to a condition that evaluates as true, then SimBionic will
normally abort the behavior on the spot and redirect execution flow to the rectangle (i.e., action or behavior) directly
following the condition.
However, if you dont want the original behavior to be abandoned but just temporarily suspended while the second
behavior executes, you can designate the connector coming out of the behavior to be an interrupt connector. When
the behavior following such a connector is triggered, it takes temporary control of execution until its done its job, and
then returns execution to the original behavior so it can pick up where it left off.
To create an interrupt connector, simply right-click the connector you want to affect and select the Interrupt option from
the menu that appears; or click the connector to select it and then click the Interrupt button, which is directly to the
right of the Elbow buttons. The connector changes from a normal line to a broken line to indicate its now set to
interrupt the current behavior (as opposed to abort it). If you later change your mind, you can select the Interrupt
option again or click the Interrupt button again to revert the connector to its normal state.
Important Note: The behavior at the end of the interrupt connector must end in a final action. Otherwise, the
interrupting behavior will never be able to return control to the original behavior, and your program will freeze.
To learn how to set a behavior to be interruptible or non-interruptible, see the Declaring a behavior topic; to learn more
about why and how behaviors can be aborted, see the Checking for completed behaviors topic; and to learn how to
create a final action, see the Setting an action as final topic.
As with any other Canvas element, you can attach bindings to a connector. For more information, see the Attaching
bindings to a Canvas element topic.
Changing a connectors priority
Every element that appears on your Canvasi.e., every action and behavior, represented as a rectangle; and every
condition, represented as an ovalmust be linked to some other Canvas element via at least one connector. The
connector is represented as a line originating from one element and terminating in another, and specifies the path your
program will follow when executing.
49
You arent restricted to just one connector originating from a Canvas element, however; you can have as many
connectors coming out of the element as you want, providing for a number of different possible execution paths.
When using multiple connectors, your first connector should always lead to a condition; and your program will flow
beyond it only if the condition evaluates as true. Otherwise, your program will flow to the next connector. If this
connector leads to an action or condition, your program will simply execute the rectangle and move forward.
Otherwise, if the connector leads to another condition, your program will again flow beyond it only if the condition
evaluates as true. If it doesnt, your program repeats the cycle by checking on the next connectorin other words,
operating like an IF-THEN-ELSE statement. This process continues until either your program encounters a rectangle;
a condition evaluates as true; or there are no more connectors left. (In the latter case, your program returns to the
originating element and then tries the connectors one by one again during the next clock tick. For more information,
see the Understanding SimBionic's flow of execution topic.)
Because execution will flow down the first connector that isnt blocked by a false condition, the order in which your
program checks a group of connectors can be critical. For this reason, SimBionic gives each connector a priority
number (displayed next to each line on the Canvas as 1, 2, 3, etc.) that sets which connector originating from the
same element will be checked first, second, third, and so on.
SimBionic assigns these priority numbers based on the order in which you create the connectorse.g., the third
connector you make originating from a particular element is automatically designated Priority 3. However, you can
revise these priorities at any time to specify the precise order in which you want your connectors evaluated.
To change a connectors priority, follow these steps:
1.
2.
3.
After you change a connectors priority, the other connectors coming out of the same rectangle are renumbered
accordingly.
For example, if a Canvas element has two connectors originating from iti.e., a Priority 1 and Priority 2 connector
and you change the Priority 1 connector to Priority 2, then the other connector is automatically changed to Priority 1.
Similarly, if you change the Priority 2 connector to Priority 1, then the other connector is automatically changed to
Priority 2.
If there are more than two connectors coming out of a Canvas element, incrementing s a connector causes it to swap
priorities with the connector directly following it in priority. For example, if theres a group of four connectors and you
change the Priority 1 connector to Priority 2, then the Priority 2 connector automatically changes to Priority 1; but the
Priority 3 and 4 connectors remain unchanged. Similarly, if you change the Priority 2 connector to Priority 3, then the
Priority 3 connector automatically changes to Priority 2, while the Priority 1 and 4 connectors remain unchanged.
Along the same lines, decrementing a connector causes it to swap priorities with the connector directly preceding it in
priority. For example, if theres a group of four connectors and you change the Priority 2 connector to Priority 1, then
the Priority 1 connector automatically changes to Priority 2; but the Priority 3 and 4 connectors remain unchanged.
Alternatively, if you make a larger change, then more connectors are automatically renumbered. For example, if you
have a group of five connectors and you reassign the Priority 5 connector to Priority 1, the priority number of each of
the other connectors in the group is increased by one to accommodate the changei.e., the former Priority 1
connector becomes Priority 2, Priority 2 becomes Priority 3, Priority 3 becomes Priority 4, and Priority 4 becomes
Priority 5.
Managing Canvas Elements
Copying a Canvas element
Its sometimes more efficient to make copies of Canvas elementsi.e., behaviors, actions, conditions, and connectors
than to create them from scratch.
For example, if youve attached 10 bindings to an action and then need a second action with virtually the same
bindings, you can simply copy the first action and then edit the copys bindings.
As another example, if youre creating a polymorphism thats similar to an existing behavior, you can select all the
Canvas elements in the existing behavior; insert a copy of the entire behavior into your new polymorphism window;
and then revise the behavior as needed.
To copy a single Canvas element, follow these steps:
1.
50
Right-click the Canvas element you want to copy, and select the Copy option from the menu that
appears.
Alternatively, click the element to select it; and then either click the Edit menu and select the Copy option, or
press Ctrl+C. A copy of the element is stored in the (invisible) Windows clipboard, while the original element
is unaffected.
2.
Right-click the spot on the Canvas where you want to insert the copy, and click the Paste option
from the menu that appears.
The copy is inserted at the spot you clicked.
Tip: If you dont care where the copy is inserted, you can alternatively click the Edit menu and select the
Paste option, or press Ctrl+V. The copy will appear slightly down and to the right of the original element.
3.
Optionally repeat Step 2 to add more copies of the element to the Canvas.
You can insert as many additional copies as you like. The Windows clipboard will continue to store the copy
of the element until you replace it with some other data (by using either the Copy command again or the Cut
command).
Tip #1: Because a copied Canvas element is placed into the Windows clipboard, you can paste the element into any
Windows program, not just SimBionic. For example, if you need to create a report about your SimBionic project, you
can copy & paste Canvas elements into your word processor.
Tip #2: You can alternatively copy a rectangle or oval by pressing Ctrl+Shift and, while keeping those keys held down,
clicking and dragging to a different spot on the Canvas. The original rectangle or oval remains unchanged, but a copy
of it appears on the Canvas as you drag.
To copy multiple Canvas elements, follow these steps:
1.
While holding down the Ctrl key, click each element you want to copy until all the relevant elements
are selected.
Alternatively, if you want to copy everything on the Canvase.g., so you can insert a copy of the current
behavior into a new polymorphism windowclick the Edit menu and select the Select All option, or press
Ctrl+A. After you do so, the entire behavior on the Canvas is selected.
2.
Click the Edit menu and select the Copy option, or press Ctrl+C.
A copy of the group of elements is stored in the (invisible) Windows clipboard. The original elements are
unaffected.
3.
Right-click the spot on the Canvas where you want to insert the copy, and click the Paste option
from the menu that appears.
The copy is inserted at the spot you clicked.
Tip: If youre copying an entire behavior, first click the Canvas tab representing your new polymorphism, and
then press Ctrl+V. The behavior is inserted into your new window. You can now revise it to reflect the
differences in your polymorphismwhich will typically be much faster and easier than recreating the
behavior from scratch.
4.
Optionally repeat Step 3 to add more copies of the group of elements to the Canvas.
You can insert as many additional copies as you like. The Windows clipboard will continue to store the copy
of the group of elements until you replace it with some other data (by using either the Copy command again
or the Cut command).
Right-click the Canvas element you want to move, and click the Cut option from the menu that
appears.
Alternatively, click the element to select it; and then either click the Edit menu and select the Cut option, or
press Ctrl+X. A copy of the element is stored in the (invisible) Windows clipboard, while the original element
is unaffected.
2.
Switch to the Canvas window where you want to move the element.
For example, if you want to move the element to a polymorphism window, click the Canvas tab of the
appropriate polymorphism.
3.
Right-click the spot on the Canvas where you want to insert the element, and click the Paste option
from the menu that appears.
The copy of the element is inserted at the spot you clicked. At the same time, the original element is deleted
51
from the previous window (as youll see whenever you return to that window).
Tip: If you dont care where the element is inserted, you can alternatively click the Edit menu and select the
Paste option, or press Ctrl+V.
4.
Optionally repeat Step 3 to add more copies of the element to the Canvas.
You can insert as many additional copies as you like. The Windows clipboard will continue to store the copy
of the element until you replace it with some other data (by using either the Cut command again or the Copy
command).
Tip: Because a cut Canvas element is placed into the Windows clipboard, you can paste the element into any
Windows program, not just SimBionic. For example, if you need to create a report about your SimBionic project, you
can paste Canvas elements into your word processor.
To move multiple Canvas elements to a different window, follow these steps:
1.
While holding down the Ctrl key, click each element you want to copy until all the relevant elements
are selected.
Alternatively, if you want to move everything on the Canvase.g., so you can insert the current behavior
into a new polymorphism windowclick the Edit menu and select the Select All option, or press Ctrl+A. After
you do so, the entire behavior on the Canvas is selected.
2.
Click the Edit menu and select the Cut option, or press Ctrl+X.
A copy of the group of elements is inserted in the (invisible) Windows clipboard. The original elements are
unaffected.
3.
Switch to the Canvas window where you want to move the group of elements.
For example, if you want to move the elements to a polymorphism window, click the Canvas tab of the
appropriate polymorphism.
4.
Right-click the spot on the Canvas where you want to insert the elements, and click the Paste option
from the menu that appears.
The copy of the group of elements is inserted at the spot you clicked. At the same time, the original
elements are deleted from the previous window (as youll see whenever you return to that window).
Tip: If you dont care where the elements are inserted, you can alternatively click the Edit menu and select
the Paste option, or press Ctrl+V.
5.
Optionally repeat Step 4 to add more copies of the elements to the Canvas.
You can insert as many additional copies as you like. The Windows clipboard will continue to store the copy
of the group of elements until you replace it with some other data (by using either the Cut command again or
the Copy command).
52
1.
If the item you want to find isnt already visible in the Catalog or Local Variables palette, display it.
For example, if youre seeking a local variable, click the Locals button to open the Local Variables palette;
while if youre seeking a core action, double-click the Actions header and Core AP module in the Catalog
until the core actions are displayed.
2.
3.
4.
Double-click an item listed in the Find pane that you want to review and/or edit.
The Canvas window that contains the item is displayed, and the item is highlighted so that you can spot it
easily.
5.
6.
Optionally repeat Steps 4-5 to review and/or edit another item listed in the Find pane.
Repeat this step until youve dealt with all pertinent occurrences of what youre seeking.
7.
Optionally repeat Steps 2-6 to review and/or revise all instances of another Catalog item or local
variable that appears in one or more Canvas windows of your project.
Repeat this step until youve gathered the information you required and/or completed making the necessary
changes.
This method of searching for and revising items on the Canvas is especially useful after youve compiled your project
and discovered errors in a declared variable, action, predicate, constant, or invoked behavior. The Find option helps
you locate and fix the problems quickly and easily.
Click the Edit menu and select the Find option, or press Ctrl+F.
A Find dialog box like this appears:
The dialog box consists of a Find what box into which you type the text you want to locate. This text can be
anything on the Canvas, including variable names; action, predicate, or invoked behavior names; or parts of
parameters, expressions, or bindings.
In addition, it includes a Match whole words only option that, when turned on, makes SimBionic ignore
occurrences where your text is part of a larger word. (For example, if youre searching for end and the option
is turned on, then text such as bookend and endurance would be ignored.)
The dialog box also includes a Match case option that, when turned on, makes SimBionic ignore
occurrences that dont have the same upper-case and lower-case lettering as your text. (For example, if
youre searching for end and the option is turned on, then text such as End and enD would be ignored.)
The default is for both Match options to be turned off, which allows SimBionic to locate and display as many
occurrences matching your text as possible.
53
In addition, the dialog box allows you to specify whether the replace operation should affect all behaviors, or
only the behavior currently visible on the Canvas.
Finally, the dialog box contains a Find button you can click to execute the search youve specified; and a
Cancel button you can click to abort the search.
2.
Type the text you want to locate on the Canvas into the Find what box.
If highlighted text appears in the Find what box from a previous search, your typing replaces the old text. If
you make a mistake while typing, use the Backspace or Del key to fix the error.
3.
If you want to narrow your search results to whole word instances, click Match whole word only to
turn the options checkmark on.
4.
If you want to narrow your search results to exact upper-case and lower-case matches, click Match
case to turn the options checkmark on.
5.
If you want to only search the behavior currently displayed on the Canvas, select Find in selected
behavior.
If you would prefer to search across all behaviors in the project, leave the default option Find in all behaviors
selected.
6.
7.
Double-click an item listed in the Find pane that you want to review and/or edit.
The Canvas window that contains the item is displayed, and the item is highlighted so that you can spot it
easily.
8.
9.
Optionally repeat Steps 7-8 to review and/or edit another item listed in the Find pane.
Repeat this step until youve dealt with all pertinent occurrences of what youre seeking.
10. Optionally repeat Steps 1-9 to locate all instances of another bit of text you want to review and/or
edit in your project.
Repeat this step until youve gathered the information you required and/or completed making the necessary
changes.
This method of searching for and revising items on the Canvas is especially useful after youve compiled your project
and discovered errors in an expression or binding; the Find option helps you locate and fix the problems quickly and
easily.
Note: Find will not search text annotations that youve placed directly on the Canvas using the Add text tool.
Tip: If you edit a Canvas element youve found and then decide shortly afterward that your revisions were a mistake,
you can typically reverse your changes with a few mouse clicks. For more information, see the Undoing your most
recent change(s) topic.
Replacing text in behaviors
If you need to change all instances of a particular local variable, global variable, constant, action, predicate, invoked
behavior, expression, or binding on the Canvasfor example, because youve decided to change a variables name,
or because youve detected an error in a Canvas element that you need to fix across multiple behaviorsscrolling
through the Canvas to visually locate and edit each occurrence of what youre after can take a long time, particularly if
your project is large and complex. In addition, relying on your eye alone risks overlooking elements semi-buried within
some corner of the Canvas.
As a result, SimBionic includes a Replace option that searches for whatever text you specify and allows you to
automatically replace occurrences of that text in your projects expressions and bindings.
To replaces occurrences of any text that appears in a behaviors expressions or bindings, follow these steps:
1.
54
Click the Edit menu and select the Replace option, or press Ctrl+H.
A Replace dialog box like this appears:
The dialog box provides a Find what box into which you type the text you want to locate. This text can be
anything on the Canvas, including variable names; action, predicate, or invoked behavior names; or parts of
parameters, expressions, or bindings. It also provides a Replace with box where you specify the text that
should replace each occurrence of the Find what text.
In addition, the dialog box includes a Match whole words only option that, when turned on, makes SimBionic
ignore occurrences where your text is part of a larger word. (For example, if youre searching for end and the
option is turned on, then text such as bookend and endurance would be ignored.)
It also includes a Match case option that, when turned on, makes SimBionic ignore occurrences that dont
have the same upper-case and lower-case lettering as your text. (For example, if youre searching for end
and the option is turned on, then text such as End and enD would be ignored.)
The default is for both Match options to be turned off, which allows SimBionic to locate and display as many
occurrences matching your text as possible.
In addition, the dialog box allows you to specify whether the replace operation should affect all behaviors, or
only the behavior currently visible on the Canvas.
Finally, the dialog box has several buttons you can use to guide the replace operation youve specified; and
a Cancel button you can click to abort the operation.
2.
Type the text you want to replace into the Find what box.
If highlighted text appears in the Find what box from a previous search, your typing replaces the old text. If
you make a mistake while typing, use the Backspace or Del key to fix the error.
3.
Type the new text that you want to replace the text from Step 2 into the Replace with box.
4.
If you want to limit your replacements to whole word instances, click Match whole word only to turn
the options checkmark on.
5.
If you want to limit your replacements to exact upper-case and lower-case matches, click Match case
to turn the options checkmark on.
6.
If you want to only replace text within the behavior currently displayed on the Canvas, select
Replace in selected behavior.
If you would prefer to replace the text across all behaviors in the project, leave the default option Replace in
all behaviors selected.
7.
If you would like to quickly replace all occurrences of the Find what text without checking them,
click the Replace All button.
Every occurrence of the text youve entered fitting the matching criteria youve selected will be replaced by
the Replace with text. Each replacement made by the editor is listed in the Find pane of the Output window
(near the bottom of your SimBionic window).
8.
If you would prefer to examine each occurrence of the Find what text before replacing it, click the
Find Next button.
The next occurrence of the text will be displayed on the Canvas with the containing item highlighted so that
you can spot it easily. It will also be listed in the Find pane of the Output window, indicating the behavior and
polymorphism in which the text occurs. If the text is part of an expression or binding, the listed item then tells
you the full expression or binding in which it appears; otherwise, it tells you the full name of the action,
predicate, or invoked behavior (including parameters, if any) that contains the text.
9.
If you wish to replace the displayed occurrence of the text, click the Replace button.
The text will be replaced by the Replace with text and the replacement will be noted in the Find pane of the
Output window.
10. If you dont wish to replace the displayed occurrence of the text, click the Find Next button to move
to the next occurrence.
55
If there are no more occurrences, the editor will displayed a dialog box announcing that the replacement
operation is complete.
11. Otherwise, repeat Steps 8-10 until you have examined all occurrences of the original text.
This method of replacing text across behaviors is especially useful after youve compiled your project and discovered
errors in an expression or binding; the Replace option helps you locate and fix the problems quickly and easily.
Note: Replace will not replace text in text annotations that youve placed directly on the Canvas using the Add text
tool.
Tip: If you perform a replace operation and then decide shortly afterward that it was a mistake, you can typically
reverse your changes with a few mouse clicks. For more information, see the Undoing your most recent change(s)
topic.
Undoing your most recent change(s)
You can typically reverse any change youve made to the Canvas by using the Undo command. For example, if youve
removed one or more Canvas elements and then regret your choices, selecting the Undo command will bring back the
deleted elements. Undo therefore acts like a safety net, allowing you to try out different approaches and, if youre
unhappy with the results, return the Canvas to its previous state.
To reverse one or more operations youve performed, follow these steps:
1.
Click the Edit menu and select the Undo option, or press Ctrl+Z.
SimBionic returns the Canvas to the state it was in before you made your latest change. If you needed to
reverse only one operation, then youre done.
2.
If youve made a series of changes that you regret, then press Ctrl+Z repeatedly to reverse each of
your changes in turn.
For example, if you accidentally deleted three Canvas elements, then press Ctrl+Z the first time to retrieve
the last element you deleted; press Ctrl+Z a second time to retrieve the next-to-last element deleted; and
press Ctrl+Z a third time to retrieve the first element deleted, returning the Canvas to the state you want.
Tip: You can theoretically undo a sequence of up to 100 operations. However, the Undo commands history
of changes may be wiped out when you perform operations outside of the Canvas, so its safest to undo a
change as soon as you realize youve made a mistake.
3.
If you change your mind about undoing an operation, click the Edit menu and select the Redo
option, or press Ctrl+Y.
Your most recent reversed change is restored.
4.
If youve executed a series of Undo commands that you regret, continue pressing Ctrl+Y for each of
the Undo commands you want to reverse.
You can continue pressing Ctrl+Z and/or Ctrl+Y until the Canvas returns to the state you want.
Warning: SimBionic currently doesnt support undoing any operations you perform in the Catalog. Therefore, always
think twice before making Catalog changes, such as deleting a Catalog item.
Documenting your Behaviors
Commenting on a Canvas element
You can attach a tooltip comment to any Canvas element. Such a comment remains invisible until a mouse pointer
rests on the pertinent element, which causes a tooltip containing the text youve associated with the element to pop up
for viewing. This allows you to explain why you included certain elements and/or why you set them to interact in a
particular way.
Including tooltip comments and text descriptions helps ensure your programs will be readily understood by other
members of your team; and is also useful for refreshing your own memory in case you need to return to your program
months or years later.
To attach a tooltip comment to a Canvas element, follow these steps:
56
1.
2.
3.
4.
5.
Move your mouse pointer over the Canvas element youve just documented.
Over a few moments, the comment you attached is displayed in a tooltip box.
Alternatively, you can right-click on the Canvas element and select Edit Comment from the menu that appears. You
can then follow steps 3-5 above to specify the comment text.
If you ever want to revise or delete the comment youve attached, simply repeat Steps 1-2; either edit or delete the
current text in the Edit Comment dialog box; and click OK or press Enter.
Tip: You can also use your comment instead of the normal label for a rectangle or condition. For details, see the
Changing the label for a Canvas element topic.
In addition to placing comments on Canvas elements, you can also place descriptive text directly on the Canvas. See
the Adding text to the Canvas topic for more information.
Placing a reminder on a Canvas element
You can attach a reminder to any Canvas element. This reminder remains invisible until a mouse pointer rests on the
pertinent element, which causes a tooltip containing the text youve associated with the element to pop up for viewing.
Unlike a comment, which is generally a permanent piece of documentation attached to a Canvas element (see the t
topic Commenting on a Canvas element for details), a reminder is a temporary note to yourself or other members of
the development team. Its a good place to store "TODO" reminders and notes about known bugs in your behaviors.
To attach a reminder to a Canvas element, follow these steps:
1.
2.
3.
4.
5.
Move your mouse pointer over the Canvas element youve just documented.
Over a few moments, the reminder you attached is displayed in a tooltip box (along with any comment
attached to that element).
Alternatively, you can right-click on the Canvas element and select Edit Reminder from the menu that appears. You
can then follow steps 3-5 above to specify the reminder text.
If you ever want to revise or delete the reminder youve attached, simply repeat Steps 1-2; either edit or delete the
current text in the Edit Reminder dialog box; and click OK or press Enter.
Changing the label for a Canvas element
By default, the label for a Canvas element summarizes the variable bindings and expression attached to that element,
truncating any particularly long variable names or string constants in order to keep the label a reasonable size. For
example:
If you have specified a comment for a Canvas element, you can choose to use that comment as the label for the
element by right-clicking on the element, selecting Set Label, and then selecting Comment/Reminder. For example:
57
You can also choose to display a non-truncated version of the normal label by right-clicking on the element, selecting
Set Label, and then selecting Full. For example:
You can always restore the normal label by right-clicking, selecting Set Label, and then selecting Truncated.
Adding text to the Canvas
To place always-visible text anywhere on the Canvas, follow these steps:
1.
2.
Click the spot on the Canvas where you want to place the description.
A text box appears.
3.
4.
When youre done typing, click anywhere outside the text box.
Your typing is saved, and your description appears on the Canvas.
If you later want to move the description, click anywhere within the text to make the text box appear and then drag the
box to your new location. You can also resize the text box by clicking on the text and then dragging one of the small
black squares that appear to its left and right.
If you later want to delete the description, click anywhere within the text to make the text box appear and then press
the Del key. Alternatively, right-click on the text and select Delete from the menu that appears.
You can also cut, copy, and paste the text just like a Canvas element by selecting it and then selecting the Edit menu
and clicking Cut, Copy, or Paste. Alternatively, you can right-click on the element and select Cut, Copy, or Paste.
58
Notice that each local variable has a descriptive name, which aids in a programs readability.
Also notice that each name is followed by a word indicating the type of data the variable was created to store. To learn
how to select the appropriate data declaration for a variable, see the Choosing a data type topic.
After you do so, learn how to declare and revise local variables by reading the Creating and editing local variables
topic.
Global variables
A global variable can be accessed by any operation across all of an entitys behaviors. Because they arent restricted
to a particular behavior, global variables are powerful tools for handling data that can affect an entity at any point
during its activities in your virtual world. At the down side, however, it can be difficult to keep track of the contents of a
global variable because a series of different behaviors may alter the variables values in ways you didnt predict. Its
therefore best to reserve global variables for values that genuinely need to transcend a single behavior, such as entity
IDs and descriptors.
For example, if you needed to keep track of an entitys location across behaviors, you could create a global variable
named Hero_Location. After you did so, any change made to the value of Hero_Location in Behavior A would carry
over to Behavior B, any change made in Behavior B would carry over to Behavior C, and so on.
Note: Global variables are available across behaviors but not across entities. When you run your program, SimBionic
automatically creates a separate set of the global variables youve declared in your project for each of your entities.
For example, if you created a global string variable named gEmotion (the g standing for global), the variable could
59
contain a value of "Happy" for one entity and "Sad" for another entity at the same time, because SimBionic maintains a
distinct and independent copy of the variable for every entity.
You can examine and edit the global variables youve created at any time by double-clicking the Globals header in the
Catalog. After you do so, Globals expands to display the variables it contains, as in this example:
Notice that each global variable has a descriptive name, which aids in a programs readability. In addition, each name
is preceded by the letter g, a naming convention that makes it easy for you to pick out global variables within your
program code.
Also notice that each name is followed by a word indicating the type of data the variable was created to store. To learn
how to select the appropriate data declaration for a variable, see the Choosing a data type topic.
After you do so, learn how to declare and revise global variables by reading the Creating and editing global variables
topic.
Note #1: SimBionic automatically creates a special set of global variables that correspond to the descriptor categories
youve created via the Descriptors pane. These variables, which are stored in the Polymorphisms folder under the
Globals header in the Catalog, store the entitys current state for each descriptor category. They cannot be directly
deleted or edited.
For more information, see the topic Descriptors_and_global_variables.
Note #2: If youre using any values in your project that never change, you shouldnt store them in variables but instead
assign them to constants. For more information, see the Creating and editing constants topic.
Choosing a data type
SimBionic supports 11 built-in data types: integer, float, string, vector, Boolean, entity, array, table, data, any, and
invalid. It also allows you to define your own data types by creating enumerated types and classes. When you create a
parameter, variable, or constant, the data type you declare for it tells SimBionic how to interpret the parameters or
variables information.
The following sections describe each data type.
Integer
The integer data type is used for any whole number numeric value. For example, -12, 0, 17, and 5000 are four
instances of values that could be assigned to a variable of type integer.
You can perform a variety of mathematical operations on integer values. For more information, see the Using
operators in expressions topic.
Float
The float data type is used for any floating point numeric valuei.e., any number that may include digits to the right of
the decimal point. For example, -12.333, 0.1, 55, and 6000.725344 are four instances of values that could be assigned
to a variable of type float.
You can perform a variety of mathematical operations on float values. For more information, see the Using operators
in expressions topic.
String
The string data type is used for any sequence of alphanumeric charactersi.e., letters, numbers, and/or punctuation
symbols. The beginning and end of the sequence is indicated by quotation marks. For example, "Hello", "My name is
60
Bond. James Bond.", "ABC123", and "100.45" are four instances of values that could be assigned to a variable of type
string.
Note that even though the last example, "100.45", has the appearance of a number, SimBionic would interpret it as a
sequence of alphanumeric characters. As a result, it could be used in messages to convey information, but no
numerical operations could be performed on it.
However, you can add (concatenate) strings. For example, the expression
\\
\"
\t
\n
Note: When used in Boolean operations, the string "" (i.e., an empty string) evaluates as false, while any other string
evaluates as true.
Vector
The vector data type consists of three coordinates that collectively identify a point in space in your virtual world.
Vectors are typically used to identify where an entity is located or what path an entity should take. A vector is in [x, y,
z] format, typically with x representing an East-West coordinate, y representing a North-South coordinate, and z
representing an Up-Down coordinate. (When dealing with two-dimensional paths, you can simply ignore the third
coordinate.) The coordinates must be enclosed in square brackets and separated by commas (spaces are permitted,
but unnecessary). For example, [1, -3, 2] and [2.5,0,-7.1] are both instances of values that could be assigned to a
variable of type vector.
You can perform addition and subtraction with vectors. For example, the expression
[4, 0, 5]
You can also perform multiplication with vectors. For example, either of the expressions
[3, -9, 6]
In addition, you can access any of the individual components of a vector using the "." operator
myvector.x * 3.5
Note: When used in Boolean operations, the vector [0, 0, 0] evaluates as false, while any other vector evaluates as
true.
Boolean
The Boolean data type is used for any logical value that evaluates as either true or false. For example, X<=Y, X>Y,
X==Y, X!=Y, 1, and 0 are six instances of values that could be assigned to a variable of type Boolean.
Specifically, if we assume X=3 and Y=4, then X<=Y would evaluate as true; X>Y as false; X==Y as false; X!=Y as true;
1 as true; and 0 as false. You can also assign the special keywords true and false to Boolean variables.
To learn more about Boolean operations and values, see the Using operators in expressions topic.
Entity
The entity data type is used to store the unique number codes that SimBionics run-time engine dynamically assigns to
the various entities in your program. You can use this data type to refer to particular entities.
For more information on entities, see the Understanding descriptors topic.
Array
The array data type is used to store a series of conceptually related data elements (e.g., a entitys name, strength
level, intelligence level, health level, etc.). The elements can be any combination of data types, including other arrays
61
(i.e., you can have sub-arrays within a parent array). You can access any element by referring to its position in the
array.
For more information, see the Using arrays topic.
Table
The table data type is used to store a two-dimensional array. While you can implement a table via the array data type,
using the table data type is more convenient when your information is logically organized into columns and rows.
For more information, see the Using tables topic.
Data
The data data type is a catch-all to support any type of information you require that isnt covered by the integer, float,
string, vector, Boolean, entity, or invalid data types. You will typically want to use data variables to hold pointers to
C++ or Java objects used by your application. SimBionic effectively treats a data value as a "black box," and does
nothing to the value except store it and pass it on whenever you request it. Therefore, you can assign whatever
meaning to a value of type data is most convenient for your programming needs.
Any
The any data type encompasses all the other supported data types. You can assign it to parameters that need to
handle values of multiple data typese.g., an integer value such as -12, a string value such as "Attack now!", a vector
value such as [1,-2,5], and so on.
For example, the group messaging action SendMsg and predicate GetMsgData, and the virtual blackboard action
PostBBoard and predicate ReadBBoard, are designed to transmit information of any data type to provide entities with
maximum flexibility in communicating with each other. As a result, SendMsg and PostBBoard send their information
via parameters declared to be of data type any; and GetMsgData and ReadBBoard are internally declared to return
values of data type any.
In most cases, however, a parameter will be handling a specific data type and should be declared for only that type, to
ensure your code remains clear and relatively easy to debug.
Note: To discourage poor programming practices, SimBionic does not allow a variable or constant to be of data type
any. The any option is restricted to parameters you create while declaring an action, predicate, or behavior.
Invalid
SimBionic supports an eleventh built-in data type, named invalid, which is a special case. You cannot create a variable
or parameter of type invalid. An invalid value is generated exclusively by SimBionic; and its provided to let you check
on whether a value is what you expected, or if something went wrong with an operation and an invalid value resulted
instead. You can find out whether a value is invalid by using the IsValid predicate, which evaluates as true if the value
is okay or false if its invalid.
The invalid data type is used by SimBionics built-in ReadBBoard predicate, which returns an invalid value if an entity
tries to read a virtual blackboard board section that doesnt actually exist. In addition, youor a programmer on your
development teamcan create customized actions and predicates that also return an invalid value when something
goes wrong. The results of any such operation can then be passed to the IsValid predicate for the purpose of error
checking.
For more information on the IsValid predicate, see the Checking for invalid values topic.
For more information on creating customized actions and predicates, see the Coding actions in C++ and Coding
predicates in C++ topics if you program in C++, or the Coding actions in Java and Coding predicates in Java topics if
you program in Java.
Enumerated Types
An enumerated type is a user-defined data type that consists of a set of named integer or string values. These values
can be used in place of normal strings and integers to improve the readability of your behaviors. They can also be
used to restrict the set of values that can be passed as parameters to an action or predicate, which can help prevent
authoring mistakes. You may define as many different enumerated types as you like for use in your project. For more
information, see Creating and editing enumerated types and Using enumerated types.
Classes
A class is an advanced user-defined data type that corresponds to a Java class in your application. Once you have
defined a class in SimBionic, you can create objects of that class and directly invoke the methods of the underlying
Java class as though they were actions and predicates. When your behaviors are frequently manipulating Java
objects, using classes can greatly simplify authoring. See Understanding classes for more details.
Tip: You can set a condition to evaluate as false using any built-in SimBionic data type. Specifically, for the Boolean
data type, use either the keyword false or any expression that evaluates as false; for integer or float, use the value 0;
for vector, use the value [0,0,0]; and for string, use the value "" (i.e., an empty string).
The other three individual data types can generate false values with the help of predicates. Specifically, the NullData
predicate will return a result of false for a value of type data; the NullEntityID predicate will return a result of false for a
62
value of type entity; and the IsValid predicate will return a result of false when passed a value of type invalid.
For more information, see the Creating and editing conditions and Understanding the core predicates topics.
If youve read this topic and the Understanding variables topic, youre ready to start declaring and revising variables.
To learn how to do so, see the Creating and editing local variables and Creating and editing global variables topics.
Checking for invalid values
In addition to the choice of built-in and user-defined data types you can assign to a parameter (i.e., integer, float,
string, vector, Boolean, entity, data, array, table, or any), SimBionic supports an additional data type called invalid.
An invalid value is generated exclusively by SimBionic; and its provided to let you check on whether a value is what
you expected, or if something went wrong with an operation and an invalid value resulted instead.
You can find out whether a value is invalid by using the IsValid predicate, which evaluates as true if the value is okay
or false if its invalid. IsValid is available in every SimBionic project; its automatically declared in the Catalog in the
Core AP module, with corresponding code built into SimBionics engine.
You can use IsValid to check on a predicate that has the potential of returning an invalid value. For example, the
ReadBBoard predicate normally locates a virtual blackboard with the name an entity specifies, locates a particular
board section with the name the entity specifies, and then returns the information stored in that section. However, if
either the blackboard or the section of the blackboard with the name specified doesnt actually exist, ReadBBoard
wont be able to locate any information and will instead return an invalid value.
ReadBBoard is the only predicate built into SimBionic that can return an invalid value. However, youor a
programmer on your development teamcan create customized predicates that also return an invalid value when
something goes wrong. The results of any such predicate can then be passed to the IsValid predicate for the purpose
of error checking.
IsValids single parameter is a value of type any (because IsValid can evaluate any data type):
Move to the behavior for which you want to create the local variable.
If you arent sure how to do this, see the Navigating behaviors topic. After you move to the behavior, its
displayed on the Canvas.
2.
Click the Locals button (in the upper-right of your SimBionic window).
Note: If you dont see the Locals button, click the View menu, select Toolbars, and select Variables to
display the Variables toolbar; and then click the Locals button on the toolbar.
After you click, this Local Variables dialog box appears:
63
Notice that the box starts out empty except for a Locals header.
3.
4.
Notice that the dialog box contains options for naming and describing your variable and selecting its data
type.
64
5.
6.
Click in the Type box to display the available data types, and click the data type thats appropriate
for your variable.
If you arent sure which option to click, read the Choosing a data type topic and then return to this step.
7.
Click in the Description box, and type a brief description of what the variable is for.
This documentation helps ensure your variable will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the variable in the
Catalog or any Edit dialog box.
8.
9.
Optionally repeat Steps 3-8 to create more local variables for the current behavior.
10. When youre done, click the Local Variables palettes Close button (the "X" in its upper-right corner).
The box exits, providing you with a clear view of the Canvas again.
Tip: You can also create a new local variable for the current behavior on the Canvas using the Ctrl-L shortcut.
Move to the behavior for which you want to view and/or edit the local variables.
The behavior is displayed on the Canvas.
2.
Click the Locals button (in the upper-right of your SimBionic window).
The Local Variables dialog box appears and lists all the variables youve created for the current behavior.
3.
4.
Optionally click in the Name box and change the variables name.
5.
Optionally click in the Type box and select a different data type.
6.
Optionally click in the Description box and change the description text.
7.
Click OK.
The changes you made are saved, and the variable appears in the Local Variables palette with the new
name and/or data type you specified.
8.
Optionally repeat Steps 3-7 to edit any other local variables for the current behavior.
9.
When youre done, click the Local Variables palettes Close button (the "X" in its upper-right corner).
The box exits, providing you with a clear view of the Canvas again.
Move to the behavior for which you want to delete local variables.
The behavior is displayed on the Canvas.
2.
Click the Locals button (in the upper-right of your SimBionic window).
The Local Variables dialog box appears and lists all the variables youve created for the current behavior.
3.
4.
5.
Locate and remove every occurrence of the variable in the current behavior.
If you dont eliminate every reference to the variable, youll receive error messages after you delete it and
then try to compile your program.
6.
When youre done removing all references to the variable, right-click the variable in the Local
Variables dialog box again.
Again, a menu pops up that includes a Delete option.
7.
8.
Optionally repeat Steps 3-7 to delete any other local variables for the current behavior.
9.
When youre done, click the Local Variables palettes Close button (the "X" in its upper-right corner).
The box exits, providing you with a clear view of the Canvas again.
After youve created your variables, youre ready to use them. In SimBionic, variables can be used in expressions and
bindings. To learn more, see the Understanding expressions and Attaching bindings to a Canvas element topics.
Creating and editing global variables
If youve read the Understanding variables and Choosing a data type topics, youre now ready to create and edit global
variables. The following sections tell you how.
65
2.
Notice that the dialog box contains options for naming the variable, selecting its data type, entering its initial
value, and providing a description of its purpose.
3.
4.
Click in the Type box to display the available data types, and click the data type thats appropriate
for your variable.
If you arent sure which option to click, read the Choosing a data type topic and then return to this step.
5.
Click in the Description box, and type a brief description of what the variable is for.
This documentation helps ensure your variable will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the variable in the
Catalog or any Edit dialog box.
6.
If you clicked the entity or data option, skip to Step 7. Otherwise, optionally click in the Initial Value
box and enter whatever initial data you want to assign to the variable.
Youre not allowed to enter an initial value for an entity or data variable because an entitys ID number must
be supplied by SimBionics run-time engine, and the value for a data variabletypically a data pointer
must be supplied by your simulation or game.
If you opt to enter an initial value, make sure that the data corresponds to the data type youve selected
that is, a whole number value for integer (e.g., -12); a floating point value for float (e.g., 10.25); an
alphanumeric sequence enclosed in "quotes" for string (e.g., "Welcome to your new unit, soldiers."); a
sequence of three numbers in square brackets for vector (e.g., [-1,3,2]); or a true or false value for Boolean.
Note: If you selected the array or table option in Step 4, a Set Initial Values button appears. Click the button
to open a dialog box that lets you set the size of your array or table, and the initial values of each of its
elements. (See the topics Editing arrays and Editing tables for more details.) When youre done entering
values, click OK to save your settings; youre returned to the Insert Global dialog box.
7.
66
8.
9.
When youre done creating variables, optionally double-click the Globals header to hide them (to
create an uncluttered Catalog display).
You can hide or display your global variables at any time by double-clicking the Globals header.
Tip: You can also create a new global variable in the Catalog using the Ctrl-G shortcut.
If your global variables arent already visible, double-click the Globals header to display them.
All the global variables in your SimBionic project are listed.
2.
3.
Optionally click in the Name box and change the variables name.
4.
Optionally click in the Type box and select a different data type.
5.
Optionally click in the Description box and change the variables description.
6.
If you selected entity or data in the Type box, skip to Step 7. Otherwise, optionally click in the Initial
Value box and change the initial data.
7.
Click OK.
The changes you made are saved, and the variable appears under the Globals header in alphabetical order
with the new name and/or data type you specified.
8.
9.
When youre done editing variables, optionally double-click the Globals header to hide them (to
create an uncluttered Catalog display).
After youve created your variables, youre ready to use them. In SimBionic, variables can be used in expressions and
bindings. To learn more, see the Understanding expressions and Attaching bindings to a Canvas element topics.
Creating and editing constants
Youll typically want to use certain static valuese.g., numbers, coordinates, text stringsthroughout a project. You
can reference these values in their raw form (e.g., 98.6 for body temperature, [50,75,0] for Central Headquarters
coordinates, "For first attack, fire torpedoes 1, 2, 7, and 8" for first attack orders, etc.), but doing so tends to produce
code thats difficult to read and maintain. Its therefore better to assign such values clearly representative names (e.g.,
BodyTemp, CentralHQ, FirstAttack, etc.).
You could create such names by storing each static value in its own global variable. However, its both clearer and
more efficient to declare them as constants, which are symbolic names that do nothing but act as easy-to-read standins for raw static values. When you assign a value to a constant, youre making clear that the value will never change;
creating significantly less overhead than you would by devoting a global variable to the value; and ensuring that your
program will never accidentally change the value (which could happen if it was stored in a variable).
You can create and edit constants via the Constants section in the Catalog. The following sections tell you how.
Creating constants
To create one or more constants, follow these steps:
1.
2.
67
Notice that the dialog box contains options for naming the constant, selecting its data type, entering its
value, and providing a description of its purpose.
3.
4.
Click in the Type box to display the five available data types, and click the data type thats
appropriate for your constant.
The five data types are integer, float, string, vector, and Boolean. If you arent sure which option to click,
read the Choosing a data type topic and then return to this step.
Note: Youre not allowed to create a constant for entity or data types because the former value is an ID
number that must be supplied by SimBionics run-time engine, and the latter value (typically a data pointer)
must be supplied by your simulation or game. You also cant create array or table constants, because these
data constructs typically arent well-suited for static use.
5.
Click in the Value box and enter whatever value you want to assign to the constant.
Make sure that the data corresponds to the data type youve selectedthat is, a whole number value for
integer (e.g., -12); a floating point value for float (e.g., 10.25); an alphanumeric sequence enclosed in
"quotes" for string (e.g., "Welcome to your new unit, soldiers."); a sequence of three numbers in square
brackets for vector (e.g., [-1,3,2]); or a true or false value for Boolean.
6.
Click in the Description box, and type a brief description of what the constant is for.
This documentation helps ensure your constant will be readily understood by other members of your team,
and is also useful for refreshing your own memory in case you need to return to your project months or
years later.
You can view this description later by hovering your mouse cursor over the name of the constant in the
Catalog or any Edit dialog box.
7.
8.
9.
When youre done creating constants, optionally double-click the Constants header to hide them (to
create an uncluttered Catalog display).
You can hide or display your constants at any time by double-clicking the Constants header.
Editing constants
If you change your mind about any decisions youve made regarding your constants, you can revise them quickly and
easily. To do so, follow these steps:
68
1.
If your constants arent already visible, double-click the Constants header to display them.
All the constants in your SimBionic project are listed.
2.
3.
Optionally click in the Name box and change the constants name.
4.
Optionally click in the Type box and select a different data type.
5.
6.
Optionally click in the Description box and change the description text.
7.
Click OK.
The changes you made are saved, and the constant appears under the Constants header in alphabetical
order with the new name and/or data type you specified.
8.
9.
When youre done editing constants, optionally double-click the Constants header to hide them (to
create an uncluttered Catalog display).
After youve created your constants, youre ready to use them. In SimBionic, constants can be used in expressions
and bindings. To learn more, see the Understanding expressions and Attaching bindings to a Canvas element topics.
Importing constants
If you have many constants, it may be convenient to define them in an external file and then import them into the
editor. To do so, follow these steps:
6.
7.
8.
Use the dialog box to locate the folder containing the file youre after, and then click the file.
The file is displayed in the Filename text box.
9.
The format for the constant definition file is very simple: each line should contain the name of a single constant
followed by one or more spaces and then its value. For example:
my_string
"hello world"
365
Lines beginning with a percent sign are considered to be comments and are ignored. Extra whitespace is also ignored.
Understanding Expressions
Understanding expressions
In SimBionic, an expression is typically an arithmetic phrase containing variables, static values (e.g., numbers, strings,
constants), and/or predicates linked together by operators. (For a complete list of the operators available in SimBionic,
see the Using operators in expressions topic.)
The following are some examples of valid SimBionic expressions
2+3: This expression consists of two numbers (2 and 3) and the operator for addition, resulting in a value of
5.
X*Y: This expression consists of two variables (X and Y) and the operator for multiplication. If X=2 and Y=3,
the expression results in a value of 6.
50/(X-Y): This expression consists of a number (50), two variables (X and Y), and the operators for division
and subtraction. If X=20 and Y=10, the expression results in a value of 5.
IsValid()&&IsDone(): This expression consists of the built-in predicate IsValid, which returns a Boolean
value of true or false; the built-in predicate IsDone, which also returns a value of true or false; and the
Boolean operator &&, which logically ANDs two values. If IsValid() is true and IsDone() is true, then the
expression results in a value of true; otherwise, it results in a value of false.
GetMsgData()=="Bombs Away!": This expression consists of the built-in predicate GetMsgData, which
returns the string message at the top of an entitys message queue; the string "Bombs Away!"; and the
Boolean operator ==, which compares two values to determine if theyre equal. If the top message is
actually "Bombs Away!", then GetMsgData() returns that string and the expression results in a value of true;
otherwise, it results in a value of false.
69
In SimBionic, a valid expression can also consist of a solitary predicate or action, as long as the expression is entered
into the appropriate rectangle or oval on the Canvas. Here are two examples:
IsDone(): This expression consists solely of the built-in predicate IsDone, which returns a value of true or
false. Even though it contains no operators, SimBionic considers it a valid expression as long as its entered
into a condition (i.e., oval) on the Canvas.
NextMsg(): This expression consists solely of the built-in action NextMsg, which discards the top message
of a message queue so an entity can access its next message. Even though it contains no operators and
returns no values, SimBionic considers it a valid expression as long as its entered into an action rectangle
on the Canvas.
. (member access): Accesses a vector component or a class member. Supported data types: vector, class.
Example: myvector.z, where myvector = [1,2,3]. Result: 3.
=====
- (minus sign): Performs numeric negation. (Note: Also used for subtraction, which appears further down in
this list because subtraction has a lower operator precedence.) Supported data types: Integer, float, vector.
Example: -5. Result: Negative five.
Example: [-1,-2,2]. Result: A vector whose coordinates are negative one, negative two, and two. (E.g., if
these coordinates represented East-West, North-South, and Up-Down, this vector could instruct an entity to
move West by one position, South by two positions, and Up by two positions.)
! (exclamation point): Performs Boolean negationi.e., turns a true value to false, and vice versa.
Supported data type: Boolean.
Example: !HasRifle, when Boolean variable HasRifle is true. Result: False.
Example: !HasRifle, when Boolean variable HasRifle is false. Result: True.
=====
70
* (asterisk): Performs multiplication of numbers and vectors. Supported data types: Integer, float, vector.
Example: 3*4. Result: 12.
Example: [3,3,3] * [-1,1,2]. Result: The vector [-3,3,6].
Example: [3,3,3] * 2. Result: The vector [6,6,6].
/ (forward slash): Performs numeric division. Supported data types: Integer, float.
Example: 5/2. Result: 2.5.
Example: 18-6/3. Result: 16.
Example: (18-6)/3. Result: 4.
% (percent sign): Performs modulus division (i.e., returns the remainder following division). Supported data
types: Integer, float.
Example: 14%3. Result: 2.
Example: 12%3. Result: 0.
=====
+ (plus sign): Performs numeric addition, vector addition, and string concatenation. Supported data types:
Any (because any value can be concatenated to a string).
Example: 3+2. Result: 5.
Example: [3,3,3] + [-1,1,2]. Result: The vector [2,4,5].
Example: "Those who dare, " + "win." Result: The string "Those who dare, win."
Example: "The value is " + my_vector. Result: The string "The value is [1,15,-7]".
- (minus sign): Performs numeric and vector subtraction. (Note: Also used for negation, which appears
higher up on this list because negation has a higher operator precedence.) Supported data types: Integer,
float, vector.
Example: 3-2. Result: 1.
Example: [3,3,3] - [-1,1,2]. Result: The vector [4,2,1].
=====
< (less than sign): Performs less than numeric comparison for Boolean result of true or false. Supported
data types: Integer, float.
Example: X<Y, when X=3 and Y=4. Result: True.
Example: X<Y, when X=3 and Y=3. Result: False.
Example: X<Y, when X=4 and Y=3. Result: False.
<= (less than sign, equal sign): Performs less than or equal to numeric comparison for Boolean result of
true or false. Supported data types: Integer, float.
Example: X<=Y, when X=3 and Y=4. Result: True.
Example: X<=Y, when X=3 and Y=3. Result: True.
Example: X<=Y, when X=4 and Y=3. Result: False.
> (greater than sign): Performs greater than numeric comparison for Boolean result of true or false.
Supported data types: Integer, float.
Example: X>Y, when X=3 and Y=4. Result: False.
Example: X>Y, when X=3 and Y=3. Result: False.
Example: X>Y, when X=4 and Y=3. Result: True.
>= (greater than sign, equal sign): Performs greater than or equal to numeric comparison for Boolean
result of true or false. Supported data types: Integer, float.
Example: X>=Y, when X=3 and Y=4. Result: False.
Example: X>=Y, when X=3 and Y=3. Result: True.
Example: X>=Y, when X=4 and Y=3. Result: True.
=====
== (double equal sign): Performs equal comparison for Boolean result of true or false. Supported data
types: Integer, float, string, vector, Boolean, entity, data.
Example: X==Y, when X=3 and Y=4. Result: False.
Example: X==Y, when X=3 and Y=3. Result: True.
Example: "Those who dare, " + "win."=="Those who dare, win.". Result: True.
!= (exclamation point, equal sign): Performs not equal comparison for Boolean result of true or false.
Supported data types: Integer, float, string, vector, Boolean, entity, data.
Example: X!=Y, when X=3 and Y=4. Result: True.
Example: X!=Y, when X=3 and Y=3. Result: False.
Example: "Those who dare, " + "win."!="Those who dare, win.". Result: False.
=====
&& (double ampersand): Performs logical AND numeric comparison for Boolean result of true or false; i.e.,
both expressions must be true for the result to be true. Supported data type: Boolean.
Example: (X<Y)&&(Y<Z), when X=3, Y=4, and Z=5. Result: True.
Example: (X<Y)&&(Y<Z), when X=3, Y=5, and Z=4. Result: False.
Example: (X<Y)&&(Y<Z), when X=5, Y=5, and Z=4. Result: False.
Example: (X==Y)&&(Y!=Z), when X="Candy", Y="Candy", and Z="Steak". Result: True.
|| (double vertical bars): Performs logical OR numeric comparison for Boolean result of true or false; i.e.,
either expression can be true for the result to be true. Supported data type: Boolean.
Example: (X<Y)||(Y<Z), when X=3, Y=4, and Z=5. Result: True.
Example: (X<Y)||(Y<Z), when X=3, Y=5, and Z=4. Result: True.
Example: (X<Y)||(Y<Z), when X=5, Y=5, and Z=4. Result: False.
Example: (X==Y)||(Y!=Z), when X="Candy", Y="Steak", and Z="Steak". Result: False.
=====
71
?: (ternary operator): Evaluates the first argument, and if true evaluates and returns the first argument; if
false, evaluates and returns the second argument. Supported data type: any.
Example: (X<Y) ? Y : Z, when X=3, Y=4, and Z=5. Result: 4.
The following chart summarizes SimBionic operators, their formats, and the data types they support (aside from array
and table, which dont support mathematical operations, and any, which encompasses all data types). Again,
operators are listed in order of precedence, with those grouped inside the same line borders having equal precedence:
Note: SimBionic doesnt support directly typing a single equal sign (=) to assign a value to a variable (e.g., typing X=2
isnt allowed). If you want to assign a value, you must instead use SimBionics binding option. To learn more, see the
Understanding expressions and Attaching bindings to a Canvas element topics.
Autocompleting an expression
When you edit an action or behavior on the Canvas and begin typing the actions or behaviors name in the Expression
box, the name is highlighted in the Action/Behavior List. If you skip the rest of the name and just type a left parenthesis
(or hit the Tab key), SimBionic will understand that you want it to do the typing for you and will automatically enter the
full name of the action or behavior, followed by your left parenthesis. You can then proceed to enter the necessary
parameters (if any) and a right parenthesis to complete the action or behavior.
Similarly, when you edit a condition on the Canvas and begin typing the name of a predicate in the Expression box,
the name is highlighted in the Predicate List. If you skip the rest of the name and just type a left parenthesis (or hit the
Tab key), SimBionic will understand that you want it to do the typing for you and will automatically enter the full name
of the predicate, followed by your left parenthesis. You can then proceed to enter the necessary parameters (if any)
and a right parenthesis to complete the predicate.
Along the same lines, after you begin typing the name of a variable or constant in an expression, the name is
highlighted in the Variable List. You can either hit the Tab key or proceed directly to typing whatever operator you want
to follow the variable or constant (e.g., + for addition, - for subtraction or negation, / for division, * for multiplication, ! for
Boolean negation, and so onfor more information, see the Using operators in expressions topic). SimBionic will
understand that you want it to do the typing for you and will automatically enter the full name of the variable or
constant, followed by the operator.
For more information, see the Understanding expressions, Creating and editing actions on the Canvas, Creating and
editing conditions, and Attaching bindings to a Canvas element topics.
Working with Bindings
Attaching bindings to a Canvas element
Assigning a value to either a local variable or global variable is called binding the value to the variable. For example,
X=12 binds the value 12 to an integer variable named X; and Message=GetMsgData() binds whatever data is returned
by the predicate GetMsgData to a variable named Message.
The value in a binding can be static (e.g., 12, "Bombs away!", or any constant), returned from an action or predicate,
or copied from another variable. In addition, the value can be an expression combining any or all of these elements;
72
for example, X=(GetMsgData()=="Bombs away!") binds a true value to X if the top message in an entitys message
queue is "Bombs away!" and a false if the top message is anything else.
When creating a binding, make sure that each variables type matches its values type (e.g., dont assign a string to a
float variable, a vector to a Boolean variable, and so on). Mismatching values with data types will either produce error
messages when you compile your program or simply crash your program when you try to run it.
You can attach as many bindings as you like to any action or behavior (rectangle), condition (oval), or connector (line)
on the Canvasin other words, to any Canvas element. Each variable being boundi.e., being assigned a valueis
displayed inside the Canvas element (for rectangles and ovals) or next to the element (for lines).
When your program runs, SimBionic first executes all of a Canvas elements bindings in the order you specified and
then executes any other expressions associated with the element. The only exceptions to this rule are:
If an invoked behavior on the Canvas requires more than one clock tick to execute, SimBionic will execute
the behaviors bindings during the first clock tick, but will then ignore the bindings when it returns to
executing the behavior during subsequent clock ticks.
If none of the connectors coming out of a rectangle evaluate as true, SimBionic will execute the rectangle
again during each subsequent clock tick until the situation changes, but will not execute the rectangles
bindings again.
If you attach any bindings to a final action, SimBionic will ignore them. Thats because as soon as SimBionic
encounters a final action, it ends all execution of the current behavior.
2.
Notice that the dialog box includes a button for inserting (i.e., creating and attaching) a new binding.
3.
73
The top section contains a Bound Variable box that lets you select the local or global variable you want to
use from a drop-down list; and an Expression box that lets you enter an expression representing the value
you want to assign the variable youve selected.
Youre also provided with a Predicate List box that reminds you of the predicates available in your project, in
case you want to use any of them as components of your expression. Clicking a predicate displays its
parameters in the box directly below it, reminding you of the predicates syntax. Double-clicking a predicate
enters its name into the Expression box.
In addition, youre provided with a Variable List box that lists all the local variables, global variables, and
constants available in your project. Double-clicking a variable or constant enters its name into the
Expression box.
If you need to refresh your memory about the meaning of a particular predicate, variable, or constant, simply
hover your mouse cursor over its name in the list box. After a moment, a tooltip with the description of that
item will appear.
74
4.
Click in the Bound Variable box, and click the variable you want from the drop-down list.
The variable you selected is displayed in the Bound Variable box. If the variable is of a class type, then an
additional Member drop-down list will appear to the right of the Bound Variable box. This list enables you to
select one of the member variables of the class to bind. If you wish to bind the class variable itself, make
sure "(none)" is selected in the Member drop-down list.
5.
Use the Expression box to construct the value you want to assign your specified variable.
For example, you can click in the Expression box and simply type a value; or type an expression that
evaluates to a value. You can also use the Predicate List and Variable List boxes to help built an
expression; double-clicking any listed item will copy its name into the Expression box starting at your cursor
position.
By default, the items in the list boxes will be filtered so that only those that match the type of the parameter
you are currently editing will be displayed. (If you are not editing a paramter, then all items are displayed.) If
you wish to turn off this filtering, uncheck the Filter by type box below the Variable List.
Tip: When you begin typing the name of a predicate or method in the Expression box, the name is
highlighted in the Predicate List. If you skip the rest of the name and just type a left parenthesis (or hit the
Tab key), SimBionic will understand that you want it to do the typing for you and will automatically enter the
full name of the predicate, followed by your left parenthesis. You can then proceed to enter the necessary
parameters (if any) and a right parenthesis to complete the predicate.
Similarly, after you begin typing the name of a variable or constant in the Expression box, the name is
highlighted in the Variable List. If you skip the rest of the name and either hit the Tab key or just type
whatever operator you want to follow the variable or constant (e.g., + for addition, - for subtraction or
negation, / for division, * for multiplication, ! for Boolean negation, and so onfor more information, see the
Using operators in expressions topic), SimBionic will understand that you want it to do the typing for you and
will automatically enter the full name of the variable or constant, followed by the operator.
If you are binding a variable of type array or table, a Set Value button will appear to the right of the Bound
Variable box. Clicking this button will invoke the Edit Array (or Edit Table) dialog box, which provides an
easy graphical way to specify the values of each entry in an array or table. Note that you can also specify
the value of an array or table as a text expression.
6.
7.
Optionally repeat Steps 3-6 to create more bindings to attach to your selected Canvas element.
You can attach as many bindings as you want.
8.
Tip #1: You can quickly attach a binding to a Canvas element by dragging a global variable or behavior parameter
from the Catalog, or a local variable from the Local Variables palette, onto the desired Canvas element. A new empty
binding for that variable or parameter will be created. You can then edit the binding expression as described in the
topic Revising a Canvas element's bindings, or using the
Tip #2: If youd like to bind one value under a certain condition and a different value under another condition, use the If
predicate, which consists of an expression and two values. This predicate first determines if its expression is true or
false; and then returns the first value if the expression is true or the second value if its false. The predicates format is
expression: Boolean [in], Value1: any [in], Value2: any [in] (e.g., If(EnemyAttack,FireAtWill,AwaitOrders)). It returns a
value of data type any (because both Value1 and Value2 can be any data type).
For example, if you wanted to assign the variable BabyPresent a value of BluePresent if the baby turns out to be a boy
or PinkPresent if the baby turns out to be a girl, you could use this binding: BabyPresent =
If(gender=="boy",BluePresent,PinkPresent). For more information, see the Understanding the core predicates topic.
In addition to creating bindings, you can easily edit, delete, and reorder bindings. To learn how, see the next topic,
Revising a Canvas element's bindings.
Revising a Canvas element's bindings
After youve created bindings for a Canvas element (as described in the Attaching bindings to a Canvas element
topic), you can review the bindings at any time and optionally edit them, delete them, or reorder them. The following
three sections tell you how.
Editing bindings
If you change your mind about any binding youve attached to a Canvas element, you can revise it quickly and easily
by following these steps:
1.
2.
75
Notice that the top of the dialog box lists all of the bindings attached to the Canvas element. Also notice that
below the list is a button for editing an existing binding.
76
3.
4.
The Bound Variable box displays the local or global variable to which youre assigning a value; and the
Expression box contains the value, or expression returning a value, that youre assigning to the variable.
5.
To bind a different variable, click in the Bound Variable box, and click the variable you want from the
drop-down list.
The variable you selected is displayed in the Bound Variable box.
Note: Variables that are already assigned a value within your selected Canvas element wont appear on the
drop-down list. If you want to select such a variable, then click the Cancel button, return to Step 3, and first
edit or delete the binding for that variable to make the variable available for a different binding.
6.
To bind a different value, click in the Expression box to edit the valueor expression returning a
valuethats being assigned to your selected variable.
You can use the Predicate List and Variable List below the box to help build a new expression; doubleclicking any listed item will copy its name into the Expression box starting at your cursor position. You can
also use the autocomplete feature to avoid typing the entire expression by hand.
If you are binding a variable of type array or table, a Set Value button will appear to the right of the Bound
Variable box. Clicking this button will invoke the Edit Array (or Edit Table) dialog box, which provides an
easy graphical way to specify the values of each entry in an array or table. Note that you can also specify
the value of an array or table as a text expression.
If you need to refresh your memory about the meaning of a particular predicate, variable, or constant, simply
hover your mouse cursor over its name in the list box. After a moment, a tooltip with the description of that
item will appear.
77
7.
8.
9.
Deleting bindings
If a binding ever becomes obsolete, you can quickly remove it from a Canvas element by following these steps:
1.
Right-click the Canvas element, and select the Edit Bindings option from the menu that appears.
The Edit Bindings dialog box pops up and lists all the bindings attached to the Canvas element. Notice that
the box includes a Delete button.
2.
3.
4.
Optionally repeat Steps 2-3 to delete any other bindings that have become obsolete.
5.
Tip: If you change your mind about a deletion before you click the dialog boxs OK button, simply click the Cancel
button; all the revisions youve just made via the dialog box will be discarded. Alternatively, if you change your mind
after clicking the OK button, click the Edit menu and select the Undo option, or press Ctrl+Z; the changes youve just
made to the Canvas element will be reversed.
Reordering bindings
If you dont like the order in which variables are displayed in a Canvas element, you can rearrange them. This can
have an effect on the execution of your behavior, since the bindings are evaluated in the order that you specify. As a
result, some bindings can refer to variables bound by earlier bindings in the list.
To reorder bindings, follow these steps:
1.
Right-click the Canvas element, and select the Edit Bindings option from the menu that appears.
The Edit Bindings dialog box pops up and lists all the bindings attached to the Canvas element. Notice that
the box includes Up and Down buttons.
2.
3.
Click the Up button or Down button (depending on the direction in which you want to move the
binding).
The binding shifts by one position in the list.
4.
Repeat Steps 2-3 until the binding is precisely where you want it to appear on the list.
5.
6.
78
ArrayAddEntry: Action that adds an element to the end of the specified array. Format: specified_array:
array [in/out], element: any [in].
ArrayAppend: Action that appends the elements in one array to the end of another array. Format: source:
array [in], destination: array [out].
ArrayCopy: Predicate that returns a copy of the specified array (which is useful if the arrays values
periodically change and you need to preserve its current values). Format: specified_array: array [in]. Returns
value of data type array.
ArrayDelete: Action that deletes the element at the specified position of the specified array. Each
subsequent element in the array moves forward by one (i.e., position n becomes n-1), and the arrays size is
decreased by one. Format: specified_array: array [in/out], element_position: integer [in].
ArrayGet: Predicate that returns the value of the element at the specified position of the specified array.
Format: specified_array: array [in], , element_position: integer [in]. Returns value of data type any (because
the element can be of any data type).
ArrayInsert: Action that inserts an element at the specified position of the specified array. Each subsequent
element in the array moves back by one (i.e., position n becomes n+1), and the arrays size is increased by
one. Format: specified_array: array [in/out], element_position: integer [in], element: any data type [in].
ArrayPop: Predicate that deletes the element at the end of the specified array (decreasing the size of the
array by one) and then returns the value of the element. Format: specified_array: array [in]. Returns value of
data type any (because the element can be of any data type).
ArraySet: Action that sets the value of an element of the specified array. Format: specified_array: array
[in/out], element_position: integer [in], value: any [in].
ArraySetMinSize: Action that enlarges the array if it is smaller than the specified minimum size, creating
new entries of type Invalid. If the array is already the minimum size or larger, it is not changed. Format:
specified_array: array [in/out], minimum_size: integer [in].
ArraySetSize: Action that sets the array to exactly the specified size. If the array is currently larger, the
extra entries will be destroyed. If it is smaller, it will be expanded with new entries of type Invalid. If the array
is already the specified size, it is not changed. Format: specified_array: array [in/out], new_size: integer [in].
ArraySize: Predicate that returns the number of elements in the specified array. Format: specified_array:
array [in]. Returns value of data type integer.
Note: Because these actions and predicates are hard-coded in SimBionics engine and designed to be included in
every project, you cant edit or delete their declarations in the Catalog. This is indicated by a small lock symbol in the
upper-left of each core actions and core predicates icon in the Catalog.
Alternatively, if you need to work with a two-dimensional array, youll typically find it more convenient to use the table
data type. For more information on this option, see the Using tables topic.
Editing arrays
When specifying the initial value for a global variable of type array, or when creating a binding for an array variable,
you can use the Edit Array dialog box (shown below) to graphically define the contents of each entry in the array.
Array entries (sometimes called cells) are numbered starting from zero, as shown by the labels on the left-hand side of
the dialog box. To change the size of the array, type the desired size in the Number of array entries box and click the
Resize button. The dialog box will update to reflect the new number of entries in the array. If there are more entries
than can be displayed in the dialog, a scroll bar will appear to allow you to view all entries. Note that the dialog can
also be resized by dragging its corners or outside edges.
79
To edit the value of an array entry, click on that entry and type the desired value. Remember that an array entry may
contain values of any of the basic data types, including other arrays or tables. When youre finished, hit the Tab key to
move to the next entry, or click OK to close the dialog box. If you wish to automatically place one or more entries in
quotation marks to make them into strings, select the desired entries, right-click on one of them, and select Enquote.
If the value for an entry is particularly long, you can invoke a larger edit dialog box by right-clicking on the entry and
selecting the Edit Cell option. When you have finished typing in the Edit Cell dialog box, click OK to save the value. A
truncated version of the value will be displayed in the entry. You can view the full value by hovering your mouse cursor
over the entry; after a few moments, a tooltip with the entrys value will appear. You can also resize the column to
make more of the value visible by clicking on the edge of the column header and dragging left or right.
Array values as text expressions
Though in general it is much more convenient to specify the contents of an array or table variable using the graphical
Edit Array and Edit Table dialog boxes, it is also possible to create a binding expression that specifies the desired
values.
To do so, simply list the values for each entry of the array in order, separated by commas. The entire list of values
must be enclosed in curly brackets. You can use whitespace to make the list more readable, since it is ignored by the
editor. For example, to specify an array containing the values 1, 2, 3, you would write
{ 1, 2, 3 }
An array entry can be any of the SimBionic data types, as shown in this example:
{ 1.5, [10,15,-10], "hello", 2000, true }
An array entry can also contain expressions, including variables and predicates:
{ 3+5, "James" + "Bond", 2*x+my_predicate() }
Note that the entries in a global array can only contain expressions with constant values; no variables or predicates
are allowed.
An array entry can even be another array, as shown here:
{ { 1, 2, 3 }, { 4, 5, 6 } }
This represents an array with two elements, each of which is another array with three elements. This is actually
identical to a table with two rows and three columns.
Using tables
One of the most common forms of data structures in programming is the table, which is used to store a group of
conceptually related data elements organized by columns and rows.
For example, you might store information about each character in your program by creating columns devoted to First
Name, Last Name, Address, Phone Number, etc., and then devote a separate row to store the data for each individual
character (similar to the way a telephone book is organized). The collective group of data cells, or elements, holding all
this information would be your table.
A table is actually a two-dimensional array, so you could construct it using just the array data type. Because tables are
employed so often in programming, however, SimBionic provides special support for this data structure to ensure you
can create and manipulate tables easily.
You can set a parameter or variable to handle a table by declaring it to be a table data type. (For more information,
see the Choosing a data type topic.)
Tip: When youre creating a global table or a binding on a table variable, SimBionic provides a dialog box that makes it
easy for you to enter the tables initial values. To learn more, see the Editing tables topic.
After creating a table, you can manipulate it via SimBionics built-in table actions and predicates, which are
automatically included as part of every project. These actions and predicates are declared in the Catalog in a
subfolder named Tables (within the Core AP module); and their corresponding code is built into SimBionics engine.
The names, descriptions, and parameters of the built-in actions and predicates that deal with tables are as follows:
80
TableAddCol: Action that adds the specified new column to the right-hand side of the specified table. Note
that the new column must have the same number of rows as the table. Format: table: table [in/out],
new_column: array [in].
TableAddRow: Action that adds the specified new row to the bottom of the specified table. Note that the
new row must have the same number of columns as the table. Format: table: table [in/out], new_row: array
[in].
TableAppend: Action that appends the rows in one table to the bottom of a second table. Note that the two
tables must have the same number of columns. Format: source: table [in], destination: table [in/out].
TableColSize: Predicate that returns the number of columns in the specified table. Format: specified_table:
table [in]. Returns value of data type integer.
TableCopy: Predicate that returns a copy of the specified table (which is useful if the tables values
periodically change and you need to preserve its current values). Format: specified_table: table [in]. Returns
value of data type table.
TableDeleteCol: Action that deletes the column at the specified position of the table. Each subsequent
column in the table moves forward by one (i.e., position n becomes n-1), and the tables column size is
decreased by one. Format: specified_table: table [in/out], column_position: integer [in].
TableDeleteRow: Action that deletes the row at the specified position of the table. Each subsequent row in
the table moves forward by one (i.e., position n becomes n-1), and the tables row size is decreased by one.
Format: specified_table: table [in/out], column_position: integer [in].
TableGetCol: Predicate that returns an array containing the values of the specified column of the specified
table. Format: specified_table: table [in], column_position: integer [in]. Returns value of data type array.
TableGetEntry: Predicate that returns the value of the element at the specified position of the specified
table. Format: specified_table: table [in], row_position: integer [in], column_position: integer [in]. Returns
value of data type any (because the element can be of any data type).
TableGetRow: Predicate that returns an array containing the values of the specified row of the specified
table. Format: specified_table: table [in], row_position: integer [in]. Returns value of data type array.
TableInsertCol: Action that inserts the specified column, with initial values of your choosing, in the specified
position of the table. Each subsequent column in the table moves back by one (i.e., position n becomes
n+1), and the tables column size is increased by one. Format: specified_table: table [in/out],
column_position: integer [in], new_column: array [in].
TableInsertRow: Action that inserts the specified row, with initial values of your choosing, in the specified
position of the table. Each subsequent row in the table moves back by one (i.e., position n becomes n+1),
and the tables row size is increased by one. Format: specified_table: table [in/out], row_position: integer
[in], new_row: array [in].
TableRowSize: Predicate that returns the number of rows in the specified table. Format: specified_table:
table [in]. Returns value of data type integer.
TableSetCol: Action that replaces one column of a table with the specified array. Note that the array must
have the same number of rows as the table. Format: specified_table: table [in/out], new_column: array [in].
TableSetEntry: Action that sets the value of the specified element in the table. Format: specified_table:
table [in/out], row_position: integer [in], column_position: integer [in], value: any [in].
TableSetMinSize: Action that enlarges the table if it is smaller than the specified number of rows and
columns, creating new entries of type Invalid. If the table is already the minimum size or larger, it is not
changed. Format: specified_table: table [in/out], minimum_rows: integer [in], minimum_columns: integer [in].
TableSetRow: Action that sets the values in the specified row of the table to the values in the specified
array. Format: specified_table: table [in/out], row_position: integer [in], array_values: array [in].
TableSetSize: Action that sets the table to exactly the specified number of rows and columns. If the table is
currently larger, its extra rows and columns will be destroyed. If it is smaller, it will be expanded with new
entries of type Invalid. If the table is already the specified size, it is not changed. Format: specified_table:
table [in/out], num_rows: integer [in], num_columns: integer [in].
Note: Because these actions and predicates are hard-coded in SimBionics engine and designed to be included in
every project, you cant edit or delete their declarations in the Catalog. This is indicated by a small lock symbol in the
upper-left of each core actions and core predicates icon in the Catalog.
Alternatively, if you need to create just a single row of data, or if you need to create arrays of more than two
dimensions, you should instead use the array data type. For more information on this option, see the Using arrays
topic.
Editing tables
When specifying the initial value for a global variable of type table, or when creating a binding for a table variable, you
can use the Edit Table dialog box (shown below) to graphically define the contents of each entry in the table.
81
Table entries (sometimes called cells) are numbered starting from zero, as shown by the labels on the left and top
sides of the dialog box. To change the size of the table, type the desired size in the Number of rows and Number of
columns boxes and click the Resize button. The dialog box will update to reflect the new number of entries in the table.
If there are more entries than can be displayed in the dialog, scroll bars will appear to allow you to view all entries.
Note that the dialog can also be resized by dragging its corners or outside edges.
To edit the value of a table entry, click on that entry and type the desired value. Remember that a table entry may
contain values of any of the basic data types, including arrays or other tables. When youre finished, hit the Tab key to
move to the next entry, or click OK to close the dialog box. If you wish to automatically place one or more entries in
quotation marks to make them into strings, select the desired entries, right-click on one of them, and select Enquote.
If the value for an entry is particularly long, you can invoke a larger edit dialog box by right-clicking on the entry and
selecting the Edit Cell option. When you have finished typing in the Edit Cell dialog box, click OK to save the value. A
truncated version of the value will be displayed in the entry. You can view the full value by hovering your mouse cursor
over the entry; after a few moments, a tooltip with the entrys value will appear. You can also resize the column to
make more of the value visible by clicking on the edge of the column header and dragging left or right.
Using Enumerated Types
Understanding enumerated types
An enumerated type is a user-defined data type that consists of a set of named integer or string values. These values
can be used in place of normal strings and integers to improve the readability of your behaviors. They can also be
used to restrict the set of values that can be passed as parameters to an action or predicate, which can help prevent
authoring mistakes.
For example, suppose you have an action called SetSeason that has one integer parameter season. Technically, you
can pass any integer value to SetSeason, but only the values 1 (summer), 2 (fall), 3 (winter), and 4 (spring) have any
meaning. Thus, the following action expression is incorrect, even though it will not generate a compile error in
SimBionic:
SetSeason(5*2)
To catch mistakes like this, you could define an enumerated type season that has four integer values:
1
summer
fall
winter
spring
Now you can change SetSeasons parameter from type integer to your new type season and use the enumerated type
values in your action expressions:
SetSeason(winter)
This simultaneously makes the expression much more readable and also enables the SimBionic editor to generate a
compile error if any value other than the four legal seasons is used. It does not require a change to the underlying
action code, which still takes a parameter of type integer. When the above expression is invoked in the run-time
engine, SetSeason will be passed the value for winter, which is 3.
Note: Each value of an enumerated type is equivalent to an integer or string constant. You can think of an enumerated
type, then, as simply a named group of related constants.
Creating and editing enumerated types
82
2.
Notice that the dialog box contains sections for specifying the enumerated types name, description, and
values. In addition, it contains buttons for inserting and deleting values.
3.
Click in the Type Name box and type the name you want to give the enumerated type.
To ensure the readability of your program code, enter a name that clearly describes what the enumerated
type represents (e.g., Season, Color).
4.
Click in the Description box, and type a brief description of the enumerated type.
This documentation helps ensure your enumerated type will be readily understood by other members of
your team, and is also useful for refreshing your own memory in case you need to return to your project
months or years later.
5.
Select Integer or String to determine the data type of the enumerated types values.
If you select integer, each value of the enumerated type will be equivalent to an integer constant. If you
select string, they will be equivalent to string constants.
6.
7.
8.
Click in the Value field to edit the integer or string value for this value.
The SimBionic editor automatically assigns a value to new enumerated type values of type integer. If you
are happy with this value, you can leave it unchanged.
9.
10. Click the OK button of the Insert Enumerated Type dialog box.
The dialog box closes, and the enumerated type youve declared is saved and displayed under the Types
header in the Catalog.
83
If you ever change your mind about the name, description, and/or values of an enumerated type, you can edit the
declaration by either double-clicking it, or right-clicking it and selecting the Edit option from the menu that appears.
Doing so brings up an Edit Enumerated Type dialog box. You can then revise the text in the Name and/or Description
boxes; and revise any listed value by clicking on its Name or Value fields. You can also add additional values with the
Insert button or permanently remove a value by selecting it and clicking the Delete button.
Using enumerated types
Once you have created an enumerated type, you can use it exactly like any of the built-in SimBionic data types. You
can declare local and global variables of that type as well as parameters to actions, predicates, and behaviors. You
can also use it in expressions
SetColor(myentity,green)
and variable bindings
current_season = summer
The SimBionic editor provides an autocomplete feature for enumerated type values. While editing a parameter of an
enumerated type in an expression, you can hit the Tab key to display a pop-up menu listing all of the values for that
type, as shown here
Select the value you wish to use and it will be inserted into the expression.
84
Descriptors are hierarchical. Specifically, you first create a top-level descriptor, called a descriptor category, which
represents a single aspect or "dimension" of an entitys state. You can then create second-level descriptors branching
from that category. You can additionally create third-level descriptors that branch from a second-level descriptor,
fourth-level descriptors that branch from a third-level descriptor, and so on.
Each descriptor can have specific behaviors associated with it. When your program runs, SimBionic will always look
for the lowest-level descriptor youve specified that matches the entitys current state, in order to execute the most
specific behavior available. If that descriptor has no behavior associated with it, however, SimBionic will then try to
execute the behavior associated with the next-highest level in the descriptors hierarchy. If that behavior doesnt exist
either, SimBionic will again go to the next-highest level, until it reaches a descriptor in the category that does have a
behavior associated with it.
For example, assume youve created a descriptor category named Ducks; and within that category youve specified
three descriptors named Huey, Dewey and Louie. Also assume that youve created a generic set of behaviors for
Ducks, and individual character-based behaviors for Huey and Dewey respectively; but youve neglected to create any
behaviors for Louie. When your program runs, SimBionic will begin to execute the behavior youve created for Huey,
and then the behavior for Dewey. When it reaches Louie, however, SimBionic will recognize no customized behavior
exists for this entity, and so will instead apply the generic behavior you created for Ducksi.e., the next-highest level
in that descriptors hierarchy.
As another example, assume that in addition to your Ducks category, youve created a second descriptor category
named Emotions. Within this Emotions category, youve created descriptors named Happy, Sad, Angry, Hungry, and
Sleepy.
This second category of descriptors allows you to create subtle variations of behavior. For example, you can make the
behavior of Huey Sad be somewhat different from Huey Happy, and the behavior of Dewey Hungry be different from
Dewey Sleepy. Again, if you skip creating specific behaviors for a particular combination of descriptors and that
85
combination comes up in your program, SimBionic will simply use the behaviors associated with the next-highest level
descriptore.g., if no specific behaviors were created for Dewey Sleepy, SimBionic will use the behaviors created for
Dewey Emotions.
Combining descriptors from two or more categories and then building a variation on a behavior to assign to that
combination is called creating a polymorphism. In the world of biology, polymorphism refers to variations in organisms
within the same species. In SimBionic, the term is used to refer to creating behaviors that are slightly different from
each other under different conditions, resulting in a virtual world that feels more nuanced and realistic. You can always
identify the combination of descriptors associated with a particular polymorphism by checking the descriptor names
displayed on the bottom tab of the Canvas.
Note: You should, at minimum, associate a behavior with any top-level descriptor or combination of top-level
descriptors. This ensures that SimBionic will always be able to locate a behavior to execute regardless of an entitys
descriptor status. Otherwise, SimBionic may occasionally be unable to locate a behavior to execute, causing your
program to crash or perform erratically.
Descriptors and global variables
For every descriptor category you create, the SimBionic editor automatically adds a corresponding global variable of
type string to the Polymorphic folder in the Globals list in the Catalog. These global variables (which you cannot
directly delete or rename) are used to store the current state of an entity for each of the various descriptor categories.
By default, each variable is set to the topmost descriptor in the hierarchy for the corresponding category. For example,
the descriptor category Ducks would have a corresponding global variable named gDucks whose default value would
be "Ducks".
When an entity invokes a behavior (by executing a behavior rectangle), the run-time engine dynamically selects the
polymorphism of that behavior that is most appropriate for the entity based on its current state. To determine what the
current state of the entity is, the engine examines the values of the special global variables in the Polymorphic folder.
You can therefore change an entitys state by simply binding a new value to one of these global variables (just as you
would with any other variable see the topic Attaching bindings to a Canvas element for details). Keep in mind that
the new value should also be one of the descriptors in the hierarchy for that category. Binding a non-descriptor value
to these special global variables will cause errors when that entity attempts to invoke a new behavior, since the runtime engine will be unable to find a matching polymorphism.
You should note that descriptors and polymorphisms could alternatively be implemented using ordinary global
variables and lots of conditions and behavior rectangles. Under this approach, each time you invoked a behavior (e.g.,
Attack), you would need to check the value of the global "state" variables and then execute the behavior rectangle for
the appropriate version of that behavior (e.g., Attack_Scout_Injured). The key differences between this approach and
SimBionics approach are:
Descriptors are clearly associated with particular behaviors (because the bottom tab of the Canvas always
displays the descriptors linked to the displayed behavior).
Polymorphisms conceal the "machinery" i.e., the extra conditions and behavior rectangles needed to
select and invoke the appropriate version of a behavior based on an entitys current state. They also neatly
group all variations of a behavior in one place for easy comparison and editing.
Descriptors are hierarchical, so even if theres no behavior that matches a specified combination of
descriptors, SimBionic will be able to identify and execute a more generic version of the requested behavior.
You may find for your project, however, that there are some aspects of an entitys state that will only affect behavior
selection under certain specific conditions. If this is the case, you might choose to make those aspects ordinary global
variables instead of descriptor categories, and then explicitly query the global variables where necessary in your
behaviors. Whether you set an attribute to be a global variable or a descriptor really depends on how central the
attribute is to your simulation or gamee.g., how often you expect it to be a determining factor in selecting behaviors.
For more on creating descriptors and polymorphisms, see the Creating and revising descriptors and Creating
polymorphisms topics.
Examples of descriptors
While you can select anything you want to be a descriptor, youll generally create at least one descriptor category that
refers to the type of an entity. Here are four examples of this kind of descriptor category:
86
This example illustrates that any descriptor can contain its own sublevel of descriptors. Specifically, the category
Classic_Cars contains three second-level descriptors: 1940s, 1950s, and 1960s. And each of these descriptors has its
own third-level descriptors, which are particular cars of that era. Each particular car could additionally have its own
fourth-level descriptors (e.g., 1958_Ford_Skyliner could have Two_Door and Four_Door descriptors branching from it).
Its also worth noting this sample category avoided using spaces. Thats not technically required; and if you create only
one descriptor category for your project, theres no reason to not simply use spaces (e.g., Classic Cars vs.
ClassicCars or Classic_Cars). If you create two or more descriptor categories, however, we recommend that you
double up words or use the underscore, because otherwise you may have trouble accurately reading the names on
the Canvas tabs of the polymorphisms you create.
For example, if your project contained the Detective and ClassicCar hierarchies above, and you customized a
behavior for Shaggy driving a 1945_Cadillac_Convertible, the Canvas window tab for your polymorphism would read
"Shaggy 1945_Cadillac_Convertible," which makes it fairly clear that youre combining two descriptors. If youd used
spaces when creating the second descriptor, though, the resulting tab would read "Shaggy 1945 Cadillac Convertible,"
and you might not be able to tell at a glance whether this referred to one, two, three, or four descriptors combined.
More examples of descriptors
While your project will typically have at least one descriptor category tied to the type of an entity (as discussed
previously), it can additionally include categories based on any other terms or attributes that describe the possible
states that an entity can be in. Here are some examples of such attribute-based hierarchies:
87
These descriptors represent different states that your entities may attain as conditions change over the course of your
simulation or game. These attribute-based descriptors can therefore help you create nuances and subtleties in the
way your entities behave.
Tip: As a rule of thumb, you should probably avoid creating more than around three descriptor categories in a project,
because polymorphisms with four or more names tend to create more confusion than clarity. But thats simply a
guideline. SimBionic allows you to create an unlimited number of descriptors and polymorphisms, so youre free to use
these features in whatever manner you determine best suits a particular project.
Creating and revising descriptors
If youve read the Understanding descriptors topic, youre now ready to create, rename, delete, and reposition
descriptors. The following four sections tell you how.
Creating first-level descriptor categories
To create one or more first-level descriptor categories, follow these steps:
1.
88
Notice that at the top of the pane is a header that says Project Untitled Descriptors. (If youve previously
saved your work, Untitled is replaced by the name of your project.) Youll right-click this header to create
new descriptor categories.
Also notice that a checkbox appears next to each descriptor in the pane. Youll use these checkboxes to
assign descriptors to polymorphic behaviors (as described in the next topic, Creating polymorphisms). The
checkboxes of first-level categories are pink, and the checkboxes of all other descriptors are green.
If youre starting a new project, the Descriptors pane begins with a single category, which is named Empty.
This is simply a placeholder which you must rename. (Alternatively, if you only want to add new descriptors
to existing ones, skip to Step 5.)
2.
Click the Empty descriptor category, wait a second or two, and then click it again.
The name of the descriptor category is highlighted, allowing you to replace it with a different name.
3.
Type the name you want to give your first descriptor category.
To ensure the readability of your program code and polymorphism windows, choose a name that clearly
represents the entities or attributes to which the category refers.
4.
Press Enter, or click anywhere outside the name youve just typed.
Your first descriptor category is created with the name you specified.
If your project requires only a single descriptor category, skip to the next section, "Creating lower-level
descriptors."
5.
To add a new descriptor category, right-click the Project Descriptors header at the top of the
Descriptors pane.
Be sure to click using your right (not left) mouse button. If youre starting a new project, the header says
Project Untitled Descriptors; otherwise, the name of your project appears in place of Untitled. After you
right-click, an Insert Descriptor Category option appears.
6.
89
7.
Type the name you want to give your new descriptor category.
Again, to ensure the readability of your program, choose a name that clearly represents the entities or
attributes to which the category refers.
8.
Press Enter, or click anywhere outside the name youve just typed.
Your descriptor category is created with the name you specified.
9.
If you want to create additional first-level descriptor categories, repeat Steps 5-8.
Keep in mind that creating more than three first-level descriptor categories can result in polymorphic tabs
that are excessively confusing. However, theres technically no limit to the number of categories you can
create, so you should do whatever makes sense for your particular project.
2.
3.
4.
Press Enter, or click anywhere outside the name youve just typed.
Your descriptor is created with the name you specified.
5.
Renaming descriptors
If you change your mind about the name youve given a descriptor, you can rename the descriptor quickly and easily.
To do so, follow these steps:
1.
2.
3.
4.
5.
Deleting descriptors
If an descriptor becomes obsolete, you can remove it with a couple of mouse clicks. To do so, follow these steps:
1.
2.
Note: You cant undo any actions you perform in the Descriptors pane. Therefore, think twice before deleting a
descriptor, particularly if it has many descriptors below it.
Repositioning descriptors
The Descriptors pane normally lists descriptors on the same level in the order in which you created them. How
descriptors are ordered within the same level has no effect on SimBionics execution; but if youd like to rearrange a
levels display to make it more readable or convenient, follow these steps:
90
1.
2.
Click the Move Up or Move Down option (depending on the direction you want to move the
descriptor).
The descriptor shifts by one position.
3.
Repeat Steps 1-2 until the descriptor is precisely where you want it to appear in its level.
4.
After youre done creating and revising your descriptors, youre ready to use them to create polymorphic behaviors. To
learn how, see the next topic, Creating polymorphisms.
Creating polymorphisms
In the world of biology, polymorphism refers to variations in organisms within the same species. Similarly, in SimBionic
a polymorphism is a behavior thats a variation on another behavior in your project.
As explained in the Understanding descriptors topic, a polymorphism results when you combine descriptors from two
or more descriptor categories and then build a variation on a behavior to assign to that combination. By creating
behaviors that are slightly different from each other under different conditions, you can build a virtual world that feels
more nuanced and realistic.
To create one or more polymorphisms for an existing behavior, follow these steps:
1.
Click the Descriptors tab in the Project window, and create all the descriptors youll be using for
your project.
If you arent sure how to do this, see the Creating and revising descriptors topic.
2.
Move to a generic behavior in your project for which you want to create one or more polymorphisms.
If you arent sure how to do this, see the Navigating behaviors topic. After you move to the behavior, its
displayed on the Canvas.
3.
4.
5.
For each descriptor category youve created, click the checkbox to the left of the descriptor to which
you want to assign this polymorphism.
A checkmark appears to the left of each descriptor youve selected. Also, the name of each selected
descriptor appears on the tab of the current Canvas page.
6.
Edit the Canvas elements to create a new behavior for the combination of descriptors youve
selected.
Once youre done revising the Canvas elements, your new polymorphism is complete. When you compile
and run your program, SimBionic will execute the behavior youve just created every time an entity matches
the combination of descriptors youve specified for this polymorphism.
Alternatively, if you would prefer to start from scratch in your new polymorphism (instead of revising the original
behavior), right-click on the tab at the bottom of the Canvas and select the Insert Polymorphism option. A new blank
page will be added to the behavior. You can assign descriptors to this new polymorphism as described in Step 5
above.
Tip #1: If you ever want to assign different descriptors to an existing polymorphism, simply select the polymorphism by
clicking its tab on the Canvas and then click the checkboxes of the descriptors you want. The names on the tab of the
polymorphism will instantly reflect your changes.
Tip #2: If you dont like the order in which a particular polymorphism appears on the Canvas, click the tab of
polymorphism and, while holding your mouse button down, drag it to where you want it (i.e., to the left or right), and
then release your mouse button. The polymorphism is instantly repositioned to the location you specified.
Tip #3: If a polymorphism ever becomes obsolete, you can remove it by right-clicking its tab and selecting the Delete
Polymorphism option from the menu that appears. You cant undo this deletion, however, so always think twice before
removing a polymorphism.
For more information about descriptors, see the Understanding descriptors and Creating and revising descriptors
topics.
91
Creating Programs
Understanding SimBionic's flow of execution
A SimBionic programs operation primarily consists of evaluating conditions to determine what invoked behavior and/or
action to go to next, and then invoking the appropriate behavior and/or executing the appropriate action. Within this
general framework, however, are subtleties you need to understand to ensure that your programs perform in precisely
the ways you intend.
The initial steps of the engine are determined by the API methods you use in the C++ or Java code of your simulation
or game. You must always begin by starting up the engine via the Initialize method. You then typically create each
entity you want to be active and assign it an initial behavior via the CreateEntity method.
Every time you create an entity, the engine automatically creates three constructs devoted to that entity:
Global variables: Variables that are declared in the Catalog and store values across behaviors. The engine
creates a separate copy of your projects global variables for each entity, so that each set can store values
exclusive to that entitys activities. For more information, see the Understanding variables topic.
Message queue: A storage area devoted to messages sent to a particular entity. The queue holds each
message until the entity accesses the message, optionally reads it, and explicitly discards it. For more
information, see the Communicating via group messages topic.
Execution stack: A data structure that, in SimBionic, is devoted to tracking the behaviors of a particular
entity. More information about this critical component appears shortly.
If rectangle A is an action and its connector leads directly to another rectangle, SimBionic assigns execution
for the next clock tick to flow to that second rectangle.
93
If rectangle A is an action and its connector leads to a condition or series of conditions that all evaluate as
true, SimBionic assigns execution for the next clock tick to flow to the rectangle that directly follows the
condition or series of conditions.
If rectangle A invoked a behavior that hasnt yet completed execution and its connector leads directly to
another rectangle, SimBionic assigns execution to remain within the invoked behavior for the next clock tick.
This cycle will repeat until the behavior has completed (i.e., reached a final action), at which point execution
will flow to the second rectangle.
If rectangle A invoked a behavior that hasnt yet completed execution and its connector leads to a condition
or series of conditions that all evaluate as true, SimBionic aborts the invoked behavior (i.e., pops it from the
stack) and assigns execution for the next clock tick to flow to the rectangle that directly follows the condition
or series of conditions. (For more information, see the Checking for completed behaviors topic.)
If none of the situations above apply, and none of rectangle As connectors lead to conditions that all
evaluate as true, and if there are any behaviors above this one on the stack, SimBionic will proceed to check
the connectors coming out of the current rectangle in the next behavior on the stack, according to the rules
described above.
Otherwise, SimBionic assigns execution for the next clock tick to remain within the current rectangle.
Specifically, if the rectangle is a behavior that hasnt been completed, the behavior will continue executing
during the next clock tick; while if the rectangle is an action, or is a behavior that has been completed, then
no further execution will take place in the rectangle during the next clock tick. In any case, the rectangles
connectors will be evaluated again during the next tick. The cycle just described continues until one of the
connectors evaluates as true.
Note: If there are any bindings attached to the rectangle, they arent re-executed during subsequent clock
ticks.
Tip: If youd prefer that an action continue being executed over and over until one of its current connectors
evaluates as true (as opposed to doing nothing after the first clock tick), you can add a last connector that
leads back to the rectangle. To do so, press the Crtl key and, while keeping it held down, click the rectangle
and drag your mouse outward until you see a green starting point, and then drag your mouse back to the
rectangle until you see a red endpoint. When you release your mouse button, the connector curves to both
begin and end in the rectangle.
Again, the above represents the engines typical flow of execution. There are some exceptions to these general rules,
though, which are covered in the next section.
Exceptions to the rule
While the engine typically executes an action per entity every clock tick, you can designate an urgent behavior to run
from beginning to end in a single clock tick, as described in the topic Setting a behavior to run in one tick. You can also
specify that a behavior should not be aborted or suspended by behaviors below it on the execution stack, as described
in the topic Setting a behavior to run uninterrupted.
Another notable exception involves connectors. Specifically, if a connector coming out of an interruptible behavior
evaluates as true, then SimBionic will normally abort the behavior on the spot and redirect execution to flow to the
rectangle directly following the condition.
However, if you dont want the original behavior to be abandoned but just temporarily suspended while the second
rectangle executes, you can designate the connector coming out of the behavior to be an interrupt connector. When
the rectangle following such a connector is triggered, it takes temporary control of execution until its done its job, and
then returns execution to the original behavior so it can pick up where it left off. You can readily identify an interrupt
connector on the Canvas because its displayed with broken lines instead of a solid line.
For more information, see the Creating an interrupt topic.
Finally, "every entity gets an action executed every clock tick" is only true if you accept the engines default update
setting. If you create a large number of entities, you may find it best to set less-critical entities to update less frequently
(e.g., every other tick or every third tick). This provides the engines scheduler with the flexibility it needs to create
about the same load on the CPU for every clock tick, ensuring that your simulation or game runs smoothly. For more
information, see the topic Controlling the entity scheduler.
Checking for completed behaviors
When a standard (i.e., interruptible) behavior is invoked, during every clock tick SimBionic executes a rectangle within
that behavior and then evaluates the connector(s) coming out of that behavior.
If any of the behaviors connectors leads to a condition that evaluates as true, the behavior will be aborted mid-stream.
SimBionics execution will then be redirected to flow down the path following the condition.
In some cases, this is precisely what you want to occurfor example, when a new situation arises that makes the
current invoked behavior superfluous.
In many cases, however, youll want a behavior to entirely finish before execution flows down the path of one of its
connectors. To ensure this occurs, you must insert an additional condition that checks on whether the behavior is done
executingi.e., has reached a final action. This checking is performed by the IsDone predicate, which evaluates as
94
Creating Programs
false when a behavior is still running and true when the behavior is completed. IsDone is available in every SimBionic
project; its automatically declared in the Catalog in the Core AP module, with corresponding code built into
SimBionics engine.
Implicit IsDone
Using IsDone is only necessary when a behaviors connector leads to a condition. Thats because the condition allows
you to test for a change in your virtual world that, if it becomes true, may make you want to abort the behavior.
In contrast, if a behaviors connector leads to a rectangle, SimBionic assumes that you dont want to transition out of
the behavior until its completedbecause you arent checking for any changed situation that might impel you to
abandon the behavior.
As a result, when a behaviors connector leads to a rectangle, SimBionic automatically inserts an invisible IsDone
condition between the behavior and the rectangle. This is referred to as an implicit IsDone, because its always built
into a behavior-to-rectangle connection for you; and even though you cant see it, you can assume its there.
Therefore, you never need to insert an IsDone condition between an invoked behavior and a rectangle; but you do
need to use IsDone whenever you want to ensure a condition doesnt abort a behavior.
An IsDone example
To help you visualize the practical usage of IsDone, assume your primary behavior on the Canvas is named Main, and
within Main you invoke another behavior called DoSomething. Also assume that coming out of DoSomething are three
connectors that are respectively designed to handle emergency orders, new orders, and standard orders, as shown
here:
After executing one of DoSomethings rectangles, SimBionic evaluates the first connector, which leads to a condition
that checks on whether emergency orders have been received. If they have, the DoSomething behavior is immediately
aborted, and SimBionic redirects execution to the EmergencyOrders action. Otherwise, SimBionic proceeds to
evaluate the middle connector.
The second connector leads to two conditions. The first is an IsDone condition that checks on whether DoSomething
has completed executing. If IsDone evaluates as true, then a second condition checks on whether new orders have
been received. If this condition also evaluates as true, then SimBionic directs execution to the NewOrders action.
Otherwise, SimBionic proceeds to evaluate the final connector.
The last connector leads to a default StandardOrders action. No IsDone condition is visible between DoSomething and
the action; but because this is a behavior-to-rectangle connection, it automatically includes an implicit IsDone. As a
result, the StandardOrders action wont be triggered unless DoSomething has completed execution by reaching an
internal final action. Otherwise, SimBionic realizes that its run out of connectors and returns the flow of execution to
DoSomething.
If DoSomething has been declared as a multi-tick behavior, SimBionic will execute the cycle above once every clock
tick, until DoSomething is either aborted or completed.
Alternatively, if DoSomething has been declared as a one-tick interruptible behavior, SimBionic will execute the cycle
above over and over again during the same clock tick, until DoSomething is either aborted or completed.
Note #1: If DoSomething had been declared as a one-tick non-interruptible behavior, then the description above
wouldnt apply. Instead, SimBionic would skip evaluating any of DoSomethings connectors until the behavior had
entirely finished executing. As a result, you never need to use an IsDone condition with a non-interruptible behavior,
because the behavior is guaranteed to complete execution before it encounters any conditions that might otherwise
abort it. To learn more about this option, see the Setting a behavior to run uninterrupted topic.
95
Note #2: In the example above, all the connectors are standard ones. Alternatively, however, we couldve set one or
more of the connectors to be an interrupt. In this case, whenever all the conditions (both explicit and implicit) on an
interrupt connector evaluated as true, DoSomething would not be aborted, but just temporarily suspended while
execution flowed to the connectors rectangle. After the rectangle finished executing, control would return to
DoSomething, which would continue executing where it left off. The interrupt option therefore provides you with a way
of responding to new situations rapidly without permanently disrupting a current behavior. To learn how to convert a
standard connector into an interrupt, see the Creating an interrupt topic.
Exploring IsDone more deeply
To help you better understand the way IsDone operates, heres a detailed description of how SimBionics engine
would execute the above program segment:
When SimBionic starts the Main behavior, it creates and places an execution frame for Main on its stack. This frame
includes a status flag that SimBionic can set to false or true, and indicates whether a behavior thats invoked by Main
has completed execution. Its this flag that the IsDone predicate checks to return its value of true or false.
Execution then flows to Mains initial rectangle, which in this scenario is DoSomething. Because the latter is a
behavior, SimBionic first sets the status flag on Mains execution frame to zero, indicating that it now has an invoked
behavior thats in the process of executing. SimBionic then creates and places an additional execution frame on its
stack for DoSomethingi.e., directly above the one for Main.
Note: DoSomething also has a status flag, because it might also invoke a behaviorwhich in turn might invoke its
own behavior, ad infinitum. Each invoked behavior clears the status flag on the execution frame that called it and then
gets its own execution frame placed on top of the stack.
After DoSomething has executed a rectangle, SimBionic checks the behaviors first connector. If emergency orders
have been received, then the first condition evaluates as true. In this case, SimBionic immediately abandons its
execution of the DoSomething behavior, sets Mains status flag to 1, and pops DoSomethings execution frame from
its stack. (Note: If DoSomething invoked a behavior itself, and that behavior invoked another behavior, and so on,
SimBionic abandons the execution of all those behaviors and pops the execution frame of each of them from the stack
right before popping DoSomething.) Execution then flows to the EmergencyOrders action.
On the other hand, if emergency orders have not been received, then SimBionic evaluates the second connector with
its explicit IsDone, and then the third connector with its implicit IsDone. Unless the DoSomething behavior is
completed, though, neither of these IsDone conditions evaluates as true. In this case, execution flows back to
DoSomething on the next clock tick; SimBionic executes another rectangle within DoSomething; and SimBionic then
checks the behaviors three connectors again.
Assuming no emergency orders appear, this cycle continues until the DoSomething behavior is finished. The status
flag on Main's execution frame is then set to 1; and the IsDone conditions on the last two connectors will now both
evaluate as true. If new orders have been received, SimBionic will pop DoSomething's execution frame from its stack,
and the program will proceed to the NewOrders action. Otherwise, SimBionic will still pop DoSomething's execution
frame from its stack, but the program will instead proceed to the StandardOrders action.
Because of its key role in regulating the execution of behaviors, IsDone is the most important predicate in SimBionic.
Be sure to insert IsDone in front of any condition coming out of an interruptible behavior that you dont want triggered
until the behavior has finished executing.
IsDone requires no parameters. To use it, simply include the following in a condition or binding on the Canvas:
IsDone(). It returns a value of data type Boolean.
Compiling your project
The word compile means "to put together or compose from materials gathered from several sources." In the software
world, compile refers to assembling various bits of source code and translating it all into a single program file that can
be executed by an engine.
Similarly, before you can execute your SimBionic project in the run-time engine, you must first compile it into a format
that the engine understands. The compilation process will condense your descriptors; your action, predicate, behavior,
and variable declarations; and the actions, behaviors, conditions, and connectors youve created on the Canvas to
visually represent your program (stored within separate .APD, .BTN, and .SBP files) into a compiled project file and
zero or more package files.
To compile your project, you can either click the Build menu and select the Compile option; press F7; or click the
Compile button in the upper-right of the editor window.
When youre ready to compile your SimBionic project, follow these steps:
1.
2.
96
Creating Programs
Notice the text box named Path for compiled project (SIM) file, and the Browse button to its right. You can
specify the folder and filename under which you want to save your compiled project file by either typing the
information directly, or by using your mouse to browse your hard drive or LAN.
3.
If you want to enter the path and filename directly, click in the Path for compiled project (SIM) file
text box; type the path and filename under which you want to save your compiled project file; and
press Enter.
For example, if you wanted to save the file on your C drive in a folder named SimBionic Projects and under
the name MyProject.sim, youd type C:\SimBionic Projects\MyProject.sim. (Including the .SIM extension
is optional; if you leave it off, SimBionic will add it for you.) After you press Enter, your setting is saved. To
now compile your project, skip to Step 9.
4.
To specify the path and filename by browsing folders, click the Browse button to the right of the
Path for compiled project (SIM) file box.
A file dialog box like this appears:
97
5.
Specify the path and filename for your compiled project file.
For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.
6.
Click Save.
The path and filename you specified are entered into the Path for compiled project (SIM) file text box.
7.
8.
Click OK.
Your setting is saved. Youre now ready to compile your project.
9.
Click the Build menu and select the Compile option; or press F7; or click the Compile button (the
third button from the right on the second row of toolbars).
Any of the above actions compiles your project andif no serious problems are encounteredsaves the
results in the folder and filename you specified. Any package files you have specified will also be saved to
that folder.
In addition, any errors (i.e., serious problems) and warnings (i.e., minor or potential problems) the compiler
encountered are listed in red in the Build pane of the Output window at the bottom of the editor window, as
in this example:
10. To examine the cause of any listed error or warning, double-click the pertinent red message in the
Build pane.
After you double-click, the action, behavior, condition, or connector to which the message refers is displayed
and highlighted on the Canvas.
Alternatively, you can move from one error or warning to the next by clicking the View menu and then
selecting Go->Prev Error or Go->Next Error.
11. Revise the highlighted Canvas element to correct the reported problem, and then recompile (e.g.,
click the Compile button again) to verify that your fix was effective.
Repeat Steps 10-11 until youve eliminated all error messages, as well as any warning messages that you
consider to be legitimate problems.
98
Creating Programs
When youre done, your compiled project file is ready for execution.
After youve compiled your project, you can either:
Test it out via the interactive debugger. For more information, see the Debugging your project topic.
Try to execute it immediately via the run-time engine. For the C++ engine, see the Understanding the
C++ run-time engine, Using the C++ engine's API methods, and Starting and controlling the C++ run-time
engine topics. For the Java engine, see the Understanding the Java run-time engine, Using the Java
engine's API methods, and Starting the Java run-time engine topics.
.SBP (SimBionic Project): Stores all the behaviors youve created on the Canvas as well as your
descriptors and global variables. A single .SBP file is created per project. Example: MyProject.sbp.
.APD (Action and Predicate Declarations): Stores all the actions and predicates declared in an AP
module. A single .APD file exists per AP module. Example: MyProject.apd.
.BTN (Behavioral Transition Network): Stores a single behavior declared in the Catalog for your project,
along with all of its polymorphisms. One .BTN file is created for each behavior in the Catalog. Example:
MyProject.btn.
.TPD (TyPe Declarations): Stores all the enumerated types and classes declared in your project. A single
.TPD file exists per project. Example: MyProject.tpd.
SimBionic generates these four types of files instead of just one to provide you with the option of copying the action,
predicate, behavior, and type declarations youve created for your current project into subsequent projects. You can
load an .APD file via the File menus Import AP Module option; and you can load a .BTN file by right-clicking the
Behaviors header in the Catalog and then selecting the Import option from the menu that appears. For more
information, see the Importing AP Modules and Importing a behavior (BTN) topics. Also, keeping the files separate
allows multiple people to work on the same project at once, as described in the topic Working with multiple authors.
In addition, SimBionic automatically generates two types of files when you compile your project:
.SIM (Simulation file): Also known as the compiled project file. Stores the compiled version of your project
in a form that can be understood by the SimBionic engine. To generate this file, click the Build menu and
select the Compile option, or press F7, or click the Compile button in the upper-right of the editor window.
Example: MyProject.sim. For more information, see the Compiling your project topic.
.BIM (Behavior sIM file): Also known as a package file. Stores the compiled version of a package,
containing one or more behaviors. By default, no package files are generated. To configure the package
settings for your project, see the topic Working with behavior packages . Any packages that you have
specified in your project settings will be automatically generated when you compile your project.
SimBionic can also optionally generate C++ or Java files to help you implement your actions and predicates:
.H (C++ Header file): A C++ header file that lets you refer to the actions and predicates in your project via
symbolic names instead of the ID numbers assigned them by the SimBionic editor. To generate it, click the
File menu, select Export, select Export Header, specify the files name and path, and click the Save button.
You can then #include the file in your simulations or games C++ code. Example: MyProject.h. For more
information, see the Creating C++ symbolic names for actions & predicates topic.
.CPP (C++ source file): A C++ source file that provides a skeleton implementation of the AI_Interface class,
including method skeletons for each of your actions and predicates. To generate it, click the File menu,
select Export, and select Export Skeleton Code. Example: MyProject.cpp. For more information, see the
Generating skeleton code for C++ topic.
.JAVA (Java file): SimBionic can generate two kinds of Java files. The first kind defines symbolic names for
the actions and predicates in your project that you can use instead of the ID numbers assigned them by the
SimBionic editor. To generate this file, click the File menu, select Export, select Export Constants, select
Java, specify the files name and path, and click the Save button. For more information, see the Creating
Java symbolic names for actions & predicates topic. SimBionic can also generate a skeleton implementation
of the SB_Interface class for you, including method skeletons for each of your actions and predicates. To
generate it, click the File menu, select Export, and select Export Skeleton Code. For more information, see
the Generating skeleton code for Java topic. Once you have generated either of these files, you can import
them in your simulations or games Java code. Example: MyProject.java.
99
If everything doesnt work as planned, however, you can identify and fix your project using SimBionics interactive
debugger, which allows you to step through your program clock tick by clock tick, and watch how the behaviors youve
created on the Canvas result in changes in the entities, variables, and stacks driven by the run-time engine.
There are four basic steps to using the debugger, described in the following topics: Configuring the debugger,
Enabling debugging for your application, Launching the debugger, and Using the debugger.
Configuring the debugger
Before you can use the interactive debugger with your application, you first need to configure it by following these
steps:
1.
2.
Notice that there are two text boxes labeled Simulation executable and Command line arguments. The first
box lets you specify the folder location and filename of your SimBionic-enabled application. The second box
lets you enter any command line arguments for your application.
There is also a Connection Timeout box, which allows you to specify for how long (in seconds) the editor
should try to establish a debugging connection to your application.
In addition, the dialog box includes a Server IP address box, for when the application you want to debug is
running on a different PC; and a Loopback checkbox, for when the application is running on the same PC.
3.
Click in the Simulation executable text box, and type the path and filename of your SimBionicenabled application.
For example, if the application is on your C drive in a folder named My Simulations and under the name
MySimulation.exe, youd type C:\ My Simulations\MySimulation.exe.
Alternatively, click the Browse button directly to the right to bring up a dialog box that lets you locate the
executable file using your mouse. After you do so, double-click the file to have its path and name entered
into the Simulation executable text box for you.
4.
Optionally click in the Command line arguments text box, and type any arguments that should be
passed to your application.
For example, if youve written your simulation to accept a -n argument to specify the number of entities it
generates, you could type -n 9 to tell it to create nine entities after launching.
5.
Optionally click in the Connection Timeout box and specify a new timeout duration (in seconds).
Normally the default value of thirty seconds is more than adequate. In some cases, a longer timeout is
necessary to enable the debugger to successfully connect to your application for example, if your
application takes longer than thirty seconds to start up.
100
Creating Programs
6.
If the application you wish to debug is on the same computer that youre running the editor on, make
sure the Loopback option is checked (which is the default) and then proceed to Step 7. Otherwise,
click Loopback to turn the checkmark off, click in the Server IP address box, and type the address of
the computer on which the second file resides.
The SimBionic interactive debugger uses the TCP/IP protocol to communicate with your SimBionic-enabled
application. This gives you the freedom to run your application on one computer and debug it from a
different computer on the network. This can be useful in certain situations, such as when the user interface
for your application occupies the entire screen, leaving no room to view the editor.
7.
Click OK.
Your settings are saved. Youre now ready to debug your project.
2.
Optionally change the timeout duration for the debugger by setting the debugConnectTimeout
variable in the AI_Config or SB_Config object.
By default, after you call Initialize the run-time engine will wait thirty seconds for a debugging connection
from the editor. You can change this duration via the debugConnectTimeout variable.
3.
Make sure that youre using the Development version of the run-time engine.
The Production version of the engine does not include the code necessary to run the interactive debugger.
You can only start an interactive debugging session with the Development version of SimBionic. If you are
uncertain which version of the run-time engine you are currently using, you can call the GetVersion API
method to find out.
If youve already configured the SimBionic editor for debugging (see the topic Configuring the debugger), youre ready
to start an interactive debugging session. See the topic Launching the debugger for more information.
Launching the debugger
Once youve configured the interactive debugger for your project and enabled debugging for your application, you can
initiate a debugging session in one of two ways:
Quick-Run: Click the Build menu and select the Quick-Run option; or press Ctrl+F5; or click the Quick-Run
button (the "!" button, which is rightmost on the second row of toolbars). This does three things in
succession: first, it launches your application using the command line arguments in the Project Settings
dialog box; second, it initiates a TCP/IP debugging session between the editor and your application; and
third, it switches the editors user interface into interactive debugging mode.
Connect: First launch your application from Windows (using whatever command line arguments you want).
Once your application is running, click the Build menu and select the Connect option, or click the Connect
button (the "lightning bolt" button, which is the next to last on the second row of toolbars). This initiates a
TCP/IP debugging sessions between the editor and your application and switches the editors interface into
interactive debugging mode.
Using the Quick-Run option is typically more convenient, because allows you to launch your application and initiate a
debugging session with a single mouse click.
However, if you have a series of different command line arguments you want to test frequently, continually changing
the arguments in the editors Project Settings dialog box could become a nuisance. In this case, you may prefer
creating a Windows shortcut for each set of arguments, launching your simulation or game via these shortcuts, and
then using the Connect button to connect to and display the debugger.
Note: When debugging is enabled in your application, the Initialize API method will not immediately return after
loading your project but will instead wait for a connection from the editor before proceeding. If a connection is not
received within thirty seconds, the debugger will be disabled and the application will execute normally. (You can
change this timeout for details, see the topic Enabling debugging for your application.)
Using the Debugger
101
You can use these commands and windows to step through your project as slowly as a clock tick at a time, and study
how your C++ or Java code, in conjunction with the current behavior on the Canvas, results in changes to your
programs entities, execution stacks, and variable values. In addition, you can use the Output window (at the bottom)
to view the moment-by-moment messages that are being sent from your application to the debugger (displayed in
black text) and from the debugger to your application (displayed in green text).
Tip: If you find a column in any window is too narrow to display your debugging data, resize the column by clicking its
border and dragging it outward.
You can end an interactive debugging session at any time by clicking the Debug menu and selecting the Stop option;
or pressing Shift+F5; or clicking the Stop button (the third button on the Debug toolbar). You can also return to the
interactive debugger at any time by using the Quick-Run or Connect commands again.
Entities window
The Entities window in the interactive debugger allows you to track the activities of every entity created by your
simulation or game via the CreateEntity or MakeEntity API method. The window devotes a row to each entity, and
provides data about the entity via the following six columns:
102
ID: Displays the entitys ID number. This number is assigned on the fly by SimBionics run-time engine when
your program creates the entity via the CreateEntity or MakeEntity API method.
Entity Name: Displays the text name you optionally assigned to the entity via the CreateEntity or
MakeEntity API method. If you skipped creating a text name for the entity, this cell is blank.
Current Behavior: Displays the text name of the behavior (i.e., the name you declared in the Catalog and is
displayed on the Canvas) that the entity is currently executing.
Stack: Displays the level of the frame currently being executed on the entitys stack. For example, if the
entity has just been created, the stack level will be 1, because the entity will be in the bottommost frame of
the stack; but the first time a behavior is invoked, the level will be 2, because the invoked behavior will
cause a second frame to be placed onto the stack and executed. (For more information, see the
Understanding SimBionic's flow of execution topic.)
H:M:S: Displays the number of hours, minutes, and seconds the entity has been executing.
Creating Programs
Watch: Allows you to designate particular entities for which you want to set breakpoints. You can then use
the Breakpoint List to indicate that a breakpoint should be enabled only for the those entities on your Watch
list.
To use this feature, click in the Watch cell of the entity for which you want to enable breakpoints; a
checkmark appears to indicate the entity is now added to your Watch list. If you later want to remove the
entity from the Watch list, click in the cell again to make the checkmark disappear.
Note: Selecting an entity in the Entities window will cause the Execution stack window, Variables window, and Canvas
to update to show the current status of the selected entity.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Level: Displays the level of the execution frame on the stack. The first behavior will be level 1, the next
invoked behavior will be level 2, and so on.
Behavior: Displays the name of the behavior being run via the execution frame.
Current Rectangle: Displays the name of the action or behavior rectangle currently being executed in the
behavior.
Invoking Frame: Displays the stack level of the behavior that invoked the current behavior. In almost all
cases, this number will be one less than the current framei.e., the invoking behavior will be directly under
the current behavior on the stack. The one exception is when the current frame is an interrupt behavior, in
which case the invoking frame may be at any level below the current one. To help you easily pick out these
exceptions to the rule, this window displays the text representing interrupt behaviors in cyan (as opposed to
standard black text). Note: The initial behavior will have a dash (-) instead of a number in this column,
because it wasnt invoked by any previous behavior.
Note: Selecting a row (i.e., execution frame) in the Execution stack window will cause the Variables window and
Canvas to update to show the current behavior in that frame as well as its local variables and parameters.
For more information, see the Understanding SimBionic's flow of execution topic.
Variables window
The Variables window in the interactive debugger allows you to track your programs use of global variables, local
variables, and behavior parameters. The window devotes a row to each variable or parameter, and provides data
about the variable or parameter via the following five columns:
Global/Local/Parameter: Displays the letter G is the item is a global variable, L if its a local variable, or P if
its a behavior parameter.
Variable Name: Displays the text name you declared for the variable or parameter.
Type: Displays the data type you declared for the variable or parameter. Specifically, displays the letter I for
integer, F for float, S for string, V for vector, B for Boolean, E for entity, A for array, T for table, D for data,
and INV for Invalid. (For more information, see the Choosing a data type topic.)
Value: Displays the value currently stored in the variable or parameter. If the value is longer than the column
width, displays the initial data followed by an ellipsis () to let you know that you can view more of the value
by widening the column (by clicking and dragging a column border).
Tip #1: You can change the variables or parameters value on the spot. To do so, click this cell; after a
moment, a text box appears that contains the value. Replace the current value with the value you want, and
then click anywhere outside the text box to save your change. Note that this is only possible for data types
integer, float, Boolean, string, and vector.
Tip #2: For an array or table variable, the cell displays a string representation. Double-click the cell to pop
up a dialog box that lets you view all of the arrays or tables values.
Breakpoint: Allows you to set a breakpoint that pauses your program whenever the value in the variable or
parameter changes.
To use this feature, click in the Breakpoint cell of the variable or parameter on which you want to set a
breakpoint. After you do so, a checkmark appears, and the variable or parameter is added to the Breakpoint
List window. If you later want to remove the breakpoint, click in the cell again; the checkmark disappears,
and the variable or parameter is removed from the Breakpoint List window.
103
Breakpoint List
The Breakpoint List window allows you to track and control your use of breakpoints in the interactive debugger. Unlike
the other debugger windows, this window is hidden by default; but you can toggle its display on at any time by clicking
the Breakpoint List button on the Debug toolbar. The window devotes a row to each breakpoint youve created, and
provides data about the breakpoint or parameter via the following five columns:
Enabled: Allows you to turn the breakpoint off. This is useful if you dont want to remove the breakpoint but
just temporarily disable it, allowing execution to flow past the breakpoint without pausing.
To use this feature, click in the Enabled cell of the breakpoint you want to turn off. After you do so, the
checkmark under the column disappears, and the bullet in the pertinent Canvas element is hollowed out.
If you later want to turn the breakpoint back on, click in the cell again; the checkmark reappears and the
bullet in the pertinent Canvas element is filled in again.
Breakpoint: Displays the name of both the behavior and the Canvas element or Catalog item to which the
breakpoint is attached.
Entity: Allows you to set whether the breakpoint applies to All entities (represented by A, which is the
default); or just the entities in the Entities window that youve set to be Watched (represented by W); or just
one particular entity (represented by that entitys ID number).
To use this feature, click in the Entity cell of the breakpoint you want to adjust. A text box appears that lets
you type an A, a W, or an entity ID number (e.g., 0, 1, 12). Type the letter for the setting you want, or type
the ID number of the entity youre targeting, and then click outside of the text box to save your setting.
#: Allows you to set how many times your program must flow to the breakpoint before the breakpoint
actually pauses execution. The default setting is 0, meaning the breakpoint will pause execution every time
your program encounters it.
For example, if you only wanted to pause execution every other time the breakpoint was reached, youd set
this value to 1; if you wanted to pause every third time the breakpoint was reached, youd set this value to 2;
and so on.
To use this feature, click in the # cell of the breakpoint you want to adjust. A text box appears that lets you
type a whole number (e.g., 1, 2, 12). Type the number of times you want the breakpoint to allow execution to
proceed before its triggered, and then click outside of the text box to save your setting.
Constraint: Allows you to enter an expression that evaluates as true or false (e.g., Count>5, or X==Y). The
breakpoint will only be active when the expression you specify evaluates as true. The default is to specify no
expression, which places no constraint on the breakpoint being active.
To use this feature, click in the Constraint cell of the breakpoint you want to adjust. A text box appears that
lets you type any expression that evaluates to true or false. Type the expression and then click outside of
the text box to save it.
You can enter only one expression per breakpoint. However, you can use the logical AND (&&) and logical
inclusive OR (||) operators to create complex expressions. (For more information, see the Using operators in
expressions topic.)
To set a breakpoint on a rectangle or condition on the Canvas, select the desired rectangle or condition
and then click the Breakpoint button (or hit F9). A red bullet appears in the selected Canvas element to
indicate a breakpoint has been set. Your program will now pause whenever execution flows to this Canvas
element.
To set a breakpoint on a global variable or behavior parameter, right-click on the desired variable or
parameter in the Catalog and select Breakpoint. A checkmark appears in the menu to indicate that the item
has a breakpoint on it. Your program will now pause whenever the value of the variable or parameter is
modified.
To set a breakpoint on a local variable, right-click on the desired variable in the Local Variables palette
and select Breakpoint. A checkmark appears in the menu to indicate that the variable has a breakpoint on it.
Your program will now pause whenever the value of the variable is modified.
If you later want to remove a breakpoint, simply repeat the steps you used to create it e.g., select the pertinent
Canvas element, and then click the Breakpoint button again or press F9 again.
You can view a summary of all of your current breakpoints from the Breakpoint List window. This window also allows
you to temporarily disable breakpoints as well as to impose additional constraints on them.
Breakpoints are saved automatically as part of your project. You can create an unlimited number of breakpoints.
Tip: You can create breakpoints while using the program editor via the same methods just described for creation using
the debugger. Breakpoints remain on the Canvas regardless of whether youre in the program editor or the debugger.
Exploring the Sample Programs
104
Creating Programs
2.
Press N to start a new game, and then use your arrow keys to move around the Pac-Man-like
character.
The goal is to eat all the dots on each screen, along with the occasional bouncing fruit, while evading the
ghosts Blinky, Pinky, Inky, and Clyde. You get extra points for consuming any of the ghosts, which are
temporarily vulnerable after Pac-Man eats one of the power pellets residing in the four corners of the screen.
(Tip: If your officemates begin staring, you can turn the sound off by pressing the "S" key.)
3.
Play around with the game, and refresh your memory regarding the details of its operation.
Have fun; but at the same time, try to identify the underlying behaviors that make the game operate the way
it does.
4.
5.
6.
7.
8.
If you had to create the underlying behaviors that drive this game, how would you do it?
Grab a sheet of paper, or open a Notepad window, and break down how youd program the AI for Pac-Man in a
SimBionic project. Include the entities youd define in the Descriptors pane, the actions and predicates youd declare in
the Catalog, and the behaviors youd create on the Canvas.
When youre done, read the next section to see to what extent your design corresponds with the one we actually used.
105
However, the dots and power pellets in the game are not entities, because theyre relatively static and entirely
predictable, exhibiting no behavior that requires AI.
Based on this analysis, we created the following entities for this project in the Descriptors pane:
The category title of Thing is arguably too generic (GhostsNFruit might have been a better choice). However, the
second-level descriptor names of Ghost and Fruit are on target; and so are the names of the entities within the Ghost
subcategory.
Note that we alternatively couldve grouped Blinky, Pinky, Inky, Clyde, and Fruit all together as second-level
descriptors. This would work fine as long as we stayed with a single descriptor category. If we ever wanted to increase
the complexity of the games AI by adding a second descriptor category, howeverfor example, a Strategy category
that would let us create such polymorphic behaviors as Blinky DirectPursuit, Pinky ThreeStepsAhead, Inky
RandomPursuit, and so onwed benefit from having the generic ghost behavior for pursuing and fleeing Pac-Man
(i.e., the default behavior assigned to the Ghost descriptor) be distinctly different from the generic fruit behavior for
evading Pac-Man (i.e., the default behavior assigned to the Fruit descriptor).
For more information on descriptors, polymorphisms, and default behaviors, see the Understanding descriptors topic.
The first thing you should notice is that this behaviors initial rectangle is a None actioni.e., it has no expression and
performs no action. However, the rectangle has a binding that stores the name of the current entity in the global
variable Thing (a variable SimBionic created automatically when we declared Thing as a descriptor category). This
allows us to identify which entity is being controlled.
106
Creating Programs
Coming out of the rectangle is a condition based on the custom predicate IsPlaying, which checks on whether the PacMan game is currently being playedi.e., whether the player has pressed N for New Game. If this condition is false,
then the flow of execution remains in the initial None action until the next clock tickat which point the IsPlaying
condition is evaluated again. In other words, the behavior initially does nothing but wait until the player has pressed
the necessary key to begin the game.
When IsPlaying becomes truei.e., the game startsexecution first flows to another None action, which is also
designed to await an event. In this case, the action has two conditions coming out of it. The first, IsActive, is based on
a custom predicate that detects whether the current entity is doing anything yet that requires AI control. For example,
when the game begins, three of the ghosts simply move back and forth in their pen. This is an unchanging bit of
animation that requires no AI; so if the current entity is, say, Clyde, then IsActive would initially evaluate as false.
The second condition, IsGameOver, is based on a custom predicate that detects whether the game has ended. If it
evaluates as true, then execution flows back to the initial action, which then waits for a new game to begin. However, if
it evaluates as false, then execution remains in the second None action until the next clock tickat which point the
IsActive condition is evaluated again. In other words, the behavior continues to do nothing but wait until the current
entity is required to perform some action that requires AI.
Once an entity becomes active, the Main behavior invokes PickDirection, which (as youll see shortly) is a behavior
that determines whether the entity should move up, down, right, or left. During each clock tick, SimBionic executes a
rectangle within PickDirection, and then evaluates the two conditions coming out of the behavior.
The first is the core predicate IsDone, which checks on whether PickDirection has completed executing (for more
information, see the Checking for completed behaviors topic). If PickDirection hasnt finished, then execution flows
back to it during the next clock tick so the behavior can pick up where it left off and execute its next rectangle.
When PickDirection has completed (i.e., reached a final action), IsDone evaluates as true, and execution then flows to
the next condition, which is !IsActivethat is, the negation of IsActive, meaning its only true when the entity has
ceased to be active. If the entity remains active, then execution returns to PickDirection, which is invoked again to
select another direction for the entity. In other words, PickDirection will continue mapping out a path for the entity, one
step at a time, until the entity ceases to be active (e.g., because Pac-Man ate it).
When !IsActive becomes true, executes flows to the second None action againwhich, as before, allows the entity to
wait until either its active again or the game is over. If the entity becomes active again, it repeats the cycle just
described; while if the game ends, execution flows to the first None action, where SimBionic again waits until the entity
reactivates.
In other words, this Main behavior creates an infinite loop. Thats generally a fatal design for any invoked behavior; but
putting your first-level behavior in an infinite loop is actually an effective way to keep driving all of your projects other
behaviors. When youre ready to end the Main behavior, you can do so via C++ or Java code from your simulation or
gamee.g., the SetBehavior method, which switches an entity to a different behavior; the SetUpdateFreq method,
which can freeze an entitys activities; the DestroyEntity method, which deletes the entity entirely; or the Terminate
method, which shuts down the engine. (For more information, see the Using the C++ engine's API methods or Using
the Java engine's API methods topic.)
107
PickDirection gets Pac-Mans current location and direction (which is data it obtains directly from the game) and then
tries to anticipate at which maze intersection Pac-Man will show up next. It does this via three custom actions:
FindDestination, RankDirections, and TryDirection.
FindDestination takes in Pac-Mans current position via the parameters Location (vector: in) and Direction (string: in);
and then computes the intersection where Pac-Man is most likely to emerge and returns that value via parameter
Destination (vector: out). A vector is an [x, y, z] value that typically identifies an entitys location via coordinates. Since
our version of Pac-Man is two-dimensional, not a 3-D simulation, the third coordinate in this case is simply ignored. If
FindDestination does a good job, the value it returns identifies the best spot for a ghost to cut Pac-Man off.
RankDirections then looks at where an entity is currently located and where it ideally should end up, and determines
the best direction, the next best direction, the third best direction, and the least effective direction, assigning rankings
to the four possibilities of Left, Right, Up, and Down. To perform this calculation, RankDirections effectively draws a
rectangle in which one corner is where the entity is and another corner is where Pac-Man is. RankDirections then
assigns a ranking of 1 to traveling along the longer side of the rectangle; a ranking of 2 to travel along the shorter side;
a ranking of three to travel in the opposite direction of the short side (which may be necessary if the entitys path is
blocked); and a ranking of 4 is to travel in the opposite direction of the long side. This algorithm couldve been
implemented as a SimBionic behavior; but since its relatively straightforward and unlikely to change, it was instead
programmed via C++ code and declared as an action.
TryDirection then tests each direction in order of rank to see if its feasible. If it isnt, then TryDirection tests the nextbest direction, until a direction that can actually followed is found.
There are two conditions coming out of RankDirections. The first one is Random()<0.5, which returns a random
floating point number between 0 and 1. If the number is less than .5 (for which the odds are 50/50), the condition
evaluates as true, and execution flows to a None action that uses bindings to swap the values of the two top-ranked
directions. Adding this random element to movement helps create an appearance of independent behavior among the
individual ghosts. It also creates a better chance of surrounding Pac-Man and so cutting off his retreat options.
Regardless of the results of the Random condition, execution eventually flows to the second condition, IsFleeing,
which determines whether Pac-Man has swallowed a power pill. If he has, then the ghosts must run away from him for
a period of time rather than pursue him. In this case, execution flows to an action that uses bindings to swap the
values of all four ranked directions, which effectively reverse a ghosts attack behavior into fleeing behavior. (As for the
fruit, the IsFleeing condition is always set to true, because the fruit must always seek to avoid getting eaten.)
108
Creating Programs
After the Random and IsFleeing conditions are evaluated, execution flows to the TryDirection behavior, which (as
mentioned previously) checks each direction in order of rank to see whether the proposed destination is feasible. The
behavior looks like this:
The behavior first sets a return parameter named Result to a value of 0 (i.e., a Boolean value of false).
Execution then flows to an IsBlocked condition that checks for a blocked path; for example, if the proposed direction is
up, TryDirection checks whether theres a wall that would prevent the entity from actually moving up. If IsBlocked
evaluates as true, execution flows to the final action (i.e., the red None action), and TryDirection terminates by
returning a value of false to PickDirection.
Otherwise, the second condition IsReverse is evaluated. This condition checks whether the proposed direction is the
opposite of the entitys current direction. If it is, then the direction must again be rejected, because entities arent
allowed to do an abrupt about-face in Pac-Man. In this case, execution again flows to the final action, and TryDirection
returns a value of false to PickDirection.
If both the IsBlocked and IsReverse conditions evaluate as false, however, execution flows to an action that sets the
just-tested direction to be the next direction the entity follows; and also sets the return parameter Result to 1 (i.e., a
Boolean value of true). Execution then flows to the final action so PickDirection can pick up where it left off
specifically, this final section of the PickDirection behavior:
109
Again, each direction is tested in order of rank. After TryDirection returns the value of Result, execution flows to a
condition that simply contains a variable storing that value. If the Result condition evaluates as false, that means the
current direction failed TryDirections testing, and so execution flows down to the next TryDirection rectangle. But if the
Result condition evaluates as true, then execution flows to the final action, the PickDirection behavior terminates, and
the Main behavior picks up where it left off.
As youve just seen, Main, PickDirection, and TryDirection are all relatively simple behaviors; but theyre enough to
drive the logic of an extremely compelling game like Pac-Man. If you employ SimBionics power to create more
complex behaviors, theres no telling how gripping and realistic your virtual worlds can be.
This topic covered how to create behaviors on the Canvas. However, you also need to understand how to create the
underlying C++ or Java code that powers actions and predicates, and drives the run-time engine. To view sample
code that demonstrates this, see the next topic, Exploring the "Hello World" program.
Exploring the sample "Hello World" program
In the previous topic, Exploring the sample Pac-Man program, we concentrated on programming behaviors on the
Canvas. In this example, well look at how to create C++ code that hooks a SimBionic project into your simulation or
game.
This second sample program is called Hello World, and it can be found in a HelloWorld folder in your SimBionic
package. This is a very simple program that consists of the following single behavior:
110
Creating Programs
The behavior begins with a custom action named Say that accepts a string parameter and then displays that string on
the users screen. The initial string passed to the action is "Hello World". (This isnt clear from the rectangle display,
which shows only the first few letters of the string; but you can view the entire string by either double-clicking the
rectangle, or selecting the rectangle and then looking at the Expression toolbar.)
Execution then flows to a condition based on a custom predicate named HappinessLevel, which ideally would perform
a useful computation and then return a value. In this example, though, the predicate actually does nothing but return
the value 87.
After HappinessLevel returns its value, the condition checks on whether the number is higher than 50. If it is, the
condition evaluates as true, and execution flows to a second Say action that displays the text "Happy Day!" Otherwise,
execution flows to the second connector coming out of the initial action, which leads to a Say action that displays the
text ""Gloom and Doom..."
Both of the second Say actions then lead to a final action, which terminates the behavior.
Again, this is a very simple example of a SimBionic project, so how to create it on the Canvas is relatively obvious.
What might be less evident is how to write the underlying C++ code to support the behaviors custom action Say and
custom predicate HappinessLevel; include the files necessary to make this project work in conjunction with your
simulation or game; and start up the SimBionic engine so it can run the SIM file containing the compiled version of the
project.
The HelloWorld folder included in your SimBionic package contains all the files needed to accomplish this. The most
instructive file is named HelloWorld.cpp (the .CPP extension being short for C++). The following shows you all of
HelloWorld.cpps contents, and demonstrates virtually everything you need to know about making a SimBionic project
work with your simulation or game:
***************
/*
* This is a sample project designed to show you how to build a very
* simple "Hello World" program using SimBionic.
*/
#include "Interface\AI_Engine.h"
111
#include "Interface\AI_Interface.h"
#include "HelloWorld.h"
/**
* This class defines a simple interface between SimBionic and
* our HelloWorld application.
*/
class HelloWorldInterface : public AI_Interface
{
void DoAction(AI_ProcId actionId, AI_Entity entityId, AI_ParamVec& params)
{
switch (actionId)
{
case HELLOWORLD_ACTION_Say:
{
// extract the first parameter, which is of type "string"
AI_String message = params[0].String();
// now print the string to the console
printf("%s\n", message);
}
break;
default: printf("Unknown action!\n"); break;
}
}
AI_Param DoPredicate(AI_ProcId predId, AI_Entity entityId, AI_ParamVec& params)
{
AI_Param returnValue;
switch (predId)
{
case HELLOWORLD_PRED_HappinessLevel:
{
// since we have no real simulation, just make up
// an arbitrary happiness level
// set the return value for the predicate
returnValue.SetInteger(87);
}
break;
default: printf("Unknown predicate!\n"); break;
}
return returnValue;
}
};
112
Creating Programs
113
}
// shut down and unload SimBionic
engine.Terminate();
return 0;
}
***************
For more information about the details of this sample code, see the topics Understanding the C++ run-time engine,
Coding actions in C++, Coding predicates in C++, and Using the C++ engine's API methods topics.
114
Launch the SimBionic editor and open the project for which you want to export XML.
2.
Click the File menu and select the Export XML option.
An Export XML dialog box appears.
3.
4.
Click Save.
The XML file is saved in the folder and under the name you specified.
Launch the SimBionic editor and open the project for which you want to export documentation.
2.
Click the File menu and select the Export HTML Doc option.
An Export HTML Doc dialog box appears.
3.
Specify the folder and filename for the documentations index file.
For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.
4.
Click Save.
The HTML files are saved in the folder you specified. You can view them by opening the index file in your
web browser.
Note that there are a few restrictions on sharing projects across multiple users. The declarations for all descriptors,
constants, and global variables are stored in the project (.SBP) file. This means that only one developer can edit these
declarations at a time. Also, project files that have been externally modified cannot be automatically reloaded in the
editor; you need to exit SimBionic and load the project again.
Command-line options
When youre working in the SimBionic editor, youll typically compile your project using the Compile button (or by
pressing F7). SimBionic also provides a command-line build mode, however, which enables you to easily integrate it
into any automated build processes that you may use for your application. To use this mode, simply invoke the
SimBionic editor from the command line as follows:
simbionic.exe project-filename [options]
The following command-line options are available. Square brackets around a parameter indicate that it can be left out.
-c [log-file-path]
115
Compiles the project. If log-file-path is present, compile messages will be written to the specified file. For
more information, see the topic Compiling your project.
-d index-file-path
Generates HTML documentation for the project, in the folder specified by index-file-path. For more
information, see the topic Creating HTML documentation.
-e [constants-file-path]
Causes the -gc or -gj options to export constant definitions to a separate file. If constants-file-path is present,
the constant definitions will be written to that file. Otherwise, they will be written to the default file
code_constants.h or code_constants.java.
-gc [code-file-path]
Generates C++ code for the project. If code-file-path is present, skeleton code will be created in the
specified file, as described in the topic Generating skeleton code for C++.
-gj [code-file-path]
Generates Java code for the project. If code-file-path is present, skeleton code will be created in the
specified file, as described in the topic Generating skeleton code for Java.
-o sim-file-path
Sets the filename and path for the compiled project file created using the -c option. Any package files will be
created in the same folder. If this option is not specified, -c will use the filename specified in the projects
saved settings.
-u
Causes the -gc or -gj options to export definitions for user-defined constants. If this option is not present,
they will not be exported.
-x xml-file-path
Generates an XML representation of the project, in the folder specified by xml-file-path. For more
information, see the topic Exporting XML.
Example #1: If your project is named "MyProject.sbp", you can compile it like this:
simbionic.exe MyProject.sbp c
Example #2: There are several ways you can generate C++ interface code for your project:
simbionic MyProject.sbp -gc code.h eu
simbionic MyProject.sbp -gc code.h -e constants.h
simbionic MyProject.sbp -gc -eu constants.h
The first line will generate C++ skeleton code in the specified files code.h and .cpp, placing the constant definitions
(including user-defined constants) in a separate file called code_constants.h (the default name).
The second line will generate C++ skeleton code in the specified files code.h and .cpp, placing the constant definitions
in a separate file called constants.h that does not include the user-defined constants.
The third line will generate only a C++ constant definitions file called constants.h that includes the user-defined
constants.
Creating and editing sub-behaviors
In SimBionic, you can control the pace of a behavior's execution i.e., how many clock ticks that behavior will need to
run from its initial rectangle to a final action by setting its execution mode. While this suffices for most situations,
sometimes you may want to exercise more fine-grained control, varying the pace of execution within a single behavior.
You can do this using the sub-behavior construct, which allows you to group together two or more rectangles (and the
connectors and conditions that link them) into a single "block" that can have its own execution mode.
Creating a sub-behavior
To create a sub-behavior, follow these steps:
116
1.
Select all of the Canvas elements that you want to be part of the sub-behavior.
You can select the elements by holding down the Shift key and clicking on each element. Alternatively, you
can click on an empty part of the Canvas and then drag while holding down the mouse button until all of the
desired elements are enclosed by the dashed selection box.
Note: You must select at least two rectangles. Each element you select should also be directly connected to
at least one other element in the sub-behavior (ensuring that execution can flow without a break through the
sub-behavior).
2.
Right click on any of the selected elements and select Create sub-behavior.
A thin black rectangle will appear around the elements to indicate that they have been placed in a subbehavior, as shown in this example:
Editing a sub-behavior
Once youve created a sub-behavior, the elements within it are locked, meaning that you can no longer rearrange
them on the Canvas (though you can still edit any other aspect of the elements, including their expressions, bindings,
comments, and reminders). You can, however, move the sub-behavior itself around on the Canvas. To do so, first
select the sub-behavior by clicking on an empty area within the sub-behavior rectangle. The sub-behavior will be
highlighted with a thick blue border. You can then drag the sub-behavior to the desired location on the Canvas, and all
of its constituent elements will be dragged with it. You can also perform any of the standard edit operations (i.e., cut,
copy, paste, or delete) on the sub-behavior while it is selected.
Destroying a sub-behavior
To remove a sub-behavior from your behavior, right-click on an empty area within the sub-behavior rectangle and
select Destroy sub-behavior. The sub-behavior rectangle will disappear from the Canvas. Note that destroying a subbehavior does not destroy its constituent elements.
Changing the execution mode of a sub-behavior
By default, a sub-behavior has the same execution mode as the behavior it is a part of. You can change this by rightclicking on an empty area within the sub-behavior rectangle and then selecting the desired mode from the Set
Execution Mode menu that appears. A checkmark will appear by the mode that is currently selected for the subbehavior.
The execution mode for a sub-behavior is active for as long as the current rectangle remains within the sub-behavior.
As soon as execution flows out of the sub-behavior, the behavior will return to the execution mode specified in its
declaration.
Note: Certain execution modes take precedence over others (as described in the Setting a behavior's execution mode
topic). For example, one-tick mode is higher-precedence than multi-tick. Thus, if a behaviors execution mode is onetick and it has a sub-behavior whose execution mode is multi-tick, the sub-behaviors execution mode will be
overridden and it will execute in one-tick mode.
Sub-behaviors versus invoked behaviors
You might have observed that you can mimic the effect of a sub-behavior by using an ordinary behavior. For example,
imagine that you have created a multi-tick Attack behavior, and now you decide that you want several rectangles in
that behavior but not all of them to execute in a single tick. You could create a sub-behavior containing those
rectangles and set its execution mode to one-tick. Alternatively, you could create an entirely new one-tick behavior,
move those rectangles into it, and then invoke the new behavior from the original behavior. Which option is better
depends on your preferences and the demands of your project.
Sub-behaviors have the advantage of keeping all of the logic of the behavior on a single Canvas, where you can see
the flow of execution at a glance. Of course, they also have the potential to complicate the flow of execution with
117
constant changes in the execution mode. Invoked behaviors, on the other hand, are more opaque, but they can also
be invoked by more than one behavior, and thus encourage the creation of modular, reusable behaviors.
Extracting a behavior
If you decide that an existing sub-behavior would make more sense as a full-fledged behavior, SimBionic can
automatically perform the necessary steps to set it up for you. Simply right-click on the sub-behavior and select Extract
Behavior. SimBionic will create a new behavior in the Catalog with the same name as the parent behavior plus a
distinguishing suffix. (For example, if the parent behavior was Attack, the extracted behavior would be named
Attack1.) The new behavior will have all of the same Canvas elements as the original sub-behavior. It will also have a
parameter for each local variable or parameter of the parent behavior that is referenced by the sub-behavior. You will
probably need to edit the new behavior slightly to choose an appropriate initial rectangle and possibly create one or
more final actions.
Note: Extracting a behavior does not remove the original sub-behavior from the parent behavior. If you wish to replace
the sub-behavior with your new behavior, you can do so by destroying the sub-behavior, deleting the constituent
elements, and then dragging the new behavior onto the Canvas and adding the necessary connectors.
Controlling the entity scheduler
Each time your application calls SimBionics Update API method, the run-time engine consults its built-in scheduler to
determine which entities should be updated on the current clock tick. Because updating an entity uses a bit of valuable
CPU time, SimBionics scheduler attempts to evenly distribute these updates across multiple clock ticks. This loadbalancing process ensures that the run-time engine maintains a steady level of CPU usage, without peaks or valleys
that might adversely affect the performance of your application.
You can control how a particular entity is scheduled via two parameters: its update frequency and its update priority.
You can set these parameters when the entity is initially created, or you can change them later using the
SetUpdateFreq and SetUpdatePriority API methods or core actions.
Update frequency: This is the minimum frequency with which you want the entity updated, specified via an
integer from -1 to 100. A setting of 0 tells the engine to update the entity precisely once every clock tick, and
is the default. Higher number settings tell the engine that it can update the entity less frequently; e.g., a
setting of 1 means to update at least every other clock tick, a setting of 2 means to update at least every
third clock tick, a setting of 3 means to update at least every fourth clock tick, and so on. If it has the
resources available, the engine will update an entity more frequently than the setting youve specified; but it
will never update less frequently. Alternatively, if you want to temporarily prevent an entity from executing, a
setting of -1 bars the entity from performing additional behaviors during any clock tick, effectively freezing it
until you change its update frequency back to a positive number.
Update priority: This is the execution priority you want to assign the entity within any given clock tick,
specified via an integer from 0 on up through the highest integer allowed by your compiler. For example, a
setting of 0 (which is the default) tells the engine to execute the entitys behavior before entities scheduled to
execute during the same clock tick that have settings of 1 or higher; a setting of 1 means to execute the
entity before entities scheduled to execute during the same clock tick that have settings of 2 or higher; and
so on.
Note: You can change the maximum value allowed for an entitys update frequency allowed by setting the value of the
maxUpdatePeriod variable in the configuration object you pass to the run-time engine on startup (i.e., AI_Config for
C++ and SB_Config for Java). The default value is 100.
Enabling Entities to Communicate
Communicating via virtual blackboards
SimBionic includes two basic ways for your entities to communicate with each other. One is via group messaging, in
which messages are sent directly to each entity belonging to a specified group. For more information on this approach,
see the Communicating via group messages topic.
The other communication method built into SimBionic uses virtual blackboards, which are storage areas available to
all entities for sharing information. A blackboard is divided into sections; and each section holds a piece of information
118
of any data type. Your entities can create an unlimited number of blackboards; and can also create an unlimited
number of sections on any board.
Any entity can create a blackboard by simply providing the board with a unique name (e.g., "Target_Locations"). Any
entity that "knows" the boards name can then place information on it by specifying the name, the name of the section
of the board that will store the information (if the section doesnt already exist, its created automatically), and the
actual information (e.g., "Target_Locations", "Enemy_Headquarters", Info). Similarly, any entity that "knows" the
boards name and the sections name can specify those names to read the information they store (e.g.,
"Target_Locations", "Enemy_Headquarters"). The blackboards therefore makes it easy for any entity to share
information with any or all other entities in your program.
Once information is placed on a section of a board, it remains stored there unless an entity overwrites it by posting
new information to that same section. The only other way to eliminate the information is for an entity to destroy the
entire board thats storing it (which is also useful for eliminating obsolete boards and freeing up memory). An entity can
also effectively "erase" a board by destroying it and then immediately creating a new, blank board with the same
name.
Blackboards are accessed via SimBionics built-in actions and predicates, which are automatically included as part of
every project. Their declarations are stored in the Catalog in the Blackboards subfolders within the Core AP module;
and their corresponding code is built into SimBionics engine, which identifies each of them via a unique action or
predicate ID number.
The names, descriptions, parameter formats, and ID numbers of the six built-in actions and predicates that deal with
virtual blackboards are as follows:
CreateBBoard: Action that lets any entity create a virtual blackboard specified by a particular name. Format:
name: string [in] (e.g., CreateBBoard("Target_Locations")).
DestroyBBoard: Action that eliminates a named blackboard, freeing up the memory taken up by the board
and all the information stored on it. Alternatively, an entity can "erase" the information on a blackboard by
destroying the board with this action and then immediately creating a new blank board with the same name
via CreateBBoard. Format: name: string [in] (e.g., DestroyBBoard("Target_Locations")).
IsBBoard: Predicate that lets an entity verify a named blackboard existsi.e., was created previously via
the CreateBBoard action and hasnt been permanently eradicated via the DestroyBBoard action. If the board
with the name specified exists, IsBBoard returns a value of true; while if the board doesnt existeither
because it was never created or has subsequently been destroyedIsBBoard returns a value of false.
Format: name: string [in] (e.g., IsBBoard("Target_Locations")). Returns value of data type Boolean.
PostBBoard: Action that lets an entity place information in a named section of a named blackboard. The
information can then be read by any entity that "knows" the names of the blackboard and section. The
information remains available until its either replaced (via another PostBBoard action) or the board is
destroyed (via the DestroyBBoard action). Format consists of the boards name, followed by a key-value pair
identifying board sections name and the data to be stored (which can be any data type): name: string [in],
key: string [in], value: any [in] (e.g., PostBBoard("Target_Locations", "Enemy_Headquarters", Info)).
ReadBBoard: Predicate that lets an entity access any blackboard (created previously via the CreateBBoard
action) and read any information on the board (placed previously via the PostBBoard action) by specifying
the boards name and the section of the board storing the information. ReadBBoard therefore allows any
entity to obtain information from any other entity in your program. Format consists of the name of the board
followed by the name of the section storing the data: name: string [in], key: string [in] (e.g.,
ReadBBoard("Target_Locations", "Enemy_Headquarters")). Returns value of data type any (because the
information can be any data type).
IsValid: Predicate that checks on whether a value of type any is what was expected; or is instead invalid,
indicating that something went wrong. You can use IsValid to check on a predicate that has the potential of
returning an invalid value. For example, the ReadBBoard predicate normally returns data stored in a named
section of a named blackboard; but if either the blackboard or its named section doesnt exist, ReadBBoard
will instead return a value of invalid. If you then use IsValid, it will return a Boolean value of false to indicate
the ReadBBoard value was not valid. Format: var: any [in] (e.g., IsValid(x)). Returns value of data type
Boolean. (Note: Because IsValid has uses beyond working with virtual blackboards, its declaration is stored
in the root of the Core AP module.) For more information, see the Checking for invalid values topic.
Note: Because these actions and predicates are hard-coded in SimBionics engine and designed to be included in
every project, you cant edit or delete their declarations in the Catalog. This is indicated by a small lock symbol in the
upper-left of each core actions and core predicates icon in the Catalog.
Virtual blackboards are ideal for handling a variety of communication needs. These include:
Storing information that can be accessed by any number of entities at any time.
Having the option of instantly and completely destroying all of a boards stored information.
119
On the other hand, if your programs communication needs are more suited to sending messages directly to members
of a particular group (similar to sending email), you can alternatively use SimBionics built-in group messaging. For
more information on this option, see the Communicating via group messages topic.
Communicating via group messages
SimBionic includes two basic ways for your entities to communicate with each other. One is via virtual blackboards,
which are storage areas available to all entities for sharing information. To learn more, see the Communicating via
virtual blackboards topic.
The other communication method built into SimBionic focuses on group messaging, which allows an entity to join a
named group of entities and receive every message directed at that group. It also allows any entity to send a message
to a named group, regardless of whether the entity belongs to the group. Group messaging therefore allows any entity
to communicate directly with a select group of other entities.
Every group message is sent to an entitys message queue, which is a personal storage area SimBionic automatically
creates for each entity, and which holds onto each message until the entity is ready to access it, optionally read it, and
discard it. Messages are accessed in first in, first out ordere.g., if an entity receives three messages, it must access
and discard the first one before it can access the second one, and must access and discard the second one before it
can access the third one.
Each message contains three components an entity can read:
The name of the entity who sent the message, which is of data type entity. This information can be used
to provide context to a messageor determine whether the message needs to be read at all. (E.g., a soldier
entity might be instructed to read messages only from its commander, in which case it would check the
sender of each message and simply discard any message not from its commander.)
A number code associated with the message, which is of data type integer. SimBionic doesnt ascribe
any meaning to this code, so what number is attached to a particular message and what that number
represents is entirely up to you. For example, you might assign each message a priority number from 1 to 5,
with 1 meaning Urgent; read immediately! and 5 meaning Light news; read at your leisure. Or you might
assign each entity a unique number and then use the numbers to flag messages directed exclusively at a
particular entity. Or you might use number codes to indicate different ways a particular message should be
interpreted (e.g., 1 might mean Read as text string, 2 might mean Read as map coordinates, 3 might mean,
Read as direction and velocity changes, etc.). No matter what coding system you create, it should provide
useful information.
The actual message, which is of whatever data type you select. For example, you can choose to make all
messages text strings; or you can opt to send messages consisting of a variety of data types and identify
each type by a number code (as described in the previous paragraph).
For an entity to directly receive messages, it must join at least one named group. If the entity tries to join a group that
doesnt exist, SimBionic will automatically create the group using the name the entity specified and then make the
entity the first member of that group. Any entity that subsequently joins will simply be added as another member of the
group. As a result, a groups membership can be as small as one.
An entity doesnt have to be a member of a group to send a message to that group; it simply needs to "know" the
name of the group. The advantage of belonging to a group is that an entity receives all the messages sent to that
group. But if, say, a leader entity needs to send frequent messages to subordinate entities, it might opt to not join the
subordinates group so that its message queue doesnt become cluttered with its own messages. Further, the leader
might create another group consisting solely of itself, so that subordinates can send messages to the leader that only
the leader can read.
Theres no limit to the number of groups that can be created; the number of groups a particular entity can join; the
number of entities that can belong to a particular group; or the number of messages that can be sent to a particular
group.
It isnt possible to block a member of a group from receiving a particular message sent to that group. However, an
entity can always create a new group with a slightly different membership for the sake of sending messages that arent
intended for certain members of a previous group.
If an entity no longer desires to receive messages from a group, it can resign from membership. Similarly, if an entire
group becomes obsolete, it can be destroyed (which has the same effect as each member of the group resigning from
membership as the same time). In either case, each entitys message queue will continue to store whatever messages
were previously received from the group until the entity accesses and explicitly disposes of those messages.
Group messaging is handled via SimBionics built-in actions and predicates, which are automatically included as part
of every project. Their declarations are stored in the Catalog in the Messages subfolders in the Core AP module; and
their corresponding code is built into SimBionics engine, which identifies each of them via a unique action or predicate
ID number.
The names, descriptions, parameter formats, and ID numbers of the 10 built-in actions and predicates that deal with
group messaging are as follows:
120
JoinGroup: Action that lets an entity join a named group of entities. If the group doesnt already exist,
JoinGroup creates it using the specified name and then makes the entity the groups first member. After
joining, the entity receives any message sent to the group, along with every other member of the group.
Format: name: string [in] (e.g., JoinGroup("Superheroes")).
QuitGroup: Action that lets an entity belonging to a named group of entities resign its membership so that it
stops receiving messages sent to that group. Format: name: string [in] (e.g., QuitGroup("Superheroes")).
DestroyGroup: Action that dissolves a named group, which has the same effect as each member of the
group quitting it at the same time. As a result, no entity receives any subsequent messages directed at the
group. However, each entitys message queue continues to store whatever messages were previously
received from the group until the entity accesses and explicitly disposes of those messages. Format: name:
string [in] (e.g., DestroyGroup("Superheroes")).
NumMembers: Predicate that lets an entity find out how many entities belong to a named group.
NumMembers returns a value of zero if the group with the specified name either was never created, or has
been dissolved via the QuitGroup and/or DestroyGroup actions. Format: name: string [in] (e.g.,
NumMembers("Superheroes")). Returns value of data type integer.
SendMsg: Action that lets an entity send a message and number code to a named group of entities. Format
consists of the name of the group, which is of data type entity; the number code, which is of data type
integer; and the actual message, which can be any data type: group: entity [in], number code: integer [in],
msg: any data type [in] (e.g., SendMsg("Superheroes", 1, "Stop approaching meteor from striking Earth!!")).
NextMsg: Action that lets an entity discard the top message of its message queue so it can access the next
message in the queue. Format: no parameters (e.g., NextMsg()).
IsMsg: Predicate that lets an entity check whether it currently has any messages stored in its message
queue. If the queue contains at least one message, IsMsg returns a value of true; while if the queue is
empty, IsMsg returns a value of false. IsMsg should be used each time an entity has discarded the top
message in its queue (via the NextMsg action) to determine if there are any additional messages waiting to
be accessed. Also, after the entity has dealt with and discarded all its messages, it should use IsMsg
periodically to find out if any new messages have been received in its queue. Format: no parameters (e.g.,
IsMsg()). Returns value of data type Boolean.
GetMsgSender: Predicate that lets an entity read who sent the message at the top of its message queue,
which helps to place the message in context (and might even determine whether the entity bothers to read
the message at all). The message is unaffected by having the identity of its sender read, and will remain
stored in the queue until the entity discards it (via the NextMsg action) to access the next message in the
queue. Format: no parameters (e.g., GetMsgSender()). Returns value of data type entity.
GetMsgType: Predicate that lets an entity read a number code thats attached to the current message in its
message queue. (What meaning is ascribed to the number is up to you.) The message is unaffected by
having its code number read, and will remain stored in the queue until the entity discards it (via the NextMsg
action) to access the next message in the queue. Format: no parameters (e.g., GetMsgType()). Returns
value of data type integer.
GetMsgData: Predicate that lets an entity read the message thats at the top of its message queue. The
message is unaffected by being read, and will remain stored in the queue until the entity discards it (via the
NextMsg action) to access the next message in the queue. Format: no parameters (e.g., GetMsgData()).
Returns value of data type any (because a message can be any data type).
Note: Because these actions and predicates are hard-coded in SimBionics engine and designed to be included in
every project, you cant edit or delete their declarations in the Catalog. This is indicated by a small lock symbol in the
upper-left of each core actions and core predicates icon in the Catalog.
Group messaging is ideal for handling a variety of communication needs. These include:
Communicating directly with a particular entity. This can be done by either having the entity create a group
in which its the sole member; or instructing the entity to pay attention to messages that are from a particular
sender and/or that have a particular number code attached to them.
Providing context for each message by identifying its sender and attaching a number code.
Allowing each entity to read messages at its own pace (even after a group is destroyed).
On the other hand, if your programs communication needs are more suited to placing information in a public storage
area that any entity can access, you can alternatively use SimBionics built-in virtual blackboards. For more information
on this option, see the Communicating via virtual blackboards topic.
Dynamically Loading Behaviors
Dynamically loading and unloading behaviors
121
When you start the SimBionic run-time engine, you must specify a compiled project file containing the declarations that
make up your SimBionic project (as described in the Starting and controlling the C++ run-time engine and Starting and
controlling the Java run-time engine topics). By default, this project file includes all of the behaviors in your project (as
well as all of their polymorphisms), which means that the run-time engine will load all of your behaviors into memory
when it starts up.
If you have limited memory available for your application, however, or you have a large number of behaviors in your
project, you may not want the run-time engine to keep all of your behaviors in memory at once. You might instead
want to load only the behaviors that you need at the moment, and then unload those behaviors when youre done with
them and load a new set of behaviors. You can do this in SimBionic by organizing your behaviors into packages,
which are simply collections of behaviors that can be loaded and unloaded as a group by the run-time engine. (To
learn more about creating and editing packages, see the Working with behavior packages topic.)
The compiled project file (with the .SIM extension), which contains all of the action, predicate, descriptor,
and global variable declarations for your project
One package file (with the .BIM extension) for each package you have specified in your project. A package
file contains the compiled version of every behavior you placed in that package.
Note that each behavior must appear in exactly one compiled file, so if you put a behavior in a package, it will not
appear in the compiled project file. This also means that every behavior that is not assigned to a package will
automatically be saved to the compiled project file.
122
This dialog box contains options that control how your project is compiled. In particular, it allows you to
specify how your behaviors are packaged.
2.
Select the All behaviors in individual bim files option under Behavior packaging mode.
When this option is selected, SimBionic will generate a package (.BIM) file for each behavior in your project.
Each package file will contain only a single behavior (and any polymorphisms it may have).
2.
Select the User-specified behavior packaging option under Behavior packaging mode.
This option permits you to group your behaviors into a set of packages that you specify.
3.
123
This dialog box contains one row for each behavior in your project. The left-hand column lists the name of
the behavior, and the right-hand column contains a drop-down box allowing you to choose the package for
that behavior.
It also has two buttons in the lower left corner that allow you to change the package assignments for all of
your behaviors at once.
Finally, the dialog box has a Package List button that pops up a dialog box allowing you to create and delete
packages.
124
4.
If you want to reset the package assignment for all behaviors at once, click the All to sim file or All to
individual files button.
These buttons are equivalent to the All behaviors in sim file and All behaviors in individual bim files options
in the Behavior packaging mode drop-down box in the Project Settings.
5.
If you want to assign behaviors to a package that does not already exist, click the Package List
button.
The Package List dialog box appears:
This dialog lists all of the custom packages you have created for your project. You can create a new
package by clicking in a blank row and typing the name of the package. (Alternatively, you can click the
white page icon and then type the package name.)
You can rename an existing package by selecting it, waiting a moment, and then clicking again on it. A
cursor will appear in the row, allowing you to edit the name. When youre satisfied with the new name, hit
Enter to save it. The name change will be reflected in the Behavior Packaging dialog box.
Finally, you can delete a package by selecting it and then clicking the red X icon. If you delete a package to
which one or more behaviors are currently assigned, the package assignment for those behaviors will
change to sim file.
6.
If you want to change the package assignment for a single behavior, click in the Compile To column
for that behavior.
This will display a drop-down box listing all of the packages to which you can assign the behavior. Two builtin packages are always available in this box: sim file, which places the behavior in the compiled project file;
and bim file, which puts the behavior in its own individual package with the same name as the behavior. The
drop-down box also contains any other packages that you have created using the Package List button.
Tip #1: If you want complete control over the loading and unloading of each individual behavior in the run-time engine,
you should use the All behaviors in individual bim files behavior packaging option. While it gives you total control, this
option also creates more work for your application programmer, since your application is responsible for making sure
that each behavior is loaded in the run-time engine before it is invoked. It also means that you must call the
LoadPackage or LoadPackageFile API method for every single behavior that the SimBionic run-time needs to load,
which is less efficient than loading many behaviors from a single package file.
Tip #2: If at any time you decide that you no longer want to use dynamic behavior loading, simply select the All
behaviors in sim file option under Behavior packaging mode in the Project Settings. This will cause all of your
behaviors to revert back to being stored in the compiled project file. It will not delete any custom packages that youve
created. Note that this operation cannot be undone.
Handling Run-time Errors
Understanding error handling
Sometimes errors occur in the underlying code that implements an action or predicate. SimBionic provides a built-in
facility, modeled after Javas exception-handling mechanism, for handling these run-time errors in a graceful and
consistent fashion within your behaviors.
To make use of this facility, you must ensure that your action and predicate code throws the special SimBionic
exception AI_Exception (for C++) or SB_Exception (for Java) when it encounters an error. SimBionic will not catch
other kinds of exceptions.
SimBionic provides two error-handling constructs and three core actions devoted to error recovery:
The catch rectangle is the core error-handling construct that catches exceptions. See The catch rectangle
for more information.
The Retry, Resume, and Rethrow core actions help you recover from an error once its been caught. See
Recovery actions for more information.
125
The always rectangle enables you to ensure that certain actions are always executed at a behaviors
termination. See The always rectangle for details.
It is otherwise identical to a normal rectangle: it can invoke an action or behavior; it can have one or more variable
bindings; and it can have both incoming and outgoing connectors. A behavior may have at most one catch rectangle.
Note that the catch rectangle is optional. If a behavior does not have a catch rectangle, then any exception thrown in
that behavior will be automatically thrown down the stack to its invoking behavior (there to be handled by that
behaviors catch rectangle, if any, or else thrown down the stack again). When an exception is thrown down the stack
in this manner, the behavior that threw it is popped from the stack (along with any behaviors above it on the stack).
For example, suppose that behavior A invokes behavior B. Behavior A has a catch rectangle but B does not. If an
exception is thrown by an action rectangle in behavior B, behavior B will throw the exception to its invoking behavior,
A, and pop itself from the stack. Behavior As catch rectangle will catch the exception, and execution will continue from
that rectangle.
If an exception is thrown in the bottommost behavior on the stack and no catch rectangle is provided, then the Update
API method will return kFailure, and the GetLastError API method will return the message string for the exception.
Note: If a new exception is thrown during the execution of a catch block, the current exceptions information is lost,
and control returns to the catch rectangle at the start of the current catch block.
The Retry action causes behavior execution to jump to the rectangle where the exception was thrown in this
behavior, executing that rectangle exactly as if it had just become the current rectangle in normal fashion
that is, the bindings for that rectangle will be evaluated, and then the action or behavior will be invoked. Note
that this behavior might not be the one that threw the original exception (because that behavior may have
been popped off the stack). If this is the case, then the rectangle that invoked the behavior that threw the
original exception will be retried.
Retry is generally invoked after attempting to diagnose and fix whatever error condition caused the
exception to be thrown, in the hopes that the second attempt will be more successful.
The Resume action causes execution to resume at the rectangle in this behavior where the exception was
thrown without attempting to retry execution of that rectangle. That rectangle becomes the new current
rectangle, but its bindings are not evaluated and its action or behavior expression is not executed. The
conditions leading out of the rectangle will be evaluated normally, however.
Resume is typically invoked when it is not possible to fix the error condition (so retrying the offending action
or predicate would be fruitless), but it is still possible to clean up after the error and continue with the
behaviors normal course of execution.
The Rethrow action rethrows the current exception down the stack to the current behaviors invoking
behavior and then terminates the current behavior just as if a final rectangle had been executed. The
invoking behavior then becomes the new current behavior and must attempt to handle the exception exactly
as if it had been thrown in that behavior.
Rethrow is called when a behavior is unable to recover from an error and needs to pass responsibility for
error recovery on to another behavior.
126
It is otherwise identical to a normal rectangle: it can invoke an action or behavior; it can have one or more variable
bindings; and it can have both incoming and outgoing connectors. The always rectangle is optional. If it is present,
however, there must be a path leading from it to a final rectangle. A behavior may have at most one always rectangle.
Always rectangles are primarily useful for cleaning up any resources that might have been used by a behavior. Typical
actions for an always block include deallocating client-allocated memory and relinquishing control over O/S resources
(e.g., files, devices). Note that there are a variety of ways in which a behavior can be popped from the stack, and the
always rectangle will execute for all of them:
disruption: A non-interrupt connector in a behavior lower on the stack has been followed.
unhandled exception: An exception was thrown in the behavior or one of its child behaviors, and the behavior
contains no catch rectangle.
rethrown exception: An exception was caught in this behavior, but the Rethrow action was invoked.
cleared: The client application called an API method (e.g., SetBehavior) that cleared the entitys execution
stack, including this behavior.
127
1.
2.
Notice that the dialog box contains sections for specifying the classs name, description, member variables,
and methods.
3.
Click in the Fully-Qualified Java Class box and type the fully-qualified Java name of the class.
The fully-qualified name includes the package specification for the class, just as though you were importing
it into a Java file. Example: com.mycompany.myproject.FooClass
4.
Click in the SimBionic Class Name box and type the SimBionic name of the class.
This is the name that will be used to refer to the class in your SimBionic project. It is generally the name of
your Java class without the package specification, though it can be whatever you wish. Sometimes
shortening long class names can improve the readability of your behaviors.
128
5.
Click in the Description box, and type a brief description of the class.
This documentation helps ensure your class will be readily understood by other members of your team, and
is also useful for refreshing your own memory in case you need to return to your project months or years
later.
6.
To add a member variable, click the Insert button next to the Member Variables list box. (To add a
method instead, skip to step 12.)
A new row will be added to the list box, with the Name field selected.
7.
8.
9.
17. Optionally click in the Description box, and type a description of the method.
18. Optionally click Insert to add a parameter to the method.
A new row will be added to the Parameters list box, with the Name field selected.
19. Type the name you want to give the parameter.
This name does not have to match the parameter name of the underlying Java method.
20. Select the data type of the parameter.
This data type must exactly match the type of the parameter in the underlying Java class. Note that if the
parameters type is of a class type that you have not yet defined in SimBionic, you will first need to define
that class and then set the type for the parameter.
129
Right-click on the Types header in the Catalog and select the Import Java Class option.
The Import Java Class dialog appears:
2.
Click in the Java classpath box and type the path to the root of the Java class hierarchy or jar file
containing the class you wish to import.
You may optionally click the "..." button to the right of the box, which will display a Browse for Folder dialog
box allowing you to browse your hard disk for the desired directory.
3.
Click in the Fully-specified Java class name box and type the fully-qualified Java name of the class
you wish to import.
The fully-qualified name includes the package specification for the class, just as though you were importing
it into a Java file. Example: com.mycompany.myproject.FooClass
4.
Once you have imported the class into SimBionic, it is identical to a class created by hand in the editor. You may edit it
or delete it if you wish.
You may also import a class from a special SimBionic class specification file, which has the following format:
class com.mycompany.Test
var com.mycompany.Employee employee
var static int counter
method static int getCounter()
method int abs(n : float [in])
endclass
To import from a class specification file, follow these steps:
1.
130
Right-click on the Types header in the Catalog and select the Import Class Spec option.
An Open dialog box appears that allows you to browse your hard disk or network for class specification files.
2.
Use the dialog box to locate the folder containing the class specification file youre after, and then
click the file.
The file is displayed in the Filename text box.
3.
For the complete specification, see The class specification file format.
Using classes
Variables with a class type are created and used much like other SimBionic variables (both local and global) except
that they must first be initialized. One way to do this is via the class constructor. Unlike Java, there is no new
command. Instead, calls to constructors must be preceded by the class name. For example, to initialize a variable mc
of type MyClass, the variable binding would look like
mc = MyClass.MyClass()
You can also initialize a variable of type class by creating a variable binding with an expression that evaluates to a
class object. For example:
mc = GetMyClassObjectByName("bob")
mc = mc2
In all of these examples, the variable mc is being bound to a particular Java class object. If mc is not bound, then its
default value will be the Java value null. You can detect a null value using the core predicate IsNull.
Member Variables
Once a variable is initialized with a class object, then you can access its member variables via the dot operator:
mc._integer + 5
computeSum(mc.myInt)
Member variables can be used in an expression anywhere that a normal global or local variable would appear. You
can also bind a member variable of a class object by creating a binding on the class variable itself and then selecting
which member you wish to bind. (See Attaching bindings to a Canvas element for details.)
Methods
You can also invoke the methods of the class object with the dot operator:
mc.setMyInt(anotherMyClass)
Methods can be used in an expression anywhere that an action or predicate would normally appear. Note that the
SimBionic run-time engine will attempt to automatically typecast method parameters to match the types expected by
Java. See Understanding automatic casting for more information.
Static Members
Static methods and member variables can be accessed both through a particular variable of that type:
mc.myStaticMethod(2,3)
or by using the unqualified class name:
MyClass.myStaticMethod(2,3)
Java arrays (e.g., int[]) are not handled. Methods and member variables that use arrays are ignored when
importing from a Java class.
It is not generally possible to create a deep copy of class objects. This means that changes caused by variable
bindings (including functions called in those bindings) on conditions that fail will not be retracted as with the
built-in SimBionic types.
Understanding automatic casting
Java classes in SimBionic may reference any Java primitive type as well as any Java class defined in the SimBionic
project. (Standard Java classes such as Integer, Boolean, Float, String, Long, Double, Short, Byte, Char, ArrayList,
Vector, and Object are provided as Core Classes in every project.)
The table below shows the conversion behavior exhibited by the Java SimBionic engine for the various permutations
of classes and built-in data types. The left-hand column represents either the left-hand side of a variable binding or
the formal parameter of a class method ("that which is being converted to"). The top row is either the right-hand side
131
of a variable binding, the return value of a class method, or the actual parameter of a class method ("that which is
being converted from").
Converting From
int, float,
boolean, entity
Integer, Float,
Boolean, Long
data
Object
Java class C2
int, float,
boolean, entity
no conversion
needed
corresponding
types are
converted
ILLEGAL
ILLEGAL
ILLEGAL
Integer, Float,
Boolean, Long
corresponding
types are
converted
no conversion
needed
ILLEGAL
ILLEGAL
ILLEGAL
data
ILLEGAL
upcast to
Object (data)
no conversion
needed
no conversion
need
upcast to
Object (data)
Object
ILLEGAL
upcast to
Object
no conversion
need
no conversion
need
upcast to
Object
Java class C1
ILLEGAL
ILLEGAL
cast to C1 &
catch exception
(if any)
cast to C1 &
catch exception
(if any)
cast to C1 &
catch exception
(if any)
Converting To
SimBionic primitive types are typecast by the engine to Java types as follows. Note that some SimBionic primitive
types have no corresponding Java primitive type.
SimBionic
Java
Java
SimBionic
primitive
boxed type
primitive
boxed type
integer
int
Integer
data
Object
Object
float
float
Float
vector
SB_Vector
SB_Vector
boolean
boolean
Boolean
array
Vector
Vector
entity
long
Long
table
Vector
Vector
string
String
String
There are several Java primitive types that are not fully supported by the SimBionic engine in the sense that one
cannot create a variable of those types. Java classes may use those types, however, in their methods and fields, and
the SimBionic engine will typecast accordingly. The following table specifies the various typecasts. Note that these
unsupported primitives are changed to be SimBionic class objects of their boxed type.
From Java
To SimBionic
short
Short
char
Character
byte
Byte
double
Double
Here we present an extended example to clarify the workings of type conversion. Suppose we have the Java classes
MyClass and OtherClass in the package com.mycompany.mystuff:
132
class MyClass
{
OtherClass methodA(Object o) {...}
Object methodB(Integer i) {...}
Integer methodC(int i) {...}
int methodD() {...}
String methodE(long l) {...}
short methodF(double d) {...}
}
Now we have a SimBionic behavior with the following local variables:
MyClass mc;
OtherClass oc;
int i;
Integer I;
data d;
Object o;
string s;
float f;
entity e;
Consider the following variable bindings in SimBionic:
1.
oc = mc.methodA(I)
Returned OtherClass object gets bound to variable of same type.
The Integer param gets upcast to an Object.
2.
d = mc.methodA(d)
Returned OtherClass object is converted (upcast) to data variable.
Data param gets converted to an Object.
3.
o = mc.methodA(o)
Returned OtherClass object is upcast to Object.
4.
oc = mc.methodA(i)
ILLEGAL!
Can't cast a primitive SimBionic type (integer) to a Java object other than its matching capital-letter class.
5.
oc = mc.methodB(I)
Returned Object is downcast to OtherClass (may throw ClassCastException, which will be caught).
6.
o = mc.methodB(i)
Primitive int param is converted to Integer.
7.
d = mc.methodB(I)
Returned Object is converted to type data.
133
8.
i = mc.methodC(I)
Returned Integer is converted to primitive int.
Integer param is converted to primitive int.
9.
o = mc.methodC(i)
Returned Integer is upcast to Object.
Primitive int param is passed as-is.
10.
I = mc.methodD()
Returned primitive int is converted to Integer.
11.
o = mc.methodD()
ILLEGAL!
Can't cast returned primitive int to Object other its matching capital-letter class.
12.
= mc.methodE(e)
Primitive entity param is converted to Java long. Returned String is converted to primitive string.
13.
= mc.methodF(f)
Primitive float param is converted to Java primitive double. Returned Java primitive short is converted to
SimBionic primitive int.
The conversion cases for arrays are as follows:
Converting From
134
Converting To
SB array
Vector
SB array
no conversion needed
Vector
no conversion needed
Impressive speed, helped by a load-balancing scheduling system for controlling large numbers of entities
without sapping the CPU.
Efficient use of memory, thanks to both a small footprint and the engines own memory management
system.
Powerful API methods that let you precisely control when each entity is created, how often it executes,
which behaviors it executes, and how extensively its activities are recorded.
A thin API for easy integration with virtually any simulation or game.
Direct support for C++. (SimBionic also includes a Java run-time engine that makes it easy to work with
Java-based simulations or games; to learn more, see the Understanding the Java run-time engine topic.)
The C++ run-time engine is stored in a library that must be loaded by your application. There are four versions of this
library in your SimBionic package:
A dynamic library (DLL) that you can load at any time via your simulation or game; and that you can
unload at any time, causing it to free all the memory it was occupying.
A static library (LIB) that must be linked in as part your simulation or game, launches at the same time as
your simulation or game, and takes up memory for the entire time that your simulation or game is running.
This static version is therefore less flexible. On the plus side, however, it spares you from having to
distribute a SimBion.dll file with your program; and eliminates the possibility that the SimBion.dll file on
someones system might be improperly installed, accidentally damaged or deleted, or get out of sync with
the version of SimBionic being used.
Development editions of both the dynamic and static libraries that contain extra code to enable
interactive debugging and logging (as described in the Debugging your project and Logging your project's
execution topics).
Each of these four library files is stored in a folder that identifies which version of the engine it contains. In addition,
you can differentiate the files by their sizes (e.g., the development versions are larger than the release versions); and
via the GetVersion API method, which tells you the currently-loaded engines version number, and whether its a
release or development version.
In addition to the engine library, you must #include several C++ files packaged with SimBionic for your project to run
properly. (Note: SimBionic is designed to work with C++ or Java, which are the most popular object-oriented
programming languages for creating simulations and games. If youre using a different language, see the Using
SimBionic with other languages topic.)
These files are:
AI_Config.h: A header file that defines configuration settings for the enginee.g., the filename and location
of your compiled project file; the filename and location of the engines Log file, whether the interactive
debugging feature is enabled or disabled; etc.
AI_Engine.h and AI_Engine.cpp: Defines the AI_Engine wrapper class that provides the API for the runtime engine.
AI_Exception.h and AI_Exception.cpp: Defines the AI_Exception class used internally by the run-time
engine.
AI_Interface.h and AI_Interface.cpp: Defines the AI_Interface base class that you will subclass in order to
implement your actions and predicates.
AI_Params.h and AI_Params.cpp: Defines the parameters for actions; the parameters and return values
for predicates; important constants; and methods for setting and inspecting a value.
Note: You must use the version of the supplementary files supplied with the run-time engine. For example, if you try to
use a run-time engine from SimBionic 1.2 with the AI_Interface.h file from SimBionic 1.1, youll receive an error
message.
For more information about using the C++ run-time engine, see the following topics:
To configure your C++ project settings and development environment for SimBionic, see the Setting up your
C++ project topic.
To create the underlying C++ code for the custom actions and predicates in your project, see the
Implementing your application interface in C++ topic.
135
To generate skeleton code for your custom actions and predicates, see the Generating skeleton code for
C++ topic.
To access and/or set the parameter values of your custom actions and predicates via C++ code, see the
Accessing and setting parameter values in C++ topic.
To generate symbolic names for all the actions and predicates in your project, see the Creating C++
symbolic names for actions & predicates topic.
To exploit the run-time engines API methods, see the Using the C++ engine's API methods topic.
To view sample code for starting up the engine, see the Starting and controlling the C++ run-time engine
topic.
To terminate the engine, see the Shutting down the C++ run-time engine topic.
For a summary of C++ run-time engine information, see the SimBionic C++ Engine Cheat Sheet topic.
Using SimBionic with other languages
SimBionic is designed to interact directly with C++ or Java, which are the most popular object-oriented programming
languages used for creating simulations and games. If your program is written in some other language, you can still
utilize SimBionic but must take some additional steps.
First, you must be able to access a dynamic link library from the language youre using. Its not possible to use the
static C++ library version of SimBionic with a non-C++ language, nor is it generally possible to use the AI_Engine
interface (unless you compile AI_Engine as a separate C++ component). In most cases, itll be easiest to access the
exported DLL functions directly from your simulation language. The arguments expected by these functions are
available as primitive types in most modern languages, so type conversion is likely to be relatively easy.
Second, you must implement a custom C++ AI_Interface class regardless of the language in which your simulation
system is written. As a result, you must be able to create a bridge between your non-C++ simulation and your
AI_Interface. Many modern languages provide built-in protocols for connecting to C++ modules; in these cases,
building such a bridge is very easy.
For languages that provide no such facility, more indirect routes are possible. For example, you could implement your
AI_Interface as a separate process that communicates with your simulation over a TCP/IP connection (or via remote
method invocation, or using COM, etc.). The only requirement is that SimBionic entities have access to the simulation
via the AI_Interface, regardless of how the messages actually are communicated.
Setting up your C++ project
Before you can use the SimBionic run-time engine with your C++ application, youll first need to set up your C++
project to work with SimBionic. This involves only a few simple steps:
1.
Add SimBionics C++ interface files to your project or makefile so that they will be compiled in with
your application code.
These files are:
AI_Config.h: Defines configuration settings for the enginee.g., the filename and location of your
compiled project file; the filename and location of the engines Log file, whether the interactive
debugging feature is enabled or disabled; etc.
AI_Engine.h and AI_Engine.cpp: Defines the AI_Engine wrapper class that provides the API for the
run-time engine.
AI_Exception.h and AI_Exception.cpp: Defines the AI_Exception class used internally by the runtime engine.
AI_Interface.h and AI_Interface.cpp: Defines the AI_Interface base class that you will subclass in
order to implement your actions and predicates.
AI_Params.h and AI_Params.cpp: Defines the parameters for actions; the parameters and return
values for predicates; important constants; and methods for setting and inspecting a value.
3.
Add the SimBionic static library Simbion.lib to the list of input libraries in your projects linker
settings.
There are two versions of the static library available, a Development build that includes logging and
interactive debugging capabilities, and a Production build that is optimized for maximum speed. Make sure
you link against the appropriate one for your application.
4.
136
This will instruct SimBionic to load the SimBionic DLL and to invoke its API methods using function pointers
to the DLLs exported methods. (The details of this are hidden from your application by the AI_Engine
wrapper class.)
5.
6.
If your project uses only the two default AP modules (Core and Project):
a.
Disable AP modules by going to the Build menu, selecting the Project Settings option, and unchecking
the "Enable AP modules" box. This will tell the SimBionic run-time engine to look in the compiled
project file for information about your projects actions and predicates.
b.
Create a subclass of the SimBionic class AI_Interface. (See "Subclassing AI_Interface" below.) This
class will contain the implementation for all of your actions and predicates.
c.
Implement the DoAction and DoPredicate methods of your subclass. These are the methods called by
the run-time engine when it invokes an action or predicate. (See Coding actions in C++ and Coding
predicates in C++.)
Enable AP modules by going to the Build menu, selecting the Project Settings option, and checking the
"Enable AP modules" box. This will tell the SimBionic run-time engine to look to the AP modules
themselves (rather than the compiled project file) for information about your projects actions and
predicates.
b.
Create a subclass of the SimBionic class AI_Interface for each AP module in your project (aside from
the built-in Core AP module). (See "Subclassing AI_Interface" below.) Each subclass will contain the
implementation for the actions and predicates in a single AP module. Remember that if you have
imported an existing AP module into your project, you can simply reuse the existing subclass for that
AP module.
c.
Implement the DoAction and DoPredicate methods of each subclass. These are the methods called by
the run-time engine when it invokes an action or predicate. (See Coding actions in C++ and Coding
predicates in C++.)
d.
Subclassing AI_Interface
To create a subclass of AI_Interface, first include the header file defining the AI_Interface class itself:
#include "Interface/AI_Interface.h"
Next, define a new class that takes AI_Interface as its parent class:
class MyInterface : public AI_Interface
{
};
137
AI_Interface is an abstract base class that defines a number of methods. Two of these methods, DoAction and
DoPredicate, are pure virtual methods and must be overridden.
Coding actions in C++
Each time the run-time engine invokes an action, it calls the DoAction method of the AI_Interface subclass that
implements that action. This pure virtual method takes three arguments: the procedure identifier for the action to be
enacted, the unique identifier for the entity performing the action, and an ordered, typed list of parameters for the
action. The types of all of these arguments are defined in AI_Params.h.
The body of the DoAction method carries out the operations appropriate for the given action identifier, often (but not
necessarily) involving manipulation or assessment of simulation state. A switch statement is commonly used to select
the proper code path based on the procedure identifier. One convenient way to organize your code is to create an
auxiliary method for each action that's called by the associated case statement.
To illustrate, the boldfaced portion of the code below is an example of how to code a customized action named Say in
C++. This action accepts a text string and then displays a sentence onscreen that incorporates the string:
***************
class MyInterface : public AI_Interface
{
// this method defines the implementation for all actions
void DoAction(AI_ProcId actionId, AI_Entity entityId, AI_ParamVec& params)
{
switch (actionId)
{
// implementation for an action "Say" that prints out its one parameter
//
//
//
(as opposed to the integer, float, vector, Boolean, entity, data, any, or invalid data type)
case MYPROJECT_ACTION_Say:
printf("Entity %d says: %s\n", entityId, params[0].String());
break;
}
}
// this method implements all predicates
AI_Param DoPredicate(AI_ProcId predId, AI_Entity entityId, AI_ParamVec& params)
{
AI_Param returnValue;
return returnValue;
}
};
***************
The constant MYPROJECT_ACTION_Say in the example above represents the unique procedure identifier (or
AI_ProcId) for that action. These constants are defined in a file generated by the SimBionic editor. For more
information, see the topic Creating C++ symbolic names for actions & predicates.
The SimBionic editor can help you with the task of coding your actions by automatically generating skeleton code for
your custom AI_Interface subclass. For more information on how to do this, see the Generating skeleton code for C++
topic.
For the syntax you must use to access and/or set parameter values, see the Accessing and setting parameter values
in C++ topic.
In addition to actions, you must create underlying C++ code for your projects predicates. To learn how, see the
Coding predicates in C++ topic.
Coding predicates in C++
138
Each time the run-time engine invokes a predicate, it calls the DoPredicate method of the AI_Interface subclass that
implements that predicate. This pure virtual method takes three arguments: the procedure identifier for the predicate to
be enacted, the unique identifier for the entity performing the predicate, and an ordered, typed list of parameters for
the predicate. The types of all of these arguments are defined in AI_Params.h.
The body of the DoPredicate method carries out the operations appropriate for the given predicate identifier, often (but
not necessarily) involving manipulation or assessment of simulation state. A switch statement is commonly used to
select the proper code path based on the procedure identifier. One convenient way to organize your code is to create
an auxiliary method for each action that's called by the associated case statement.
To illustrate, the boldfaced portion of the code below is an example of how to code a customized predicate named
IsGreaterThan thats coded in C++. This predicate receives two numbers, evaluates whether the first number is
greater than the second number, and then returns a Boolean value of true or false:
***************
class MyInterface : public AI_Interface
{
// this method defines the implementation for all actions
void DoAction(AI_ProcId actionId, AI_Entity entityId, AI_ParamVec& params)
{
}
// this method implements all predicates
AI_Param DoPredicate(AI_ProcId predId, AI_Entity entityId, AI_ParamVec& params)
{
AI_Param returnValue;
switch (predId)
{
case MYPROJECT_PRED_IsGreaterThan:
bool result = (params[0].Float > params[1].Float);
returnValue.SetBoolean(result);
break;
}
return returnValue;
}
};
***************
The constant MYPROJECT_PRED_Say in the example above represents the unique procedure identifier (or
AI_ProcId) for that predicate. These constants are defined in a file generated by the SimBionic editor. For more
information, see the topic Creating C++ symbolic names for actions & predicates.
The SimBionic editor can help you with the task of coding your predicates by automatically generating skeleton code
for your custom AI_Interface subclass. For more information on how to do this, see the Generating skeleton code for
C++ topic.
For the syntax you must use to access and/or set parameter values, see the Accessing and setting parameter values
in C++ topic.
In addition to predicates, you must create underlying C++ code for your projects actions. To learn how, see the
Coding actions in C++ topic.
Generating skeleton code for C++
To integrate your C++ application with the SimBionic run-time engine, you must first subclass the AI_Interface class
provided with SimBionic and write code for each of the actions and predicates in your project. While this is typically not
a difficult process, it can be time-consuming if you have defined many actions and predicates. SimBionic thus provides
the capability to automatically generate skeleton code for these subclasses. Of course, you will still have to implement
the functionality of each action and predicate, but starting with the auto-generated skeleton code can save you a
considerable amount of time. For an example of the skeleton code generated by the editor, see the Template sample
project.
139
Select the File menu, then select Export, then select Export Skeleton Code.
An Export Skeleton Code dialog box will appear:
2.
Select the actions and predicates for which you would like SimBionic to generate skeleton code by
clicking on the checkboxes next to each one.
If you wish to generate code for all actions or all predicates, simply click the checkbox next to Actions or
Predicates.
3.
4.
If you wish to export C++ definitions for the constants in your project, make sure that the Export
user-defined constants box is checked.
This option is checked by default. If selected, SimBionic will export a #define statement for each of your
constants of type float, integer, Boolean, or string. Each exported constant will have a name of the form
myproject_myconstantname, as in this example:
#define MYPROJECT_RADARRANGE
350
140
5.
If you wish to export your constant definitions to a separate header file, make sure that the Export
constant definitions to separate file box is checked.
If you select this option, SimBionic will create a separate header file for the #define statements described in
Step 4. This file will have the same name as your main skeleton code header file, plus the extension
"_constants". This option is checked by default.
6.
If you wish to view the exported code after it is generated, make sure that the Open files after export
box is checked.
If you select this option, SimBionic will open the exported file(s) in Notepad. This option is checked by
default.
7.
8.
9.
Click Save.
For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.
SimBionic will generate the specified skeleton code file, including one subclass of AI_Interface for each AP
module selected. If you selected the View after export option in Step 6, each file will be opened in Notepad
for you to review.
10. Include the header file in your application.
Tip: If youve already using SimBionic-generated skeleton code in your application, make sure not to export new
skeleton code to the same folder and filename, since it will overwrite any action or predicate implementations that
youve added to the file. If you have added new actions and predicates to your project and would like to generate
skeleton code for them, simply follow these steps:
1.
Select the File menu, then select Export, then select Export Skeleton Code.
2.
Select only the new actions and predicates by clicking on the checkboxes next to each one.
3.
4.
Make sure that the Open files after export box is checked.
5.
6.
7.
Click Save.
SimBionic will generate the specified skeleton code files, opening them in Notepad for you to view.
8.
Cut and paste the relevant code snippets for each action and predicate.
Make sure to copy:
141
#define SIM_REV 16
// actions
#define PACMAN_ACTION_CalcShortestPath 133
#define PACMAN_ACTION_DrawPath 136
#define PACMAN_ACTION_FindDestination 129
#define PACMAN_ACTION_FindPMFacing 131
#define PACMAN_ACTION_FindPMTrailing 132
#define PACMAN_ACTION_GetPathTurn 134
#define PACMAN_ACTION_PostDest 135
#define PACMAN_ACTION_RankDirections 130
#define PACMAN_ACTION_SetDirection 128
// predicates
#define PACMAN_PRED_ABS 141
#define PACMAN_PRED_AdjacentToPM 148
#define PACMAN_PRED_Direction 133
#define PACMAN_PRED_Direction_PM 135
#define PACMAN_PRED_IsActive 131
#define PACMAN_PRED_IsAtIntersection 144
#define PACMAN_PRED_IsBlocked 137
#define PACMAN_PRED_IsFleeing 132
#define PACMAN_PRED_IsGameOver 130
#define PACMAN_PRED_IsPlaying 129
#define PACMAN_PRED_IsPMOnNewLane 149
#define PACMAN_PRED_IsReverse 143
#define PACMAN_PRED_Location 134
#define PACMAN_PRED_Location_PM 136
#define PACMAN_PRED_Name 128
#define PACMAN_PRED_Opposite 142
#define PACMAN_PRED_Random 138
#define PACMAN_PRED_SameLane 145
#define PACMAN_PRED_SameLoc 146
#define PACMAN_PRED_X 139
#define PACMAN_PRED_Y 140
// constants
// How fast the ghosts move
#define PACMAN_GHOST_SPEED 15
class PacMan_Interface : public AI_Interface
{
public:
void DoAction(AI_ProcId actionId, AI_Entity entityId, AI_ParamVec& params);
AI_Param DoPredicate(AI_ProcId predId, AI_Entity entityId, AI_ParamVec& params);
// actions
void CalcShortestPath(AI_Vector target, AI_Boolean allowreverse, std::string& path, AI_Integer& pathlength);
142
143
break;
case PACMAN_ACTION_DrawPath:
DrawPath(params[0].String());
break;
case PACMAN_ACTION_FindDestination:
FindDestination(params[0].Vector(), params[1].String(), params[2].Vector());
break;
case PACMAN_ACTION_FindPMFacing:
FindPMFacing(params[0].Vector(), params[1].Vector(), params[2].Vector(), params[3].Integer());
break;
case PACMAN_ACTION_FindPMTrailing:
FindPMTrailing(params[0].Vector(), params[1].Vector(), params[2].Vector(), params[3].Integer());
break;
case PACMAN_ACTION_GetPathTurn:
{
std::string param0( params[0].String() );
std::string param1( params[1].String() );
GetPathTurn(param0, param1);
params[0].SetString( param0.c_str() );
params[1].SetString( param1.c_str() );
}
break;
case PACMAN_ACTION_PostDest:
PostDest(params[0].String(), params[1].Vector());
break;
case PACMAN_ACTION_RankDirections:
{
std::string param1( params[1].String() );
std::string param2( params[2].String() );
std::string param3( params[3].String() );
std::string param4( params[4].String() );
RankDirections(params[0].Vector(), param1, param2, param3, param4);
params[1].SetString( param1.c_str() );
params[2].SetString( param2.c_str() );
params[3].SetString( param3.c_str() );
params[4].SetString( param4.c_str() );
}
break;
case PACMAN_ACTION_SetDirection:
SetDirection(params[0].String());
break;
default:
// unknown action
break;
}
}
AI_Param PacMan_Interface::DoPredicate(AI_ProcId predId, AI_Entity entityId, AI_ParamVec& params)
{
144
switch (predId)
{
case PACMAN_PRED_ABS:
return ABS(params[0].Float());
case PACMAN_PRED_AdjacentToPM:
return AdjacentToPM(params[0].Boolean());
case PACMAN_PRED_Direction:
return Direction();
case PACMAN_PRED_Direction_PM:
return Direction_PM();
case PACMAN_PRED_IsActive:
return IsActive();
case PACMAN_PRED_IsAtIntersection:
return IsAtIntersection();
case PACMAN_PRED_IsBlocked:
return IsBlocked(params[0].String(), params[1].Vector());
case PACMAN_PRED_IsFleeing:
return IsFleeing();
case PACMAN_PRED_IsGameOver:
return IsGameOver();
case PACMAN_PRED_IsPlaying:
return IsPlaying();
case PACMAN_PRED_IsPMOnNewLane:
return IsPMOnNewLane();
case PACMAN_PRED_IsReverse:
return IsReverse(params[0].String());
case PACMAN_PRED_Location:
return Location();
case PACMAN_PRED_Location_PM:
return Location_PM();
case PACMAN_PRED_Name:
return Name();
case PACMAN_PRED_Opposite:
return Opposite(params[0].String());
case PACMAN_PRED_Random:
return Random();
case PACMAN_PRED_SameLane:
return SameLane(params[0].Vector(), params[1].Vector());
case PACMAN_PRED_SameLoc:
return SameLoc(params[0].Vector(), params[1].Vector());
case PACMAN_PRED_X:
return X(params[0].Vector());
case PACMAN_PRED_Y:
return Y(params[0].Vector());
default:
// unknown predicate
return AI_Param();
}
}
145
146
*/
void PacMan_Interface::FindPMFacing(AI_Vector& dest1, AI_Vector& dest2, AI_Vector& dest3, AI_Integer& count)
{
// your FindPMFacing implementation here
}
/**
* Look at pacman's location and direction, and find all the
* trailing intersections, one step removed. The count indicates
* how many destinations
* @param dest1 : vector [out]
* @param dest2 : vector [out]
* @param dest3 : vector [out]
* @param count : integer [out]
*/
void PacMan_Interface::FindPMTrailing(AI_Vector& dest1, AI_Vector& dest2, AI_Vector& dest3, AI_Integer& count)
{
// your FindPMTrailing implementation here
}
/**
* Pops next direction along shortest path computed by the action
* CalcShortestPath.
* @param path : string [in/out]
* @param turn : string [out]
*/
void PacMan_Interface::GetPathTurn(std::string& path, std::string& turn)
{
// your GetPathTurn implementation here
}
/**
* TEMPORARY
* @param name : string [in]
* @param dest : vector [in]
*/
void PacMan_Interface::PostDest(AI_String name, AI_Vector dest)
{
// your PostDest implementation here
}
/**
* Ranks all four directions for current thing moving toward the
* given
* @param target : vector [in]
* @param direction1 : string [out]
* @param direction2 : string [out]
* @param direction3 : string [out]
* @param direction4 : string [out]
147
*/
void PacMan_Interface::RankDirections(AI_Vector target, std::string& direction1, std::string& direction2, std::string&
direction3, std::string& direction4)
{
// your RankDirections implementation here
}
/**
* Request next direction of current thing. Specify 'left',
* 'right', 'up', 'down', or
* @param direction : string [in]
*/
void PacMan_Interface::SetDirection(AI_String direction)
{
// your SetDirection implementation here
}
// ---- Predicate Implementations
/**
* Returns absolute value of the given
* @param number : float [in]
* @return float
*/
AI_Param PacMan_Interface::ABS(AI_Float number)
{
// your ABS implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Return true if current thing is "adjacent" to
* @param allowreverse : boolean [in]
* @return boolean
*/
AI_Param PacMan_Interface::AdjacentToPM(AI_Boolean allowreverse)
{
// your AdjacentToPM implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns direction of current
* @return string
*/
AI_Param PacMan_Interface::Direction()
{
// your Direction implementation here
return AI_Param(); // TODO: your return value here
148
}
/**
* Returns direction of
* @return string
*/
AI_Param PacMan_Interface::Direction_PM()
{
// your Direction_PM implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if current thing is active, i.e. outside of hideout and
* has not been
* @return boolean
*/
AI_Param PacMan_Interface::IsActive()
{
// your IsActive implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns true if current entity is at an
* @return boolean
*/
AI_Param PacMan_Interface::IsAtIntersection()
{
// your IsAtIntersection implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if given direction is blocked at given location in
* @param direction : string [in]
* @param location : vector [in]
* @return boolean
*/
AI_Param PacMan_Interface::IsBlocked(AI_String direction, AI_Vector location)
{
// your IsBlocked implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if current thing is fleeing (during power up for ghost,
* and always for
* @return boolean
149
*/
AI_Param PacMan_Interface::IsFleeing()
{
// your IsFleeing implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if game is
* @return boolean
*/
AI_Param PacMan_Interface::IsGameOver()
{
// your IsGameOver implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if game is
* @return boolean
*/
AI_Param PacMan_Interface::IsPlaying()
{
// your IsPlaying implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if pacman has just entered new
* @return boolean
*/
AI_Param PacMan_Interface::IsPMOnNewLane()
{
// your IsPMOnNewLane implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Checks if given direction is reverse of current thing's most
* recent
* @param direction : string [in]
* @return boolean
*/
AI_Param PacMan_Interface::IsReverse(AI_String direction)
{
// your IsReverse implementation here
return AI_Param(); // TODO: your return value here
}
150
/**
* Returns location of current
* @return vector
*/
AI_Param PacMan_Interface::Location()
{
// your Location implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns location of
* @return vector
*/
AI_Param PacMan_Interface::Location_PM()
{
// your Location_PM implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns name of current
* @return string
*/
AI_Param PacMan_Interface::Name()
{
// your Name implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns opposite of given
* @param direction : string [in]
* @return string
*/
AI_Param PacMan_Interface::Opposite(AI_String direction)
{
// your Opposite implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns a random floating point number between 0 and
* @return float
*/
AI_Param PacMan_Interface::Random()
{
// your Random implementation here
return AI_Param(); // TODO: your return value here
151
}
/**
* Returns true if the two locations are on the same lane,
* including end
* @param loc1 : vector [in]
* @param loc2 : vector [in]
* @return boolean
*/
AI_Param PacMan_Interface::SameLane(AI_Vector loc1, AI_Vector loc2)
{
// your SameLane implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns true if loc1 and loc2 describe the same
* @param loc1 : vector [in]
* @param loc2 : vector [in]
* @return boolean
*/
AI_Param PacMan_Interface::SameLoc(AI_Vector loc1, AI_Vector loc2)
{
// your SameLoc implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns x coordinate of given
* @param location : vector [in]
* @return float
*/
AI_Param PacMan_Interface::X(AI_Vector location)
{
// your X implementation here
return AI_Param(); // TODO: your return value here
}
/**
* Returns y coordinate of given
* @param location : vector [in]
* @return float
*/
AI_Param PacMan_Interface::Y(AI_Vector location)
{
// your Y implementation here
return AI_Param(); // TODO: your return value here
}
Creating C++ symbolic names for actions & predicates
152
The SimBionic editor assigns each action and predicate in your project a unique ID number, which it saves to your
compiled project file. The SimBionic run-time engine then refers to every action and predicate via these ID numbers.
This is most efficient for SimBionics execution; but using these ID numbers in your C++ code is likely to produce
programs that are difficult to read and debug.
As a result, you can request SimBionic to generate unique symbolic names to represent these ID numbers. You can
then use these symbolic names in place of the ID numbers in the C++ code of your simulation or game.
The group of symbolic names for your projects actions and predicates is defined in a C++ header file, and is a text file
with an .H extension (e.g., MyProject.h) that you can include via C++ code (e.g., #include "MyProject.h"). Youll
typically give the header file the same name as your project; but you can choose to name it anything you want and
save it to any folder you want.
Note #1: Even though the run-time engine refers to actions and predicates by number internally, it refers to them by
name when recording its activities to its Log file. It does this regardless of whether or not youve created a .H header
file, as it retrieves these names from your compiled project file.
Note #2: Behaviors and variables are referred to in the engine the same way they are in the editori.e., by name, not
number.
To create a header file providing symbolic names for your projects actions and predicates, follow these steps:
1.
Launch the SimBionic editor and open the project for which you want to create a header file.
Click the File menu, select Export, select Export Constants, and then select C++.
An Export C++ Header dialog box like this appears:
2.
3.
Click Save.
Your header file is saved in the folder and under the name you specified.
4.
Include the header file in your program via the C++ code for your simulation or game.
After the file is saved, you can examine it with any text editor. For example, the header file for the demonstration PacMan game (described in the Exploring the sample Pac-Man program topic) reads as follows:
**********
// PacMan.h : behavior editor generated constants
// SIM revision number
153
#define SIM_REV 8
// actions
#define PACMAN_ACTION_SendMsg 0
#define PACMAN_ACTION_NextMsg 1
#define PACMAN_ACTION_CreateBBoard 2
#define PACMAN_ACTION_PostBBoard 3
#define PACMAN_ACTION_DestroyBBoard 4
#define PACMAN_ACTION_JoinGroup 5
#define PACMAN_ACTION_QuitGroup 6
#define PACMAN_ACTION_DestroyGroup 7
#define PACMAN_ACTION_SetDirection 128
#define PACMAN_ACTION_FindDestination 129
#define PACMAN_ACTION_RankDirections 130
#define PACMAN_ACTION_FindPMFacing 131
#define PACMAN_ACTION_FindPMTrailing 132
#define PACMAN_ACTION_CalcShortestPath 133
#define PACMAN_ACTION_GetPathTurn 134
#define PACMAN_ACTION_PostDest 135
#define PACMAN_ACTION_DrawPath 136
// predicates
#define PACMAN_PRED_IsDone 0
#define PACMAN_PRED_IsMsg 1
#define PACMAN_PRED_GetMsgSender 2
#define PACMAN_PRED_GetMsgType 3
#define PACMAN_PRED_GetMsgData 4
#define PACMAN_PRED_ReadBBoard 5
#define PACMAN_PRED_IsBBoard 6
#define PACMAN_PRED_IsValid 7
#define PACMAN_PRED_NumMembers 8
#define PACMAN_PRED_Name 128
#define PACMAN_PRED_IsPlaying 129
#define PACMAN_PRED_IsGameOver 130
#define PACMAN_PRED_IsActive 131
#define PACMAN_PRED_IsFleeing 132
#define PACMAN_PRED_Direction 133
#define PACMAN_PRED_Location 134
#define PACMAN_PRED_Direction_PM 135
#define PACMAN_PRED_Location_PM 136
#define PACMAN_PRED_Random 138
#define PACMAN_PRED_X 139
#define PACMAN_PRED_Y 140
#define PACMAN_PRED_ABS 141
#define PACMAN_PRED_IsReverse 143
#define PACMAN_PRED_IsBlocked 137
#define PACMAN_PRED_Opposite 142
#define PACMAN_PRED_IsAtIntersection 144
#define PACMAN_PRED_SameLane 145
154
params[0].Integer()
params[0].Float()
params[0].String()
params[0].Boolean()
params[0].Entity()
params[0].Array()
params[0].Data()
params[0].Any()
Note: For more information about SimBionic data types, see the Choosing a data type topic.
To set the value of a parameter (for out or in/out parameters), use the following syntax:
params[0].SetInteger(your_integer_variable+1);
params[0].SetFloat (your_float_variable+1.25);
params[0].SetString("sample string");
params[0].SetVector(1,-2,4);
params[0].SetBoolean(true);
params[0].SetEntity(your_entity_variable);
params[0].SetArray(your_array_variable);
params[0].SetArray(your_table_variable);
params[0].SetData(your_data_variable);
Alternatively, for all variable types except string and array/table, you can set values using this more intuitive syntax:
params[0].Integer() = your_integer_variable+1;
params[0].Float() = your_float_variable+1.25;
params[0].Vector() = your_vector_variable;
params[0].Boolean() = true;
155
params[0].Data() = your_data_variable;
params[0].Entity() = your_entity_variable;
Tip: You can create an Invalid value to return from a predicate by calling SetType(kAI_Invalid) on the AI_Param
object.
Using the API
Using the C++ engine's API methods
SimBionic application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via your C++ code. These methods allow you to perform such fundamental tasks
as start up the engine, create entities, set the frequency and priority with which entities are updated, select behaviors,
set the values of global variables, retrieve error messages, insert comments to be recorded along with the engines
activities in a Log file, and shut down the engine.
The API methods for the C++ run-time engine are as follows:
Tip: If you lose track of an entitys ID number, you can retrieve it via the GetEntityID predicate. For more information,
see the GetEntityID topic.
To view sample code demonstrating how to use some of these API methods to start up the engine and run it through
its paces, see the next topic, Starting and controlling the C++ run-time engine.
Starting and controlling the C++ run-time engine
As explained in the Understanding the C++ run-time engine topic, you must perform a number of tasks before youre
ready to run your project via SimBionics run-time engine.
Once youve completed these chores, however, you can rev up the engine and put it through its paces by using code
similar to the following example:
**********
int main(int argc, char* argv[])
{
// create the action/predicate interface between the engine and the game
MyInterface* myInterface = new MyInterface();
// create the object that holds configuration parameters for the engine
AI_Config* myConfig = new AI_Config();
// specify the name of the SIM file to load
myConfig->behaviorFilename = "c:\\SimProjects\\MyProject.sim";
// creates an instance of the engine interface object
AI_Engine engine;
// initialize the engine
if (engine.Initialize(myInterface,myConfig) != kOK)
return -1;
156
// a integer parameter
// a vector parameter
id = engine.CreateEntity("MyEntity","SomeBehavior",parms,0,0);
engine.Update();
engine.Terminate();
}
**********
Note: You can also start up the engine with a mouse click via the SimBionic editor, but only for the purpose of
interactive debugging. For more information, see the Debugging your project topic.
Managing AP modules in the C++ run-time engine
When you initialize the SimBionic run-time engine, you must pass it a pointer to an AI_Interface object that implements
an AP module, typically one that defines the key actions and predicates for your game. If your project defines only a
single AP module (not counting the built-in Core AP module), then you need not read any further.
If, however, your project defines more than one AP module (again, not counting the built-in Core AP module), then you
will need to load those other AP modules so that their actions and predicates can be invoked by your behaviors. The
SimBionic run-time engine provides several API methods that allow you to do this.
Loading an AP module
Once the run-time engine is running in your application, you can direct it to load an AP module using the
LoadAPModule API method, which takes a pointer to the AI_Interface object that implements the AP modules actions
and predicates. The engine will load the AP module, and its contents can then be invoked just like actions and
predicates that were loaded on startup.
Note: You should be careful not to load an AP module again after you have already loaded it. This may cause
undesirable results. You can, however, reload an AP module after unloading it.
Unloading an AP module
When you no longer need the actions or predicates in a particular AP module, you can direct the run-time engine to
unload that AP module to free up memory. To do so, use the UnloadAPModule API method.
Shutting down the C++ run-time engine
When youre ready to shut down SimBionics run-time engine, insert the following line in your C++ code:
engine.Terminate();
Terminate is an API method that turns off the run-time engine and, if youre using the dynamic version of the engine,
unloads the SimBionic DLL.. You must use this API method last, because the engine wont be available for any other
methods after Terminate executeswith the exception of Initialize, which will start the engine up again.
157
For more information, see the Using the C++ engine's API methods and Starting and controlling the C++ run-time
engine topics.
Logging your project's execution in C++
In general, the best way to debug your SimBionic behaviors is via the interactive debugger, which provides a powerful
interface for stepping through your behaviors and monitoring the state of your entities as it changes. (See the
Debugging your project topic for more information on the interactive debugger.) Sometimes, however, it can also be
helpful while debugging to have a log of your programs execution, since it allows you to trace the flow of execution
backward to hunt down hard-to-find problems. The SimBionic run-time engine thus has a built-in logging capability. To
enable logging in the run-time engine, follow these steps:
1.
Make sure youre using the Development version of the run-time engine.
For maximum efficiency, logging is not included in the Production version of the engine.
2.
Specify the path and name for the log file by setting the AI_Config::logFilename variable.
The AI_Config object is passed to the Initialize API method when you start up the engine.
3.
Specify what aspects of the run-time engines execution you would like logged by setting the
AI_Config::logContent variable.
The SimBionic run-time engine can log a variety of information about its execution. You can control what information
gets written to the log using a set of content flags, defined in AI_Config.h. The following flags are available:
kLogDebugger: Logs information about the operation of the interactive debugger, including messages
exchanged with the editor.
kLogInit: Logs detailed information on the engines initialization and file loading process.
kLogMilestone: Logs status messages related to normal functioning of the system, mainly on initialization
and shutdown.
kLogTick: Logs basic information about the flow of execution on each clock tick.
You can specify multiple kinds of content to be logged by ORing the desired flags together. For example,
logContent = kLogAction | kLogPredicate | kLogBinding
would cause the engine to log only action and predicate invocations and variable bindings.
Note: Error messages are always logged if logging is enabled.
Memory management in the C++ engine
The SimBionic run-time engine is designed for efficient execution and a small memory footprint. The C++ version of
the engine also features its own custom memory-management system, which allows it to reduce the overhead of
allocating and deallocating memory. There are two components to the memory-management system:
Memory pools: Certain kinds of objects are so frequently used by the run-time engine that the engine
preallocates a pool of them at startup. Each time it needs an instance of one of these objects, it simply
requests one from the pool; if the pool is empty, it will be expanded with a newly-allocated block of objects.
When the engine no longer needs an instance, it releases it back to the pool for later reuse.
Tip: If you would like the size of the memory pools to be fixed at startup (disallowing any expansion), you
can recompile the run-time engine with the AI_MEMPOOL_FIXED symbol defined.
String table: The run-time engine refers to certain elements of your project (e.g., behaviors and descriptors)
by their text names. String operations e.g., copy, compare are computationally expensive, however, and
maintaining multiple copies of a string can waste a significant amount of memory. SimBionic thus maintains
a global string table that stores a single copy of each string used by the engine, and uses pointers to this
table instead of actual strings. This greatly reduces the cost of string comparison and copying operations.
You can control how much memory is preallocated for each type of memory pool used by the engine via the
memConfig variable in your AI_Config configuration object, which is passed to the engine by the Initialize API method.
This variable, a struct of type AI_MemConfig, has the following members related to memory pools:
158
initIntegerVPool: The number of integer variables to preallocate for the pool. Default: 50.
initFloatVPool: The number of float variables to preallocate for the pool. Default: 50.
initBooleanVPool: The number of Boolean variables to preallocate for the pool. Default: 50.
initStringVPool: The number of string variables to preallocate for the pool. Default: 50.
initDataVPool: The number of data variables to preallocate for the pool. Default: 50.
initEntityVPool: The number of entity variables to preallocate for the pool. Default: 50.
initVectorVPool: The number of vector variables to preallocate for the pool. Default: 50.
initArrayVPool: The number of array variables to preallocate for the pool. Default: 50.
initVarMapsPool: The number of variable maps to preallocate for the pool (directly proportional to
maximum number of behaviors that are active at once). Default: 50.
initFramePool: The number of execution frames to preallocate for the pool (also directly proportional to the
number of simultaneously active behaviors). Default: 50.
initEntityPool: The number of entities to preallocate for the pool. Default: 30.
initMsgPool: The number of communication messages to preallocate for the pool. Default: 50.
AI_MemConfig also has the following members related to the string table:
maxStrings: The maximum number of strings allowed in the string table. Default: 250.
maxStringBytes: The maximum number of bytes allocated for string data. Default: 4000.
stLoadFactor: The load factor for the string tables hashmap. Default: 3.
Tip: Use the default memory management settings during the development process. Once youre ready to fine-tune
your applications performance, use the memory usage statistics at the end of the engines log file to figure out the
optimal settings for each memory pool
The C++ API
CreateBBoard
CreateBBoard is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
CreateBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
CreateBBoard lets an entity create a virtual blackboard specified by a particular name. Any entity that "knows" the
boards name can then place information on the board (via the PostBBoard action) and/or read information from the
board (via the ReadBBoard predicate). The blackboard therefore makes it easy for any entity to share information with
any or all other entities in your program.
Theres no limit to the number of blackboards that can be created or to the amount of information that can be placed
on any blackboard. When a blackboard becomes obsolete, any entity can eliminate it (and free up the memory its
occupying) by using the DestroyBBoard action.
CreateBBoards single parameter is the blackboards name, which is a string:
For example, if you wanted an entity to create a blackboard named Target_Locations, youd insert this expression into
an action on the Canvas: CreateBBoard("Target_Locations").
For more information, see the Communicating via virtual blackboards topic.
CreateEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via your C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The CreateEntity API method creates an entity in the run-time engine and places it under SimBionics control. (Along
with each entity, the engine creates a behavior stack, message queue, and set of global variables devoted to the
activities of that entity.) This method then returns the unique ID number the engine assigns to your new entity and will
use exclusively to refer to that entity (as data type AI_Entity in C++ and long in Java).
CreateEntity is also a built-in predicate thats available in every SimBionic project. Its automatically declared in the
Catalog in the Core AP module in a folder named Entity, with corresponding code built into SimBionics run-time
engine.
CreateEntity has five parameters:
entityName: Name of the entity you want to create. This parameter is optional, since the engine uses ID
numbers exclusively to refer to entities. However, providing each entity with an appropriate name can make
your program output easier to read and debug. Data type: string [in].
159
behaviorID: Name of the behavior you want the entity to start out executing. The engine does not employ
ID numbers for behaviors, but instead refers to each behavior using the exact same nameincluding the
same upper- and lower-case spellingyou assigned to the behavior when declaring it in the Catalog (as
described in the Declaring a behavior topic). Data type: string [in].
params: Parameters to pass for the entitys initial behavior. The particular parameters will depend on the
behavior you selected. Data type for C++: AI_ParamVec [in]. Data type for Java: ArrayList of SB_Param
objects [in].
updateFreq: Sets the minimum frequency with which you want the entity updated, specified via an integer
from -1 through 100. The meaning of these values is described in detail in the topic Controlling the entity
scheduler. Data type: integer [in].
updatePriority: Sets the execution priority you want to assign the entity within any given clock tick,
specified via an integer from 0 on up through the highest integer allowed by your compiler. The meaning of
these values is described in detail in the topic Controlling the entity scheduler. Data type: integer [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
DestroyBBoard
DestroyBBoard is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
DestroyBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
DestroyBBoard eliminates a named virtual blackboard (created via the CreateBBoard action), freeing up the memory
taken up by the board and all the information stored on it. Any entity can use this action to remove obsolete
blackboards. Alternatively, an entity can just "erase" the information on a blackboard by first destroying the board and
then immediately using the CreateBBoard action to make a blank blackboard with the same name.
DestroyBBoards single parameter is the blackboards name, which is a string:
For example, if you wanted an entity to expunge a blackboard named Target_Locations, youd insert this expression
into an action on the Canvas: DestroyBBoard("Target_Locations").
For more information, see the Communicating via virtual blackboards topic.
DestroyEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via your C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The DestroyEntity method or action destroys the specified entity in the run-time engine, removing it from SimBionics
control. It also destroys the entitys stack, message queue, and global variables, thus freeing up all memory that was
devoted to the entity.
DestroyEntity is also an action thats available in every SimBionic project. Its automatically declared in the Catalog in
the Core AP module in the folder named Entity, with corresponding code built into SimBionics engine.
DestroyEntity has one parameter:
entityID: ID number of the entity you want to destroy. Data type for C++: AI_Entity [in]. Data type for Java:
long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
GetEntityGlobal
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The GetEntityGlobal method returns the value stored in a specified global variable of a specified entity. Alternatively,
returns a value of type kAI_Invalid if the specified global variable and/or entity doesnt exist.
GetEntityGlobal has two parameters:
entityID: ID number of the entity. Data type for C++: AI_Entity [in]. Data type for Java: long [in].
globalName: Name of the global variable holding the value you want to read. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
GetLastError
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
160
If the last method you used returns an error message (i.e., a non-kOK value), the GetLastError method returns a string
containing the explanatory message. Otherwise, GetLastError will return an empty string.
GetLastError has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
GetVersion
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The GetVersion method inspects the currently-loaded engine, and then tells you the engines version number, and
whether the engine is a release version (which executes faster) or a development version (which contains extra code
to enable interactive debugging, as described in the Debugging your project topic).
GetVersion has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Initialize
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Initialize method initializes the run-time engine and prepares it for operation (i.e., loads the engine into memory,
sets up the engines stack, etc.). If something goes wrong during initializatione.g., a missing file, insufficient
memorythis method returns an error code and saves an explanatory error message, which you can then retrieve via
the GetLastError method. Otherwise, it returns kOK, meaning no problems were encountered.
Note: You must use the Initialize method before using any other API method. If Initialize does not return kOK, you
should fix the problem and call Initialize again before invoking any other API methods.
Initialize has two parameters:
simInter: The custom simulation interface object. Data type for C++: pointer to AI_Interface object [in]. Data
type for Java: SB_Interface object [in].
config: Configuration parameters for SimBionic. Data type for C++: pointer to AI_Config object [in]. Data
type for Java: SB_Config object [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
IsEntityFinished
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The IsEntityFinished method returns true if the specified entity has reached the final action of its initial behavior i.e.,
if it has no behaviors remaining on its execution stack otherwise it returns false. For more information, see the topic
Understanding SimBionic's flow of execution.
IsEntityFinished has one parameter:
entityId: the unique ID of the entity whose status you wish to check. Data type for C++: AI_Entity [in]. Data
type for Java: long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
loadAPModule
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The LoadAPModule method loads an AP module and makes all actions and predicates in that AP module available for
invocation in the engine. For more information, see Managing AP modules in the C++ run-time engine and Managing
AP modules in the Java run-time engine.
LoadAPModule has one parameter:
simInterface: the interface object that implements the AP module. Data type for C++: AI_Interface* [in].
Data type for Java: SB_Interface [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
LoadPackage
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
161
The LoadPackage method loads a package file from an open input stream and makes all behaviors in that package
available for invocation in the engine. For more information, see the Dynamically loading and unloading behaviors
topic.
LoadPackage has two parameters:
packageStream: an open input stream that is ready to read from a package file. Data type for C++:
std::istream [in]. Data type for Java: InputStream [in].
packageName: the name of the package being loaded. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
LoadPackageFile
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The LoadPackageFile method loads the named package file and makes all behaviors in that package available for
invocation in the engine. For more information, see the Dynamically loading and unloading behaviors topic.
LoadPackageFile has one parameter:
packageFile: the name and location of the package file to load. Data type for C++: string [in]. Data type for
Java: URL [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Log
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Log method allows you to insert comments at select points of your program that will be written to the Log file
along with the engines activities. This method therefore allows you to make the Log file more readable, as well as
track at what point anything went wrong with your programs execution.
Note: You can control how much detail is entered into the Log file via the logContent parameter of the AI_Config (in
C++) or SB_Config (in Java) configuration object.
The Log method has one parameter of C++/Java data type string:
msg: Comment to be written to the Log file. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
MakeEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The MakeEntity method, like the CreateEntity method, creates an entity in the run-time engine and places it under
SimBionics control. (Note: Along with each entity, the engine creates a behavior stack, message queue, and set of
global variables devoted to the activities of that entity.)
MakeEntity doesnt specify the entitys initial behavior, however, so the SetBehavior method must be applied to the
entity before its first update. MakeEntity also doesnt set the entitys update frequency or priority, so if you want
anything other than the defaults for those settings applied to the entity, you must use the SetUpdateFreq and/or
SetUpdatePriority methods. MakeEntity returns the unique ID number the engine assigns to your new entity and will
use exclusively to refer to that entity (as data type AI_Entity in C++ or data type long in Java).
MakeEntity has one parameter of C++/Java data type string:
entityName: Name of the entity you want to create. This parameter is optional, since the engine uses ID
numbers exclusively to refer to entities. However, providing each entity with an appropriate name can make
your program output easier to read and debug. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
PostBBoard
PostBBoard is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
PostBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
PostBBoard lets an entity place information on any virtual blackboard (created previously via the CreateBBoard action)
by specifying the boards name, the section of the board that will house the information, and the data itself. Any entity
that "knows" both the name of the board and the section of it storing the pertinent information can then read that
162
information (via the ReadBBoard predicate). PostBBoard therefore allows any entity to provide information to any or all
other entities in your program.
PostBBoards three parameters are the blackboards name, which is a string; and then a key-value pair consisting of
the name of the section of the board that will store your particular piece of informationthe name also being a string
followed by the actual information, which can be any data type:
For example, if you wanted an entity to place information referred to by the variable Info on a blackboard named
Target_Locations in a section of the board named Enemy_Headquarters, youd insert this expression into an action on
the Canvas: PostBBoard("Target_Locations", "Enemy_Headquarters", Info).
A blackboard must existi.e., have been created via the CreateBBoard actionbefore an entity can post information
to it. However, if the section of the board where the information is being placedi.e., the keydoesnt already exist,
its created automatically with the name specified the first time an entity refers to it via the second parameter of the
PostBBoard action. Once an entity creates a named section of a blackboard, that section continues to exist for the life
of the board; and the information in each named section remains stored there until replaced with new data.
Theres no limit to the amount of information that can be placed on a blackboard. When a blackboard becomes
obsolete, any entity can eliminate it (and free up the memory its occupying) by using the DestroyBBoard action.
Alternatively, an entity can "erase" the information on a blackboard by first destroying the board and then immediately
using the CreateBBoard action to make a blank blackboard with the same name.
For more information, see the Communicating via virtual blackboards topic.
ReadBBoard
ReadBBoard is a predicate thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
ReadBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
ReadBBoard lets an entity access any virtual blackboard (created previously via the CreateBBoard action) and read
any information on the board (stored previously via the PostBBoard action) by specifying the boards name and the
section of the board that houses the information. ReadBBoard therefore allows any entity to get information from any
or all other entities in your program.
ReadBBoards two parameters are the desired blackboards name, which is a string; and the name of the section of
the boardor keythat holds the pertinent information, the latter name also being a string:
For example, if you wanted an entity to obtain information from a blackboard named Target_Locations and a section of
the board named Enemy_Headquarters, youd use this predicate: ReadBBoard("Target_Locations",
"Enemy_Headquarters"). ReadBBoard would then return whatever information was stored in the Enemy_Headquarters
section of the Target_Locations blackboard, in the form of data type any.
If an entity specifies the name of a blackboard and/or a section of the blackboard that doesnt actually exist,
ReadBBoard will return a value of Invalid. Its recommended that you always check for this possibility by using the
IsValid predicate directly after an entity uses ReadBBoard.
For more information, see the Communicating via virtual blackboards topic.
SendMsg
SendMsg is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the Core
AP module in a folder named Messages, with corresponding code built into SimBionics engine.
SendMsg is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
SendMsg lets any entity send a message directly to a group of entities by specifying the groups name (created
previously via the JoinGroup action), a number code that optionally provides some additional information about the
message, and the message itself.
The groups name is straightforward. The message is typically a text string, but can actually be of whatever data type
is best suited for the information to be sent.
As for the number code, SimBionic doesnt ascribe any meaning to it, so what number is attached to a particular
message and what that number represents is entirely up to you. For example, you might assign each message a
priority number from 1 to 5, with 1 meaning Urgent; read immediately! and 5 meaning Light news; read at your leisure.
Or you might assign each entity a unique number and then use the numbers to flag messages directed exclusively at a
particular entity. Or you might use number codes to indicate different ways a particular message should be interpreted
(e.g., 1 might mean Read as text string, 2 might mean Read as map coordinates, 3 might mean, Read as direction and
velocity changes, etc.). No matter what coding system you create, it should provide useful information.
When a message is sent to a group, every entity that belongs to the group will automatically receive the message in its
personal message queue, which will store the message until the entity is ready to access it. The entity can then check
who sent the message (via the GetMsgSender predicate), read the messages number code (via the GetMsgType
163
predicate), and/or read the message itself (via the GetMsgData predicate). When the entity is done with the message,
it can then remove it from the queue (via the NextMsg action), which allows the entity to access the next message
waiting for it.
An entity doesnt have to be a member of a group to send a message to that group; it simply needs to "know" the
name of the group. The advantage of belonging to a group is that an entity receives all messages sent to that group.
But if, say, a leader entity needs to send frequent messages to subordinate entities, it might opt to not join the
subordinates group so that its message queue doesnt become cluttered with its own messages. Further, the leader
might create another group consisting solely of itself, so that subordinates can send messages to the leader that only
the leader can read.
Theres no limit to the number of groups that can be created; the number of groups a particular entity can join; the
number of entities that can belong to a particular group; or the number of messages that can be sent to a particular
group.
SendMsgs three parameters are the groups name, which is of data type entity; the number code, which is of data
type integer; and the actual message, which can be any data type:
group: entity [in], number code: integer [in], msg: any [in]
For example, if you wanted an entity to send a message to a group named Superheroes, with a number code of 1, and
a text message saying Stop approaching meteor from striking Earth!!, youd insert this expression into an action on the
Canvas: SendMsg("Superheroes", 1, "Stop approaching meteor from striking Earth!!").
For more information, see the Communicating via group messages topic.
SetBehavior
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetBehavior method pops all execution frames currently on the specified entity's stack and then reinitializes the
entitys behavior via the specified parameters. However, SetBehavior leaves the entitys message queue and global
variables unchanged. Use this method in conjunction with the MakeEntity method or to change an entitys current
behavior.
SetBehavior is also an action thats available in every SimBionic project. Its automatically declared in the Catalog in
the Core AP module in the folder named Entity, with corresponding code built into SimBionics engine.
SetBehavior has three parameters:
entityID: ID number of the entity whose behavior you want to set. Data type for C++: AI_Entity [in]. Data
type for Java: long [in].
behaviorID: Name of the behavior you want the entity to start executing. The engine does not employ ID
numbers for behaviors, but instead refers to each behavior using the exact same nameincluding the same
upper- and lower-case spellingyou assigned to the behavior when declaring it in the Catalog (as described
in the Declaring a behavior topic). Data type: string [in].
params: Parameters to pass for the specified behavior. The particular parameters will depend on the
behavior you selected. Data type for C++: AI_ParamVec [in]. Data type for Java: ArrayList of SB_Param
objects [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SetEntityGlobal
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetEntityGlobal method sets the value of the specified global variable for the specified entity. For example, you
can use this method to assign the entity a different descriptor value, thus setting the entity to perform a different
polymorphic behavior (see the Creating polymorphisms topic).
SetEntityGlobal is also an action thats available in every SimBionic project. Its automatically declared in the Catalog
in the Core AP module in a folder named Entity, with corresponding code built into SimBionics engine.
SetEntityGlobal has three parameters:
entityID: ID number of the entity whose global variable you want to set. Data type for C++: AI_Entity [in].
Data type for Java: long [in].
varName: Name of the global variable you want to set. Data type: string [in].
value: Value you want to store in the specified global variable. Data type for C++: AI_Param [in]. Data type
for Java: SB_Param [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SetUpdateFreq
164
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetUpdateFreq method, just like the CreateEntity methods updateFreq parameter, sets the minimum frequency
with which you want an entity updated, specified via an integer from -1 through 100. Use this method in conjunction
with the MakeEntity method or to change an entitys current update frequency. See the Controlling the entity scheduler
topic for more information on the update frequency parameter.
SetUpdateFreq is also an action thats available in every SimBionic project. Its automatically declared in the Catalog
in the Core AP module in a folder named Entity, with corresponding code built into SimBionics engine.
SetUpdateFreq has two parameters:
newFreq: Update frequency you want applied to the specified entity (ranging from -1 through 100). Data
type: integer [in].
entityID: ID number of the entity whose update frequency you want to set. Data type for C++: AI_Entity [in].
Data type for Java: long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SetUpdatePriority
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetUpdatePriority method, just like the CreateEntity methods updatePriority parameter, sets the update priority
you want to assign an entity within any given clock tick, specified via an integer from 0 on up through the highest
integer allowed by your compiler. Use this method in conjunction with the MakeEntity method or to change an entitys
current update priority. See the Controlling the entity scheduler topic for more information on the update priority
parameter.
SetUpdatePriority is also an action thats available in every SimBionic project. Its automatically declared in the
Catalog in the Core AP module in a folder named Entity, with corresponding code built into SimBionics engine.
SetUpdatePriority has two parameters:
newPriority: Update priority you want applied to the specified entity (ranging from 0 on up). Data type:
integer [in].
entityID: ID number of the entity whose update priority you want to set. Data type for C++: AI_Entity [in].
Data type for Java: long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SwapProject
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SwapProject method enables you to unload the currently-loaded project from the run-time engine and load a
different project. Calling this method will also destroy all entities. While you could also accomplish this by shutting
down the engine and restarting it (via the Terminate and Initialize API methods), SwapProject is more efficient
because it doesnt have to destroy and recreate all of the engine infrastructure.
Note that the new project loaded by SwapProject must use the same actions and predicates (i.e., AI_Interface or
SB_Interface object) as the current project. It must also use the same configuration parameters.
SwapProject has one parameter:
behaviorFile: path and filename of the compiled project file that you wish to load. Data type for C++: string
[in]. Data type for Java: URL [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Terminate
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Terminate method shuts down the run-time engine and, if youre using the dynamic C++ version of the engine,
unloads the SimBionic DLL. You must use this method last, because the engine wont be available for any other
methods after Terminate executeswith the exception of Initialize, which will start the engine up again.
Terminate has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
UnloadAll
165
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UnloadAll method unloads all currently-loaded behaviors from the run-time engine and destroys all existing
entities. For more information, see the Dynamically loading and unloading behaviors topic.
UnloadAll has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
unloadAPModule
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UnloadAPModule method unloads the named AP module from the run-time engine, removing all actions and
predicates in that AP module from memory and making them unavailable for invocation. For more information, see
Managing AP modules in the C++ run-time engine and Managing AP modules in the Java run-time engine.
UnloadAPModule has one parameter:
moduleName: the name of the AP module to unload. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
UnloadPackage
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UnloadPackage method unloads the named package from the run-time engine, removing all behaviors in that
package from memory and making them unavailable for invocation. For more information, see the Dynamically loading
and unloading behaviors topic.
UnloadPackage has one parameter:
packageFile: the name of the package file to unload (including the .BIM extension). Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Update
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Update method advances the run-time engines clock by one tick, updating entities as dictated by the engines
entity scheduler. To learn more, see the Controlling the entity scheduler and Understanding SimBionic's flow of
execution topics.
Update has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
UpdateEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UpdateEntity method updates the specified entity, entirely bypassing the engines scheduler. Use this command
only for special circumstances in which an entity requires updating outside of the engines normal scheduling and
resource balancing. To learn more, see the Understanding SimBionic's flow of execution topic.
UpdateEntity has one parameter:
entityID: ID number of the entity you want to update. Data type for C++: AI_Entity [in]. Data type for Java:
long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
166
Impressive speed, helped by a load-balancing scheduling system for controlling large numbers of entities
without sapping the CPU.
Powerful API methods that let you precisely control when each entity is created, how often it executes,
which behaviors it executes, and how extensively its activities are recorded.
A thin API for easy integration with virtually any simulation or game.
Direct support for Java. (SimBionic also includes a C++ run-time engine that makes it easy to work with
simulations or games written in C++; to learn more, see the Understanding the C++ run-time engine topic.)
The Java run-time engine is distributed in a jar file. There are actually two versions of the .jar file included in
SimBionic:
A development version (simbionic-dev.jar) that contains extra code to enable interactive debugging and
logging (as described in the Debugging your project and Logging your project's execution topics).
Both of these .jar files are stored in a folder that identifies which version of the engine it contains. In addition, you can
differentiate the files by their sizes (e.g., the development versions are larger than the release versions).
There are several classes within the .jar file that you can use to quickly get your SimBionic project up and running. All
of these classes are in the com.stottlerhenke.JSimBionic.Interface package:
SB_Config: Defines configuration settings for the engine e.g., the URL of your compiled project file (see
the "Starting the run-time engine" topic); whether the interactive debugging feature is enabled or disabled;
etc. See the javadoc comments or the example at the end of this chapter for more details.
SB_Engine: The wrapper class that provides the API for the run-time engine.
SB_Interface: The abstract base class that you will subclass in order to implement your actions and
predicates.
SB_Param: Defines the parameters for actions; the parameters and return values for predicates; important
constants; and methods for setting and inspecting a value.
For more information about using the Java run-time engine, see the following topics:
To configure your Java project settings and development environment for SimBionic, see the Setting up your
Java project topic.
To create the underlying Java code for the custom actions and predicates in your project, see the
Implementing your application interface in Java topic.
To generate skeleton code for your custom actions and predicates, see the Generating skeleton code for
Java topic.
To access and/or set the parameter values of your custom actions and predicates via Java code, see the
Accessing and setting parameter values in Java topic.
To generate symbolic names for all the actions and predicates in your project, see the Creating Java
symbolic names for actions & predicates topic.
To exploit the Java run-time engines API methods, see the Using the Java engine's API methods topic.
To view sample code for starting up the engine, see the Starting and controlling the Java run-time engine
topic.
To terminate the engine, see the Shutting down the Java run-time engine topic.
Add the SimBionic run-time engine JAR file to the list of jar files in your projects settings.
There are two versions of the Java engine available, a Development build that includes logging and
interactive debugging capabilities, and a Production build that is optimized for maximum speed. Make sure
you choose the appropriate one for your application.
167
2.
If your project uses only the two default AP modules (Core and Project):
a.
Disable AP modules by going to the Build menu, selecting the Project Settings option, and unchecking
the "Enable AP modules" box. This will tell the SimBionic run-time engine to look in the compiled
project file for information about your projects actions and predicates.
b.
Create a subclass of the SimBionic class SB_Interface. (See "Subclassing SB_Interface" below.) This
class will contain the implementation for all of your actions and predicates.
c.
Implement the doAction and doPredicate methods of your subclass. These are the methods called by
the run-time engine when it invokes an action or predicate. (See Coding actions in Java and Coding
predicates in Java.)
Enable AP modules by going to the Build menu, selecting the Project Settings option, and checking the
"Enable AP modules" box. This will tell the SimBionic run-time engine to look to the AP modules
themselves (rather than the compiled project file) for information about your projects actions and
predicates.
b.
Create a subclass of the SimBionic class SB_Interface for each AP module in your project (aside from
the built-in Core AP module). (See "Subclassing SB_Interface" below.) Each subclass will contain the
implementation for the actions and predicates in a single AP module. Remember that if you have
imported an existing AP module into your project, you can simply reuse the existing subclass for that
AP module.
c.
Implement the doAction and doPredicate methods of each subclass. These are the methods called by
the run-time engine when it invokes an action or predicate. (See Coding actions in Java and Coding
predicates in Java.)
d.
Subclassing SB_Interface
To create a subclass of SB_Interface, first import the SB_Interface class itself:
import com.stottlerhenke.simbionic.api.SB_Interface
Next, define a new class that takes SB_Interface as its parent class:
public class MyInterface extends SB_Interface
{
};
SB_Interface is an abstract base class that defines a number of methods. Two of these methods, doAction and
doPredicate, are abstract methods and must be overridden.
Coding predicates in Java
Each time the run-time engine invokes a predicate, it calls the doPredicate method of the SB_Interface subclass that
implements that predicate. This method takes three arguments: the procedure identifier for the predicate to be
enacted, the unique identifier for the entity performing the predicate, and an ordered, typed list of parameters for the
predicate.
The body of the doPredicate method carries out the operations appropriate for the given procedure identifier, often
(but not necessarily) involving manipulation or assessment of simulation state. A switch statement is commonly used
to select the proper code path based on the procedure identifier. One convenient way to organize your code is to
create an auxiliary method for each action that's called by the associated case statement.
168
To illustrate, the boldfaced portion of the code below is an example of how to code a customized predicate named
IsGreaterThan thats coded in Java. This predicate receives two numbers, evaluates whether the first number is
greater than the second number, and then returns a Boolean value of true or false:
***************
import java.util.ArrayList;
import com.stottlerhenke.simbionic.api.*;
public class MyInterface extends SB_Interface
{
public MyInterface()
{
}
/**
* Defines the implementation for all actions
*
*/
public void doAction(int actionId, long entityId, ArrayList params)
{
}
/**
* Implements all predicates
*
*/
public SB_Param doPredicate(int predId, long entityId, ArrayList params)
{
SB_Param retValue = new SB_Param();
switch (predId)
{
case MyProject.PRED_IsGreaterThan:
{
boolean result = ( ((SB_Param)params.get(0)).getFloat() >
((SB_Param)params.get(1)).getFloat() );
retValue.setBoolean(true);
}
break;
}
return retValue;
}
}
***************
The constant MyProject.PRED_Say in the example above represents the unique procedure identifier for that
predicate. These constants are defined in a class generated by the SimBionic editor. For more information, see the
topic Creating Java symbolic names for actions & predicates.
169
The SimBionic editor can help you with the task of coding your predicates by automatically generating skeleton code
for your custom SB_Interface subclass. For more information on how to do this, see the Generating skeleton code for
Java topic.
For the syntax you must use to access and/or set parameter values, see the Accessing and setting parameter values
in Java topic.
In addition to predicates, you must create underlying Java code for your projects actions. To learn how, see the
Coding actions in Java topic.
Coding actions in Java
Each time the run-time engine invokes an action, it calls the doAction method of the SB_Interface subclass that
implements that action. This method takes three arguments: the procedure identifier for the action to be enacted; the
unique identifier for the entity performing the action; and an ordered, typed list of parameters for the action.
The body of the doAction method carries out the operations appropriate for the given procedure identifier, often (but
not necessarily) involving manipulation or assessment of simulation state. A switch statement is commonly used to
select the proper code path based on the procedure identifier. One convenient way to organize your code is to create
an auxiliary method for each action that's called by the associated case statement.
To illustrate, the boldfaced portion of the code below is an example of how to code a customized action named Say in
Java. This action accepts a text string and then displays a sentence onscreen that incorporates the string:
***************
import java.util.ArrayList;
import com.stottlerhenke.simbionic.api.*;
public class MyInterface extends SB_Interface
{
public MyInterface()
{
}
/**
* Defines the implementation for all actions
*
*/
public void doAction(int actionId, long entityId, ArrayList params)
{
switch (actionId)
{
case MyProject.ACTION_Say:
System.out.println( ((SB_Param)params.get(0)).getString() );
break;
}
}
/**
* Implements all predicates
*
*/
public SB_Param doPredicate(int predId, long entityId, ArrayList params)
{
return new SB_Param();
}
}
170
***************
The constant MyProject.ACTION_Say in the example above represents the unique procedure identifier for that action.
These constants are defined in a class generated by the SimBionic editor. For more information, see the topic
Creating Java symbolic names for actions & predicates.
The SimBionic editor can help you with the task of coding your actions by automatically generating skeleton code for
your custom SB_Interface subclass. For more information on how to do this, see the Generating skeleton code for
Java topic.
For the syntax you must use to access and/or set parameter values, see the Accessing and setting parameter values
in Java topic.
In addition to actions, you must create underlying Java code for your projects predicates. To learn how, see the
Coding predicates in Java topic.
Generating skeleton code for Java
To integrate your Java application with the SimBionic run-time engine, you must first subclass the SB_Interface class
provided with SimBionic and write code for each of the actions and predicates in your project. While this is typically not
a difficult process, it can be time-consuming if you have defined many actions and predicates. SimBionic thus provides
the capability to automatically generate skeleton code for these subclasses. Of course, you will still have to implement
the functionality of each action and predicate, but starting with the auto-generated skeleton code can save you a
considerable amount of time.
To use this feature, follow these steps:
1.
Select the File menu, then select Export, then select Export Skeleton Code.
An Export Skeleton Code dialog box will appear:
2.
Select the actions and predicates for which you would like SimBionic to generate skeleton code by
clicking on the checkboxes next to each one.
If you wish to generate code for all actions or all predicates, simply click the checkbox next to Actions or
Predicates.
171
3.
4.
If you wish to export Java definitions for the constants in your project, make sure that the Export
user-defined constants box is checked.
This option is checked by default. If selected, SimBionic will define a public static final member variable for
each of your constants of type float, integer, Boolean, or string. Each exported constant will have a name of
the form myconstantname, as in this example:
public static final int RADARRANGE = 330;
5.
If you wish to export your constant definitions to a separate header file, make sure that the Export
constant definitions to separate file box is checked.
If you select this option, SimBionic will create a separate Java class for the constant definitions described in
Step 4. This file will have the same name as your main skeleton code file, plus the extension "_constants".
This option is checked by default.
6.
If you wish to generate skeleton code for all user-defined classes in the project, make sure that the
Export user-defined classes box is checked.
If you select this option, SimBionic will create a separate Java class for each user-defined class in the
project. This is useful if you do not already have Java implementations for your user-defined classes.
7.
If you wish to view the exported code after it is generated, make sure that the Open files after export
box is checked.
If you select this option, SimBionic will open the exported file(s) in Notepad. This option is checked by
default.
8.
9.
172
1.
Select the File menu, then select Export, then select Export Skeleton Code.
2.
Select only the new actions and predicates by clicking on the checkboxes next to each one.
3.
4.
Make sure that the Open files after export box is checked.
5.
6.
7.
Click Save.
SimBionic will generate the specified skeleton code files, opening them in Notepad for you to view.
8.
Cut and paste the relevant code snippets for each action and predicate.
Make sure to copy:
173
FindDestination((SB_Param)params.get(0), (SB_Param)params.get(1),
break;
case ACTION_FindPMFacing:
FindPMFacing((SB_Param)params.get(0), (SB_Param)params.get(1),
(SB_Param)params.get(2), (SB_Param)params.get(3));
break;
case ACTION_FindPMTrailing:
FindPMTrailing((SB_Param)params.get(0), (SB_Param)params.get(1),
(SB_Param)params.get(2), (SB_Param)params.get(3));
break;
case ACTION_GetPathTurn:
GetPathTurn((SB_Param)params.get(0), (SB_Param)params.get(1));
break;
case ACTION_PostDest:
PostDest((SB_Param)params.get(0), (SB_Param)params.get(1));
break;
case ACTION_RankDirections:
RankDirections((SB_Param)params.get(0), (SB_Param)params.get(1),
(SB_Param)params.get(2), (SB_Param)params.get(3), (SB_Param)params.get(4));
break;
174
case ACTION_SetDirection:
SetDirection((SB_Param)params.get(0));
break;
default:
// unknown action
break;
}
}
public SB_Param doPredicate(int predId, long entityId, ArrayList params)
{
switch (predId)
{
case PRED_ABS:
return ABS((SB_Param)params.get(0));
case PRED_AdjacentToPM:
return AdjacentToPM((SB_Param)params.get(0));
case PRED_Direction:
return Direction();
case PRED_Direction_PM:
return Direction_PM();
case PRED_IsActive:
return IsActive();
case PRED_IsAtIntersection:
return IsAtIntersection();
case PRED_IsBlocked:
return IsBlocked((SB_Param)params.get(0), (SB_Param)params.get(1));
case PRED_IsFleeing:
return IsFleeing();
case PRED_IsGameOver:
return IsGameOver();
case PRED_IsPlaying:
return IsPlaying();
case PRED_IsPMOnNewLane:
return IsPMOnNewLane();
case PRED_IsReverse:
return IsReverse((SB_Param)params.get(0));
case PRED_Location:
return Location();
case PRED_Location_PM:
return Location_PM();
case PRED_Name:
return Name();
case PRED_Opposite:
return Opposite((SB_Param)params.get(0));
case PRED_Random:
return Random();
case PRED_SameLane:
return SameLane((SB_Param)params.get(0), (SB_Param)params.get(1));
175
case PRED_SameLoc:
return SameLoc((SB_Param)params.get(0), (SB_Param)params.get(1));
case PRED_X:
return X((SB_Param)params.get(0));
case PRED_Y:
return Y((SB_Param)params.get(0));
default:
// unknown predicate
return new SB_Param();
}
}
// ---- Action Implementations
/**
* Calculate the shortest geometric path from current thing to the
* given target in the maze. If allowreverse is true, this path
* should include an initial "about-face" turn if that will result
* in a shorter path. Otherwise, it should not consider an
* about-face path to be a candidate. Use predicate
* NextIntersection to extract intersections along
* @param target : vector [in]
* @param allowreverse : boolean [in]
* @param path : string [out]
* @param pathlength : integer [out]
*/
void CalcShortestPath(SB_Param target, SB_Param allowreverse, SB_Param path, SB_Param pathlength)
{
// your CalcShortestPath implementation here
}
/**
* Draw path from current thing to
* @param path : string [in]
*/
void DrawPath(SB_Param path)
{
// your DrawPath implementation here
}
/**
* Compute destination for given location and direction in
* @param location : vector [in]
* @param direction : string [in]
* @param destination : vector [out]
*/
void FindDestination(SB_Param location, SB_Param direction, SB_Param destination)
{
// your FindDestination implementation here
176
}
/**
* Look at pacman's location and direction, and find all the facing
* intersections, one step removed. The count indicates how many
* destinations
* @param dest1 : vector [out]
* @param dest2 : vector [out]
* @param dest3 : vector [out]
* @param count : integer [out]
*/
void FindPMFacing(SB_Param dest1, SB_Param dest2, SB_Param dest3, SB_Param count)
{
// your FindPMFacing implementation here
}
/**
* Look at pacman's location and direction, and find all the
* trailing intersections, one step removed. The count indicates
* how many destinations
* @param dest1 : vector [out]
* @param dest2 : vector [out]
* @param dest3 : vector [out]
* @param count : integer [out]
*/
void FindPMTrailing(SB_Param dest1, SB_Param dest2, SB_Param dest3, SB_Param count)
{
// your FindPMTrailing implementation here
}
/**
* Pops next direction along shortest path computed by the action
* CalcShortestPath.
* @param path : string [in/out]
* @param turn : string [out]
*/
void GetPathTurn(SB_Param path, SB_Param turn)
{
// your GetPathTurn implementation here
}
/**
* TEMPORARY
* @param name : string [in]
* @param dest : vector [in]
*/
void PostDest(SB_Param name, SB_Param dest)
{
// your PostDest implementation here
177
}
/**
* Ranks all four directions for current thing moving toward the
* given
* @param target : vector [in]
* @param direction1 : string [out]
* @param direction2 : string [out]
* @param direction3 : string [out]
* @param direction4 : string [out]
*/
void RankDirections(SB_Param target, SB_Param direction1, SB_Param direction2, SB_Param direction3,
SB_Param direction4)
{
// your RankDirections implementation here
}
/**
* Request next direction of current thing. Specify 'left',
* 'right', 'up', 'down', or
* @param direction : string [in]
*/
void SetDirection(SB_Param direction)
{
// your SetDirection implementation here
}
// ---- Predicate Implementations
/**
* Returns absolute value of the given
* @param number : float [in]
* @return float
*/
SB_Param ABS(SB_Param number)
{
// your ABS implementation here
return new SB_Param();
}
/**
* Return true if current thing is "adjacent" to
* @param allowreverse : boolean [in]
* @return boolean
*/
SB_Param AdjacentToPM(SB_Param allowreverse)
{
// your AdjacentToPM implementation here
return new SB_Param();
178
}
/**
* Returns direction of current
* @return string
*/
SB_Param Direction()
{
// your Direction implementation here
return new SB_Param();
}
/**
* Returns direction of
* @return string
*/
SB_Param Direction_PM()
{
// your Direction_PM implementation here
return new SB_Param();
}
/**
* Checks if current thing is active, i.e. outside of hideout and
* has not been
* @return boolean
*/
SB_Param IsActive()
{
// your IsActive implementation here
return new SB_Param();
}
/**
* Returns true if current entity is at an
* @return boolean
*/
SB_Param IsAtIntersection()
{
// your IsAtIntersection implementation here
return new SB_Param();
}
/**
* Checks if given direction is blocked at given location in
* @param direction : string [in]
* @param location : vector [in]
* @return boolean
*/
179
180
* recent
* @param direction : string [in]
* @return boolean
*/
SB_Param IsReverse(SB_Param direction)
{
// your IsReverse implementation here
return new SB_Param();
}
/**
* Returns location of current
* @return vector
*/
SB_Param Location()
{
// your Location implementation here
return new SB_Param();
}
/**
* Returns location of
* @return vector
*/
SB_Param Location_PM()
{
// your Location_PM implementation here
return new SB_Param();
}
/**
* Returns name of current
* @return string
*/
SB_Param Name()
{
// your Name implementation here
return new SB_Param();
}
/**
* Returns opposite of given
* @param direction : string [in]
* @return string
*/
SB_Param Opposite(SB_Param direction)
{
// your Opposite implementation here
return new SB_Param();
181
}
/**
* Returns a random floating point number between 0 and
* @return float
*/
SB_Param Random()
{
// your Random implementation here
return new SB_Param();
}
/**
* Returns true if the two locations are on the same lane,
* including end
* @param loc1 : vector [in]
* @param loc2 : vector [in]
* @return boolean
*/
SB_Param SameLane(SB_Param loc1, SB_Param loc2)
{
// your SameLane implementation here
return new SB_Param();
}
/**
* Returns true if loc1 and loc2 describe the same
* @param loc1 : vector [in]
* @param loc2 : vector [in]
* @return boolean
*/
SB_Param SameLoc(SB_Param loc1, SB_Param loc2)
{
// your SameLoc implementation here
return new SB_Param();
}
/**
* Returns x coordinate of given
* @param location : vector [in]
* @return float
*/
SB_Param X(SB_Param location)
{
// your X implementation here
return new SB_Param();
}
/**
182
Launch the SimBionic editor and open the project for which you want to create the Java constants
file.
Click the File menu. select Export, select Export Constants, and then select Java.
An Export Java Class dialog box like this appears:
2.
3.
Click Save.
Your Java file is saved in the folder and under the name you specified.
4.
Import the Java file in the Java code for your simulation or game.
After the file is saved, you can examine it with any text editor. For example, the Java constants file for the
demonstration Pac-Man game (described in the Exploring the sample Pac-Man program topic) would read as follows if
the program had been written in Java:
183
**********
// PacMan.java : behavior editor generated constants
public class PacMan
{
// sim revision number
public static final int SIM_REV = 15;
// actions
public static final int ACTION_SendMsg = 0;
public static final int ACTION_NextMsg = 1;
public static final int ACTION_CreateBBoard = 2;
public static final int ACTION_PostBBoard = 3;
public static final int ACTION_DestroyBBoard = 4;
public static final int ACTION_JoinGroup = 5;
public static final int ACTION_QuitGroup = 6;
public static final int ACTION_DestroyGroup = 7;
public static final int ACTION_SetDirection = 128;
public static final int ACTION_FindDestination = 129;
public static final int ACTION_RankDirections = 130;
public static final int ACTION_FindPMFacing = 131;
public static final int ACTION_FindPMTrailing = 132;
public static final int ACTION_CalcShortestPath = 133;
public static final int ACTION_GetPathTurn = 134;
public static final int ACTION_PostDest = 135;
public static final int ACTION_DrawPath = 136;
// predicates
public static final int PRED_IsDone = 0;
public static final int PRED_IsMsg = 1;
public static final int PRED_GetMsgSender = 2;
public static final int PRED_GetMsgType = 3;
public static final int PRED_GetMsgData = 4;
public static final int PRED_ReadBBoard = 5;
public static final int PRED_IsBBoard = 6;
public static final int PRED_IsValid = 7;
public static final int PRED_NumMembers = 8;
public static final int PRED_Name = 128;
public static final int PRED_IsPlaying = 129;
public static final int PRED_IsGameOver = 130;
public static final int PRED_IsActive = 131;
public static final int PRED_IsFleeing = 132;
public static final int PRED_Direction = 133;
public static final int PRED_Location = 134;
public static final int PRED_Direction_PM = 135;
public static final int PRED_Location_PM = 136;
public static final int PRED_Random = 138;
public static final int PRED_X = 139;
184
((SB_Param) params.get(0)).getInteger()
((SB_Param) params.get(0)).getString()
((SB_Param) params.get(0)).getVector()
((SB_Param) params.get(0)).getBoolean()
((SB_Param) params.get(0)).getEntity()
((SB_Param) params.get(0)).getData()
((SB_Param) params.get(0)).getArray()
Note: For more information about SimBionic data types, see the Choosing a data type topic.
To set the value of a parameter (for out or in/out parameters), use the following syntax:
((SB_Param) params.get(0)).setInteger(your_integer_variable+1);
((SB_Param) params.get(0)).setVector(your_vector_variable+(1,-2,4));
((SB_Param) params.get(0)).setBoolean(true);
((SB_Param) params.get(0)).setEntity(your_entity_variable);
((SB_Param) params.get(0)).setData(your_data_variable);
((SB_Param) params.get(0)).setArray(your_array_variable);
185
Tip: You can create an Invalid value to return from a predicate by calling setType(SB_ParamType.kSB_Invalid) on the
SB_Param object.
Using the API
Using the Java engine's API methods
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via your Java code. These methods allow you to perform such fundamental
tasks as start up the engine, create entities, set the frequency and priority with which entities are updated, select
behaviors, set the values of global variables, retrieve error messages, insert comments to be recorded along with the
engines activities in a log file, and shut down the engine.
The API methods for the Java run-time engine are as follows:
Tip: If you lose track of an entitys ID number, you can retrieve it via the GetEntityID predicate. For more information,
see the GetEntityID topic.
To view sample code demonstrating how to use some of these API methods to start up the engine and run it through
its paces, see the next topic, Starting and controlling the Java run-time engine.
Starting and controlling the Java run-time engine
As explained in the Understanding the Java run-time engine topic, you must perform a number of tasks before youre
ready to run your project via SimBionics run-time engine.
Once youve completed these chores, however, you can rev up the engine and put it through its paces by using code
similar to the following example:
**********
void startEngine()
{
// create the action/predicate interface between the engine and the game
MyInterface myInterface = new MyInterface();
// create the object that holds configuration parameters for the engine
SB_Config myConfig = new SB_Config();
//Turn off the debugger
myConfig.debugEnabled = false;
try
{
myConfig.fileURL = = new URL("file", "localhost", "c:\\SimProjects\\MyProject.sim");
}
catch(Exception e)
{
System.out.println("Exception creating URL from the sim file name.");
}
186
// a integer parameter
// a string parameter
// a vector parameter
id = engine.createEntity("MyEntity","SomeBehavior",parms,0,0);
engine.update();
engine.terminate();
}
**********
Note: You can also start up the engine with a mouse click via the SimBionic editor, but only for the purpose of
interactive debugging. For more information, see the Debugging your project topic.
Managing AP modules in the Java run-time engine
When you initialize the SimBionic run-time engine, you must pass it a pointer to an SB_Interface object that
implements an AP module, typically one that defines the key actions and predicates for your game. If your project
defines only a single AP module (not counting the built-in Core AP module), then you need not read any further.
187
If, however, your project defines more than one AP module (again, not counting the built-in Core AP module), then you
will need to load those other AP modules so that their actions and predicates can be invoked by your behaviors. The
SimBionic run-time engine provides several API methods that allow you to do this.
Loading an AP module
Once the run-time engine is running in your application, you can direct it to load an AP module using the
loadAPModule API method, which takes a pointer to the SB_Interface object that implements the AP modules actions
and predicates. The engine will load the AP module, and its contents can then be invoked just like actions and
predicates that were loaded on startup.
Note: You should be careful not to load an AP module again after you have already loaded it. This may cause
undesirable results. You can, however, reload an AP module after unloading it.
Unloading an AP module
When you no longer need the actions or predicates in a particular AP module, you can direct the run-time engine to
unload that AP module to free up memory. To do so, use the unloadAPModule API method.
Shutting down the Java run-time engine
When youre ready to shut down SimBionics run-time engine, insert the following line in your Java code:
engine.Terminate();
Terminate is an API method that turns off the run-time engine. You must use this API method last, because the engine
wont be available for any other methods after Terminate executeswith the exception of Initialize, which will start the
engine up again.
For more information, see the Using the Java engine's API methods and Starting and controlling the Java run-time
engine topics.
Logging your project's execution in Java
In general, the best way to debug your SimBionic behaviors is via the interactive debugger, which provides a powerful
interface for stepping through your behaviors and monitoring the state of your entities as it changes. (See the
Debugging your project topic for more information on the interactive debugger.) Sometimes, however, it can also be
helpful while debugging to have a log of your programs execution, since it allows you to trace the flow of execution
backward to hunt down hard-to-find problems. The SimBionic run-time engine thus has a built-in logging capability. To
enable logging in the run-time engine, follow these steps:
1.
Make sure youre using the Development version of the run-time engine, JSimBionicD.jar.
For maximum efficiency, logging is not included in the Production version of the engine.
2.
3.
188
Configure the run-time engine to use your log stream by calling SB_Engine.registerLogPrintStream.
The registerLogPrintStream API method enables logging in the engine using the stream you supply. Note
that you can register more than one log stream, in which case the engine will write the log information to all
of them.
The SimBionic run-time engine can log a variety of information about its execution. By default, all
information is logged, but you can control what information gets written to the log using a set of content
flags, defined in SB_Logger. The following flags are available:
DEBUGGER: Logs information about the operation of the interactive debugger, including messages
exchanged with the editor.
INIT: Logs detailed information on the engines initialization and file loading process.
MILESTONE: Logs status messages related to normal functioning of the system, mainly on
initialization and shutdown.
TICK: Logs basic information about the flow of execution on each clock tick.
You can specify multiple kinds of content to be logged by ORing the desired flags together. For example,
logContent = kLogAction | kLogPredicate | kLogBinding
would cause the engine to log only action and predicate invocations and variable bindings.
Note: Error messages are always logged if logging is enabled.
The Java API
CreateBBoard
CreateBBoard is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
CreateBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
CreateBBoard lets an entity create a virtual blackboard specified by a particular name. Any entity that "knows" the
boards name can then place information on the board (via the PostBBoard action) and/or read information from the
board (via the ReadBBoard predicate). The blackboard therefore makes it easy for any entity to share information with
any or all other entities in your program.
Theres no limit to the number of blackboards that can be created or to the amount of information that can be placed
on any blackboard. When a blackboard becomes obsolete, any entity can eliminate it (and free up the memory its
occupying) by using the DestroyBBoard action.
CreateBBoards single parameter is the blackboards name, which is a string:
For example, if you wanted an entity to create a blackboard named Target_Locations, youd insert this expression into
an action on the Canvas: CreateBBoard("Target_Locations").
For more information, see the Communicating via virtual blackboards topic.
CreateEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via your C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The CreateEntity API method creates an entity in the run-time engine and places it under SimBionics control. (Along
with each entity, the engine creates a behavior stack, message queue, and set of global variables devoted to the
activities of that entity.) This method then returns the unique ID number the engine assigns to your new entity and will
use exclusively to refer to that entity (as data type AI_Entity in C++ and long in Java).
CreateEntity is also a built-in predicate thats available in every SimBionic project. Its automatically declared in the
Catalog in the Core AP module in a folder named Entity, with corresponding code built into SimBionics run-time
engine.
189
entityName: Name of the entity you want to create. This parameter is optional, since the engine uses ID
numbers exclusively to refer to entities. However, providing each entity with an appropriate name can make
your program output easier to read and debug. Data type: string [in].
behaviorID: Name of the behavior you want the entity to start out executing. The engine does not employ
ID numbers for behaviors, but instead refers to each behavior using the exact same nameincluding the
same upper- and lower-case spellingyou assigned to the behavior when declaring it in the Catalog (as
described in the Declaring a behavior topic). Data type: string [in].
params: Parameters to pass for the entitys initial behavior. The particular parameters will depend on the
behavior you selected. Data type for C++: AI_ParamVec [in]. Data type for Java: ArrayList of SB_Param
objects [in].
updateFreq: Sets the minimum frequency with which you want the entity updated, specified via an integer
from -1 through 100. The meaning of these values is described in detail in the topic Controlling the entity
scheduler. Data type: integer [in].
updatePriority: Sets the execution priority you want to assign the entity within any given clock tick,
specified via an integer from 0 on up through the highest integer allowed by your compiler. The meaning of
these values is described in detail in the topic Controlling the entity scheduler. Data type: integer [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
DestroyBBoard
DestroyBBoard is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
DestroyBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
DestroyBBoard eliminates a named virtual blackboard (created via the CreateBBoard action), freeing up the memory
taken up by the board and all the information stored on it. Any entity can use this action to remove obsolete
blackboards. Alternatively, an entity can just "erase" the information on a blackboard by first destroying the board and
then immediately using the CreateBBoard action to make a blank blackboard with the same name.
DestroyBBoards single parameter is the blackboards name, which is a string:
For example, if you wanted an entity to expunge a blackboard named Target_Locations, youd insert this expression
into an action on the Canvas: DestroyBBoard("Target_Locations").
For more information, see the Communicating via virtual blackboards topic.
DestroyEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via your C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The DestroyEntity method or action destroys the specified entity in the run-time engine, removing it from SimBionics
control. It also destroys the entitys stack, message queue, and global variables, thus freeing up all memory that was
devoted to the entity.
DestroyEntity is also an action thats available in every SimBionic project. Its automatically declared in the Catalog in
the Core AP module in the folder named Entity, with corresponding code built into SimBionics engine.
DestroyEntity has one parameter:
entityID: ID number of the entity you want to destroy. Data type for C++: AI_Entity [in]. Data type for Java:
long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
GetEntityGlobal
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The GetEntityGlobal method returns the value stored in a specified global variable of a specified entity. Alternatively,
returns a value of type kAI_Invalid if the specified global variable and/or entity doesnt exist.
GetEntityGlobal has two parameters:
entityID: ID number of the entity. Data type for C++: AI_Entity [in]. Data type for Java: long [in].
globalName: Name of the global variable holding the value you want to read. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
190
GetLastError
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
If the last method you used returns an error message (i.e., a non-kOK value), the GetLastError method returns a string
containing the explanatory message. Otherwise, GetLastError will return an empty string.
GetLastError has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
GetVersion
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The GetVersion method inspects the currently-loaded engine, and then tells you the engines version number, and
whether the engine is a release version (which executes faster) or a development version (which contains extra code
to enable interactive debugging, as described in the Debugging your project topic).
GetVersion has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Initialize
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Initialize method initializes the run-time engine and prepares it for operation (i.e., loads the engine into memory,
sets up the engines stack, etc.). If something goes wrong during initializatione.g., a missing file, insufficient
memorythis method returns an error code and saves an explanatory error message, which you can then retrieve via
the GetLastError method. Otherwise, it returns kOK, meaning no problems were encountered.
Note: You must use the Initialize method before using any other API method. If Initialize does not return kOK, you
should fix the problem and call Initialize again before invoking any other API methods.
Initialize has two parameters:
simInter: The custom simulation interface object. Data type for C++: pointer to AI_Interface object [in]. Data
type for Java: SB_Interface object [in].
config: Configuration parameters for SimBionic. Data type for C++: pointer to AI_Config object [in]. Data
type for Java: SB_Config object [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
IsEntityFinished
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The IsEntityFinished method returns true if the specified entity has reached the final action of its initial behavior i.e.,
if it has no behaviors remaining on its execution stack otherwise it returns false. For more information, see the topic
Understanding SimBionic's flow of execution.
IsEntityFinished has one parameter:
entityId: the unique ID of the entity whose status you wish to check. Data type for C++: AI_Entity [in]. Data
type for Java: long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
loadAPModule
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The LoadAPModule method loads an AP module and makes all actions and predicates in that AP module available for
invocation in the engine. For more information, see Managing AP modules in the C++ run-time engine and Managing
AP modules in the Java run-time engine.
LoadAPModule has one parameter:
simInterface: the interface object that implements the AP module. Data type for C++: AI_Interface* [in].
Data type for Java: SB_Interface [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
191
LoadPackage
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The LoadPackage method loads a package file from an open input stream and makes all behaviors in that package
available for invocation in the engine. For more information, see the Dynamically loading and unloading behaviors
topic.
LoadPackage has two parameters:
packageStream: an open input stream that is ready to read from a package file. Data type for C++:
std::istream [in]. Data type for Java: InputStream [in].
packageName: the name of the package being loaded. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
LoadPackageFile
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The LoadPackageFile method loads the named package file and makes all behaviors in that package available for
invocation in the engine. For more information, see the Dynamically loading and unloading behaviors topic.
LoadPackageFile has one parameter:
packageFile: the name and location of the package file to load. Data type for C++: string [in]. Data type for
Java: URL [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Log
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Log method allows you to insert comments at select points of your program that will be written to the Log file
along with the engines activities. This method therefore allows you to make the Log file more readable, as well as
track at what point anything went wrong with your programs execution.
Note: You can control how much detail is entered into the Log file via the logContent parameter of the AI_Config (in
C++) or SB_Config (in Java) configuration object.
The Log method has one parameter of C++/Java data type string:
msg: Comment to be written to the Log file. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
MakeEntity
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The MakeEntity method, like the CreateEntity method, creates an entity in the run-time engine and places it under
SimBionics control. (Note: Along with each entity, the engine creates a behavior stack, message queue, and set of
global variables devoted to the activities of that entity.)
MakeEntity doesnt specify the entitys initial behavior, however, so the SetBehavior method must be applied to the
entity before its first update. MakeEntity also doesnt set the entitys update frequency or priority, so if you want
anything other than the defaults for those settings applied to the entity, you must use the SetUpdateFreq and/or
SetUpdatePriority methods. MakeEntity returns the unique ID number the engine assigns to your new entity and will
use exclusively to refer to that entity (as data type AI_Entity in C++ or data type long in Java).
MakeEntity has one parameter of C++/Java data type string:
entityName: Name of the entity you want to create. This parameter is optional, since the engine uses ID
numbers exclusively to refer to entities. However, providing each entity with an appropriate name can make
your program output easier to read and debug. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
PostBBoard
PostBBoard is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
192
PostBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
PostBBoard lets an entity place information on any virtual blackboard (created previously via the CreateBBoard action)
by specifying the boards name, the section of the board that will house the information, and the data itself. Any entity
that "knows" both the name of the board and the section of it storing the pertinent information can then read that
information (via the ReadBBoard predicate). PostBBoard therefore allows any entity to provide information to any or all
other entities in your program.
PostBBoards three parameters are the blackboards name, which is a string; and then a key-value pair consisting of
the name of the section of the board that will store your particular piece of informationthe name also being a string
followed by the actual information, which can be any data type:
For example, if you wanted an entity to place information referred to by the variable Info on a blackboard named
Target_Locations in a section of the board named Enemy_Headquarters, youd insert this expression into an action on
the Canvas: PostBBoard("Target_Locations", "Enemy_Headquarters", Info).
A blackboard must existi.e., have been created via the CreateBBoard actionbefore an entity can post information
to it. However, if the section of the board where the information is being placedi.e., the keydoesnt already exist,
its created automatically with the name specified the first time an entity refers to it via the second parameter of the
PostBBoard action. Once an entity creates a named section of a blackboard, that section continues to exist for the life
of the board; and the information in each named section remains stored there until replaced with new data.
Theres no limit to the amount of information that can be placed on a blackboard. When a blackboard becomes
obsolete, any entity can eliminate it (and free up the memory its occupying) by using the DestroyBBoard action.
Alternatively, an entity can "erase" the information on a blackboard by first destroying the board and then immediately
using the CreateBBoard action to make a blank blackboard with the same name.
For more information, see the Communicating via virtual blackboards topic.
ReadBBoard
ReadBBoard is a predicate thats available in every SimBionic project. Its automatically declared in the Catalog in the
Core AP module in a folder named Blackboards, with corresponding code built into SimBionics engine.
ReadBBoard is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
ReadBBoard lets an entity access any virtual blackboard (created previously via the CreateBBoard action) and read
any information on the board (stored previously via the PostBBoard action) by specifying the boards name and the
section of the board that houses the information. ReadBBoard therefore allows any entity to get information from any
or all other entities in your program.
ReadBBoards two parameters are the desired blackboards name, which is a string; and the name of the section of
the boardor keythat holds the pertinent information, the latter name also being a string:
For example, if you wanted an entity to obtain information from a blackboard named Target_Locations and a section of
the board named Enemy_Headquarters, youd use this predicate: ReadBBoard("Target_Locations",
"Enemy_Headquarters"). ReadBBoard would then return whatever information was stored in the Enemy_Headquarters
section of the Target_Locations blackboard, in the form of data type any.
If an entity specifies the name of a blackboard and/or a section of the blackboard that doesnt actually exist,
ReadBBoard will return a value of Invalid. Its recommended that you always check for this possibility by using the
IsValid predicate directly after an entity uses ReadBBoard.
For more information, see the Communicating via virtual blackboards topic.
RegisterLogPrintStream
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The RegisterLogPrintStream method declares a print stream to which logging messages will be sent, which can be
useful for Web browser applets. More than one print stream can be specified. (Note: This is a Java-only API method.)
RegisterLogPrintStream has one parameter:
logPrintStream: A valid print stream to which messages can be written. Data type: PrintStream object [in].
For more information, see the Using the Java engine's API methods topic.
SendMsg
SendMsg is an action thats available in every SimBionic project. Its automatically declared in the Catalog in the Core
AP module in a folder named Messages, with corresponding code built into SimBionics engine.
193
SendMsg is also available as an API method accessible directly from your applications code, as described in the
Understanding the C++ run-time engine and Understanding the Java run-time engine topics.
SendMsg lets any entity send a message directly to a group of entities by specifying the groups name (created
previously via the JoinGroup action), a number code that optionally provides some additional information about the
message, and the message itself.
The groups name is straightforward. The message is typically a text string, but can actually be of whatever data type
is best suited for the information to be sent.
As for the number code, SimBionic doesnt ascribe any meaning to it, so what number is attached to a particular
message and what that number represents is entirely up to you. For example, you might assign each message a
priority number from 1 to 5, with 1 meaning Urgent; read immediately! and 5 meaning Light news; read at your leisure.
Or you might assign each entity a unique number and then use the numbers to flag messages directed exclusively at a
particular entity. Or you might use number codes to indicate different ways a particular message should be interpreted
(e.g., 1 might mean Read as text string, 2 might mean Read as map coordinates, 3 might mean, Read as direction and
velocity changes, etc.). No matter what coding system you create, it should provide useful information.
When a message is sent to a group, every entity that belongs to the group will automatically receive the message in its
personal message queue, which will store the message until the entity is ready to access it. The entity can then check
who sent the message (via the GetMsgSender predicate), read the messages number code (via the GetMsgType
predicate), and/or read the message itself (via the GetMsgData predicate). When the entity is done with the message,
it can then remove it from the queue (via the NextMsg action), which allows the entity to access the next message
waiting for it.
An entity doesnt have to be a member of a group to send a message to that group; it simply needs to "know" the
name of the group. The advantage of belonging to a group is that an entity receives all messages sent to that group.
But if, say, a leader entity needs to send frequent messages to subordinate entities, it might opt to not join the
subordinates group so that its message queue doesnt become cluttered with its own messages. Further, the leader
might create another group consisting solely of itself, so that subordinates can send messages to the leader that only
the leader can read.
Theres no limit to the number of groups that can be created; the number of groups a particular entity can join; the
number of entities that can belong to a particular group; or the number of messages that can be sent to a particular
group.
SendMsgs three parameters are the groups name, which is of data type entity; the number code, which is of data
type integer; and the actual message, which can be any data type:
group: entity [in], number code: integer [in], msg: any [in]
For example, if you wanted an entity to send a message to a group named Superheroes, with a number code of 1, and
a text message saying Stop approaching meteor from striking Earth!!, youd insert this expression into an action on the
Canvas: SendMsg("Superheroes", 1, "Stop approaching meteor from striking Earth!!").
For more information, see the Communicating via group messages topic.
SetBehavior
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetBehavior method pops all execution frames currently on the specified entity's stack and then reinitializes the
entitys behavior via the specified parameters. However, SetBehavior leaves the entitys message queue and global
variables unchanged. Use this method in conjunction with the MakeEntity method or to change an entitys current
behavior.
SetBehavior is also an action thats available in every SimBionic project. Its automatically declared in the Catalog in
the Core AP module in the folder named Entity, with corresponding code built into SimBionics engine.
SetBehavior has three parameters:
entityID: ID number of the entity whose behavior you want to set. Data type for C++: AI_Entity [in]. Data
type for Java: long [in].
behaviorID: Name of the behavior you want the entity to start executing. The engine does not employ ID
numbers for behaviors, but instead refers to each behavior using the exact same nameincluding the same
upper- and lower-case spellingyou assigned to the behavior when declaring it in the Catalog (as described
in the Declaring a behavior topic). Data type: string [in].
params: Parameters to pass for the specified behavior. The particular parameters will depend on the
behavior you selected. Data type for C++: AI_ParamVec [in]. Data type for Java: ArrayList of SB_Param
objects [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SetEntityGlobal
194
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetEntityGlobal method sets the value of the specified global variable for the specified entity. For example, you
can use this method to assign the entity a different descriptor value, thus setting the entity to perform a different
polymorphic behavior (see the Creating polymorphisms topic).
SetEntityGlobal is also an action thats available in every SimBionic project. Its automatically declared in the Catalog
in the Core AP module in a folder named Entity, with corresponding code built into SimBionics engine.
SetEntityGlobal has three parameters:
entityID: ID number of the entity whose global variable you want to set. Data type for C++: AI_Entity [in].
Data type for Java: long [in].
varName: Name of the global variable you want to set. Data type: string [in].
value: Value you want to store in the specified global variable. Data type for C++: AI_Param [in]. Data type
for Java: SB_Param [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SetUpdateFreq
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetUpdateFreq method, just like the CreateEntity methods updateFreq parameter, sets the minimum frequency
with which you want an entity updated, specified via an integer from -1 through 100. Use this method in conjunction
with the MakeEntity method or to change an entitys current update frequency. See the Controlling the entity scheduler
topic for more information on the update frequency parameter.
SetUpdateFreq is also an action thats available in every SimBionic project. Its automatically declared in the Catalog
in the Core AP module in a folder named Entity, with corresponding code built into SimBionics engine.
SetUpdateFreq has two parameters:
newFreq: Update frequency you want applied to the specified entity (ranging from -1 through 100). Data
type: integer [in].
entityID: ID number of the entity whose update frequency you want to set. Data type for C++: AI_Entity [in].
Data type for Java: long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SetUpdatePriority
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SetUpdatePriority method, just like the CreateEntity methods updatePriority parameter, sets the update priority
you want to assign an entity within any given clock tick, specified via an integer from 0 on up through the highest
integer allowed by your compiler. Use this method in conjunction with the MakeEntity method or to change an entitys
current update priority. See the Controlling the entity scheduler topic for more information on the update priority
parameter.
SetUpdatePriority is also an action thats available in every SimBionic project. Its automatically declared in the
Catalog in the Core AP module in a folder named Entity, with corresponding code built into SimBionics engine.
SetUpdatePriority has two parameters:
newPriority: Update priority you want applied to the specified entity (ranging from 0 on up). Data type:
integer [in].
entityID: ID number of the entity whose update priority you want to set. Data type for C++: AI_Entity [in].
Data type for Java: long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
SwapProject
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The SwapProject method enables you to unload the currently-loaded project from the run-time engine and load a
different project. Calling this method will also destroy all entities. While you could also accomplish this by shutting
down the engine and restarting it (via the Terminate and Initialize API methods), SwapProject is more efficient
because it doesnt have to destroy and recreate all of the engine infrastructure.
195
Note that the new project loaded by SwapProject must use the same actions and predicates (i.e., AI_Interface or
SB_Interface object) as the current project. It must also use the same configuration parameters.
SwapProject has one parameter:
behaviorFile: path and filename of the compiled project file that you wish to load. Data type for C++: string
[in]. Data type for Java: URL [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Terminate
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Terminate method shuts down the run-time engine and, if youre using the dynamic C++ version of the engine,
unloads the SimBionic DLL. You must use this method last, because the engine wont be available for any other
methods after Terminate executeswith the exception of Initialize, which will start the engine up again.
Terminate has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
UnloadAll
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UnloadAll method unloads all currently-loaded behaviors from the run-time engine and destroys all existing
entities. For more information, see the Dynamically loading and unloading behaviors topic.
UnloadAll has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
unloadAPModule
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UnloadAPModule method unloads the named AP module from the run-time engine, removing all actions and
predicates in that AP module from memory and making them unavailable for invocation. For more information, see
Managing AP modules in the C++ run-time engine and Managing AP modules in the Java run-time engine.
UnloadAPModule has one parameter:
moduleName: the name of the AP module to unload. Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
UnloadPackage
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UnloadPackage method unloads the named package from the run-time engine, removing all behaviors in that
package from memory and making them unavailable for invocation. For more information, see the Dynamically loading
and unloading behaviors topic.
UnloadPackage has one parameter:
packageFile: the name of the package file to unload (including the .BIM extension). Data type: string [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
Update
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The Update method advances the run-time engines clock by one tick, updating entities as dictated by the engines
entity scheduler. To learn more, see the Controlling the entity scheduler and Understanding SimBionic's flow of
execution topics.
Update has no parameters.
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
UpdateEntity
196
SimBionic's application program interface, or API, provides you with a range of API methods that let you easily control
the functioning of the run-time engine via C++ or Java code (as described in the Understanding the C++ run-time
engine and Understanding the Java run-time engine topics).
The UpdateEntity method updates the specified entity, entirely bypassing the engines scheduler. Use this command
only for special circumstances in which an entity requires updating outside of the engines normal scheduling and
resource balancing. To learn more, see the Understanding SimBionic's flow of execution topic.
UpdateEntity has one parameter:
entityID: ID number of the entity you want to update. Data type for C++: AI_Entity [in]. Data type for Java:
long [in].
For more information, see the Using the C++ engine's API methods or Using the Java engine's API methods topic.
197
Launch the editor: Double-click the SimBionic icon on your desktop; or click the Start button and select
Programs->SimBionic->SimBionic Editor.
Open an existing project: If youve worked with the project recently, click the File menu and click the
projects name from the bottom of the menu. Otherwise, press Ctrl+O; and then locate and double-click the
projects filename.
Save your project under a different name and/or folder location: Click the File menu and select Save
As; specify the filename and folder location; and click Save.
Print the current behavior on the Canvas: Press Ctrl+P; make any necessary setting adjustments; and
click OK.
Create a descriptor category: On the Descriptors pane, right-click the top "Project" header; select Insert
Descriptor Category from the menu that appears; type the categorys name; and press Enter.
Create a descriptor: Right-click the existing descriptor under which you want to place your new descriptor;
select Insert Descriptor from the menu that appears; type the new descriptors name; and press Enter.
Create a polymorphism: Display on the Canvas the behavior for which you want to create a polymorphism;
right-click the tab at the bottom of the Canvas and select Duplicate Polymorphism from the menu that
appears; on the Descriptors pane, click the combination of descriptors to which you want to assign your
polymorphic behavior; and then revise the behavior to make it appropriate for those descriptors.
Create a Catalog item: Right-click the appropriate header for the item you want to create (i.e., Actions,
Predicates, Behaviors, Globals, or Constants); select the Insert option from the menu that appears; type the
necessary information into the dialog box that appears; and click OK.
Create a Catalog folder: Right-click the header for which you want to create the folder (i.e., Actions,
Predicates, Behaviors, Globals, or Constants); select New Folder from the menu that appears; type the
name you want to give the folder; and press Enter.
Import actions and predicates: Click the File menu and select Import AP Module.
Import behaviors: Right-click the Behaviors header; select Import from the menu that appears; specify the
filename and folder location of the pertinent BTN file; and click Open.
Create a local variable: Click the Locals button on the upper-right of the toolbar; right-click the Locals
header; select Insert Local from the menu that appears; specify the variable name and data type; and click
OK.
Create an action on the Canvas: Click and drag the action from the Catalog to the Canvas; or right-click a
blank spot on the Canvas and select Insert Action from the menu that appears.
Create a condition: Click and drag a predicate from the Catalog to the Canvas; or right-click a blank spot
on the Canvas and select Insert Condition from the menu that appears.
Create an invoked behavior: Click and drag a behavior from the Catalog to the Canvas.
Edit a Canvas expression: Select the Canvas element and press Ctrl+E to bring up an Edit Expression
dialog box; revise the expression; and click OK.
Create a connector: Press the Ctrl key while clicking and dragging from one rectangle or oval to another
rectangle or oval.
Attach a binding to a Canvas element: Select the Canvas element and press Ctrl+B; click the Insert
button on the dialog box that appears; enter the binding; and click OK twice.
Attach a tooltip comment to a rectangle or oval: Click the action, behavior, or condition; click the
Comment button; type your explanatory note; and press Enter.
Place an always-visible comment on the Canvas: Click the Connector toolbars Add Text button (which
looks like the letter "A"); click the spot on the Canvas where you want to insert your explanatory note; type
your text; and click anywhere outside the text.
Copy a Canvas element: Click the element, press Ctrl+C, right-click the spot where you want to insert the
copy, and select Paste from the menu that appears. Alternatively, for rectangles and ovals only, press
Ctrl+Shift while clicking and dragging the element.
199
Move a Canvas element: If youve moving it within the same Canvas page, simply click and drag the
element. If youve moving it to a different page, click the element, press Ctrl+X, right-click the spot where
you want to move the element, and select Paste from the menu that appears.
Find all instances of a Canvas element: Right-click the appropriate declaration in the Catalog and select
Find from the menu that appears.
Find all instances of a text sequence on the Canvas: Press Ctrl+F; type the text; and press Enter.
Replace all instances of a text sequence on the Canvas: Press Ctrl+H; type the text to replace and the
replacement text; and press Enter.
Delete a polymorphism: Click the tab at the bottom of the Canvas page and select Delete Polymorphism
from the menu that appears.
Rename a Catalog item: Double-click the item; type the new name; and click OK.
Delete a Catalog item or Canvas element: Click the item or element, and press the Del key.
Create a C++ header file for your project: Click the File menu, select Export, and select Export Header;
specify the .h filename and folder location; and click Save.
Create a Java header file for your project: Click the File menu, select Export, select Export Constants,
and select Java; specify the .java filename and folder location; and click Save.
Identify the version of SimBionic youre using: Click the Help menu and select About SimBionic. (To
check for new versions of the program, proceed by clicking the displayed link to Web site
www.simbionic.com.)
Launch the SimBionic Help system: Click the Help menu and select SimBionic Help.
Display tips about using SimBionic: Click the Help menu and select Tip of the Day.
Close the editor: Press Alt+F4, or click the File menu and select Exit.
The heart of any SimBionic project are the behaviors you create on the Canvas. You can do any of the following to
display a particular behavior:
In the Catalog, double-click the name of the behavior you want to view.
In the Navigate toolbar (directly below the menu bar and in the middle of the window), click in the drop-down
box to display a list of your projects behaviors and then click the name of the behavior you want to view.
In the Navigate toolbar, click the Back button (which looks like an arrow pointing left) to display the previous
behavior; the Forward button (which looks like an arrow pointing right) to display the next behavior; or the
Home button (which looks like a house) to jump to your initial behavior (which is named Main, unless you
chose to revise the default name).
Click the triangle button to the right of the Back or Forward button to drop down a history of your behavior
navigation, and then click the behavior you want to view.
Press Alt+Left Arrow to display the previous behavior (same as clicking the Back button) and Alt+Right
Arrow to display the next behavior (same as clicking the Forward button).
Click the View menu, select the Go option, and then select the Back option to display the previous behavior
or the Forward option to display the next behavior.
Double-click the rectangle of an invoked behavior to display the full behavior on the Canvas.
If youve created polymorphisms, click the tab at the bottom of the Canvas labeled with the combination of
descriptors youre after.
After you perform any of the above actions, the behavior you select is displayed on the Canvas.
For more information about the SimBionic editor, see the What is SimBionic? and Understanding SimBionic topics.
For a summary of SimBionic run-time engine commands, see the SimBionic C++ Engine Cheat Sheet and SimBionic
Java Engine Cheat Sheet topics.
SimBionic C++ Engine Cheat Sheet
To successfully run a SimBionic project when your simulation or game is written in C++, you need to #include the
following files (supplied in your SimBionic package) in your C++ code:
200
AI_Config.h: A header file that defines configuration settings for the enginee.g., the filename and location
of your compiled project file; the filename and location of the engines Log file, whether the interactive
debugging feature is enabled or disabled; etc.
AI_Engine.h and AI_Engine.cpp: Defines the AI_Engine wrapper class that provides the API for the runtime engine.
AI_Exception.h and AI_Exception.cpp: Defines the AI_Exception class used internally by the run-time
engine.
AI_Interface.h and AI_Interface.cpp: Defines the AI_Interface base class that you will subclass in order to
implement your actions and predicates.
AI_Params.h and AI_Params.cpp: Defines the parameters for actions; the parameters and return values
for predicates; important constants; and methods for setting and inspecting a value.
In addition to these supplied files, you can generate and #include a header file that provides symbolic names in place
of the ID numbers the engine uses to refer to your projects actions and predicates. To create this file, click the File
menu and select Export->Export Constants->C++. (For more information, see the Creating C++ symbolic names for
actions & predicates topic.)
You will also need the compiled project file (along with any package files that youve specified) that contains the
compiled version of your SimBionic project. To create these files, click the Build menu and select the Compile option;
or press F7; or click the Compile button in the upper-right of the editor window. For more information, see the
Compiling your project topic.
You also need to include the underlying C++ code for all the custom actions and predicates used in your project. For
sample code that illustrates how to do this, see the Coding actions in C++, Coding predicates in C++, and Accessing
and setting parameter values in C++ topics. SimBionic can assist you with this process by generating skeleton
interface code, as described in the Generating skeleton code for C++ topic.
Finally, you must include C++ code that starts up the engine and directs it in such activities as creating entities, setting
the frequency and priority with which entities are updated, selecting behaviors, setting the values of global variables,
retrieving error messages, inserting comments to be recorded along with the engines activities in a Log file, and
shutting down the engine. You can do this via SimBionics API methods:
Heres sample code that demonstrates how to use some of these API methods to start up the engine and put it
through its paces:
**********
int main(int argc, char* argv[])
{
// create the action/predicate interface between the engine and the game
MyInterface* myInterface = new MyInterface();
// create the object that holds configuration parameters for the engine
AI_Config* myConfig = new AI_Config();
// specify the name of the SIM file to load
myConfig->behaviorFilename = "c:\\SimProjects\\MyProject.sim";
// creates an instance of the engine interface object
AI_Engine engine;
201
// an integer parameter
// a vector parameter
id = engine.CreateEntity("MyEntity","SomeBehavior",parms,0,0);
engine.Update();
engine.Terminate();
}
**********
For more information about the run-time engine, see the What is SimBionic? and Understanding the C++ run-time
engine topics.
For a summary of how to perform common activities in the SimBionic editor, see the SimBionic Editor Cheat Sheet
topic.
SimBionic Java Engine Cheat Sheet
To successfully run a SimBionic project when your simulation or game is written in Java, you need to import the
following files (supplied in your SimBionic package) in your Java code:
SB_Config.java: Defines configuration settings for the enginee.g., the filename and location of your
compiled project file; the filename and location of the engines Log file, whether the interactive debugging
feature is enabled or disabled; etc.
SB_Engine.java: Defines the SB_Engine wrapper class that provides the API for the run-time engine.
SB_Interface.java: Defines the SB_Interface base class that you will extend in order to implement your
actions and predicates.
SB_Param.java: Defines the SB_Param class that is passed to your action and predicate code, including
methods for setting and inspecting a value.
In addition to these supplied files, you can generate and import a Java file that provides symbolic names in place of
the ID numbers the engine uses to refer to your projects actions and predicates. To create this file, click the File menu
and select the Export->Export Constants->Java option. (For more information, see the Creating Java symbolic names
for actions & predicates topic.)
You will also need the compiled project file (along with any package files that youve specified) that contains the
compiled version of your SimBionic project. To create these files, click the Build menu and select the Compile option;
or press F7; or click the Compile button in the upper-right of the editor window. For more information, see the
Compiling your project topic.
You also need to include the underlying Java code for all the custom actions and predicates used in your project. For
sample code that illustrates how to do this, see the Coding actions in Java, Coding predicates in Java, and Accessing
and setting parameter values in Java topics. SimBionic can also assist you with this process by generating skeleton
interface code, as described in the Generating skeleton code for Java topic.
Finally, you must include Java code that starts up the engine and directs it in such activities as creating entities, setting
the frequency and priority with which entities are updated, selecting behaviors, setting the values of global variables,
retrieving error messages, inserting comments to be recorded along with the engines activities in a Log file, and
shutting down the engine. You can do this via SimBionics API methods:
202
Heres sample code that demonstrates how to use some of these API methods to start up the engine and put it
through its paces:
**********
void startEngine()
{
// create the action/predicate interface between the engine and the game
MyInterface myInterface = new MyInterface();
// create the object that holds configuration parameters for the engine
SB_Config myConfig = new SB_Config();
//Turn off the debugger
myConfig.debugEnabled = false;
try
{
URL fileURL = new URL("file", "localhost", "c:\\SimProjects\\MyProject.sim");
myConfig.fileURL = fileURL;
}
catch(Exception e)
{
System.out.println("Exception in creating URL from the file name.");
}
// creates an instance of the engine interface object
SB_Engine engine = new SB_Engine();
//Add a log output stream
PrintStream logPrintStream = null;
try
{
logPrintStream = new PrintStream( new FileOutputStream("MyProject.log") );
}
catch(Exception ex)
{
ex.printStackTrace();
}
if( logPrintStream != null )
{
engine.registerLogPrintStream( logPrintStream );
}
// initialize the engine
if (engine.initialize(myInterface,myConfig) != SB_Error.kOK)
203
{
System.out.println("Engine failed to initialize");
return;
}
// create a single test entity
ArrayList parms = new ArrayList();
long id;
// add some parameters for the behavior
parms.add( new SB_Param(10) );
// a integer parameter
// a string parameter
// a vector parameter
id = engine.createEntity("MyEntity","SomeBehavior",parms,0,0);
engine.update();
engine.terminate();
}
**********
For more information about the run-time engine, see the What is SimBionic? and Understanding the C++ run-time
engine topics.
For a summary of how to perform common activities in the SimBionic editor, see the SimBionic Editor Cheat Sheet
topic.
204
Index
A
Accessing parameter values
144, 174
Action in Catalog
IsEntityFinished
150, 180
LoadPackage
151, 181
LoadPackageFile
151, 181
coding in C++
128, 144
Log
151, 181
coding in Java
160
MakeEntity
151, 181
core
15
PostBBoard
152, 181
creating
20
ReadBBoard
152, 182
deleting
32
RegisterLogPrintStream
editing
20
SendMsg
152, 182
importing
25
SetBehavior
153, 183
182
in AP module
25
SetEntityGlobal
153, 183
organizing
31
SetUpdateFreq
154, 184
renaming
31
SetUpdatePriority
154, 184
Action on Canvas
Terminate
155, 185
attaching binding to
72
UnloadAll
155, 185
changing label of
57
UnloadPackage
155, 185
commenting on
56
Update
155, 185
UpdateEntity
155, 185
compound
40
copying
50
creating
34
Array
as text expression
76
77
deleting
52
ArrayAddEntry
76
editing
34
ArrayAppend
76
moving
51
ArrayCopy
76
placing a reminder on
56
ArrayDelete
76
setting as final
43
ArrayGet
76
setting as initial
42
ArrayInsert
76
57
ArrayPop
76
93
ArraySet
76
ArraySetMinSize
76
76
AI_Config
126, 145
ArraySetSize
AI_Engine
126, 145
ArraySize
AI_Exception
115, 126
AI_Interface
AI_Param
Always rectangle
115, 116
56
76
59, 72
72
Authoring tool
Autocompleting an expression
1
72
B
Back button
33
29
Behavior in Catalog
148, 178
creating
26
CreateEntity
148, 178
deleting
32
DestroyBBoard
149, 179
editing
26
DestroyEntity
149, 179
importing
30
GetEntityGlobal
149, 179
Main
30
GetLastError
150, 180
organizing
31
GetVersion
150, 180
renaming
31
Initialize
150, 180
29
205
29
Final
43
29
Forward
33
Initial
42
72
Main
33
4
Behavior on Canvas
attaching binding to
changing label of
57
New
88
Open
commenting on
56
Paste
50, 51
copying
50
12
37
Quick-Run
93
Redo
55
52
Reminder
56
37
Save
11
108
Undo
55
creating
creating sub-behaviors within
deleting
editing
extracting
moving
108
51
navigating behaviors
33
placing a reminder on
56
Behavior package
114
Binding
attaching to Canvas element
72
creating
59, 69, 70
deleting
C
C++ run-time engine
API methods
125
145
coding actions
128, 142
coding predicates
128, 142
interfacing with
logging in
147
74
memory management
147
editing
74
shutting down
reordering
74
starting
147
103, 145
Blackboard
110
Blue rectangle
115
Bold rectangle
37
right-clicking
Breakpoint
97
Canvas element
Breakpoint list
96
attaching binding to
72
BTN files
30
commenting on
56
Build menu
Build->Breakpoint
Canvas
commenting on
33
57
34, 44, 50, 51
copying
50
97
creating
Build->Compile
90
deleting
Build->Connect
93
editing
34, 37, 44
Build->Project Settings
93
finding
52
Build->Quick-Run
93
moving
51
Bulid->Debug
93
pasting
50, 51
Build tab
90
Built-in actions
15
Catalog
Built-in predicates
18
Catalog item
Buttons on toolbar
Add Text
placing a reminder on
52
56
15
15
creating
57
deleting
32
Back
33
editing
Bindings
72
organizing
31
Comment
56
renaming
31
Compile
90
Catch rectangle
Connect
93
Changing
115
Copy
50
action in Catalog
20, 32
Cut
51
action on Canvas
34
Expression
69
behavior in Catalog
206
26, 29, 32
Index
behavior on Canvas
37, 108
creating
48
binding
74
deleting
52
56
labeling
48, 56
condition
44
moving
51
connector
49
placing a reminder on
56
constant
67
48
descriptor
82
Constant
folder
31
binding
67, 69, 72
57
creating
67
predicate
22, 32
deleting
32
variable declaration
63, 65
editing
67
Cheat Sheets
importing
67
188
moving
31
187
renaming
31
190
type
60
88
Copying
63
Class
117, 119
Coding in C++
126, 127
Canvas element
50
polymorphism
85
Core actions
15
actions
128
ArrayAddEntry
76
predicates
128
ArrayAppend
76
Coding in Java
157, 158
ArrayDelete
76
actions
160
ArrayInsert
76
predicates
158
ArraySet
76
107
ArraySetMinSize
76
Command-line options
Comment
Communicating between entities
56
15, 18
ArraySetSize
76
CreateBBoard
111
DestroyBBoard
110
DestroyEntity
149, 179
90
DestroyGroup
111
88
JoinGroup
111
Compound action
40
NextMsg
Condition
attaching binding to
PostBBoard
72
QuitGroup
111
110, 152, 181
111
changing label of
57
SendMsg
commenting on
56
SetBehavior
153, 183
copying
50
SetEntityGlobal
153, 183
creating
44
SetUpdateFrequency
154, 184
154, 184
deleting
52
SetUpdatePriority
editing
44
TableAddCol
77
moving
51
TableAddRow
77
placing a reminder on
56
TableAppend
77
77
TableDeleteRow
77
93, 94
Connector
TableInsertCol
77
attaching binding to
72
TableInsertRow
77
changing priority of
49
TableSetCol
77
commenting on
56
TableSetEntry
77
copying
50
TableSetMinSize
77
207
TableSetRow
77
56
TableSetSize
77
sub-behavior
Core predicates
18
ArrayCopy
76
ArrayGet
76
ArrayPop
76
ArraySize
76
CreateEntity
148, 178
108
142, 172
51
D
Data exchanges between entities
15, 18
111
110
GetMsgData
111
60
GetMsgSender
111
Debugger
93
GetMsgType
111
configuring
IsBBoard
110
launching
IsMsg
111
using
NumMembers
111
Declaring
action
93, 94
94
95, 96
ReadBBoard
110
TableColSize
77
behavior
TableCopy
77
class
TableGetCol
77
constant
67
20
26
117
TableGetEntry
77
enumerated type
79
TableGetRow
77
global variable
65
TableRowSize
77
local variable
63
predicate
22
CreateBBoard
CreateEntity
Creating
Deleting
action
32, 52
action in Catalog
20
AP module
action on Canvas
34
behavior
AP module
25
binding
74
behavior in Catalog
26
breakpoint
97
37
Canvas element
52
Catalog item
32
128, 160
class
32
144, 174
constant
67
128, 158
enumerated type
behavior on Canvas
class
code for action
117
56
package
25
32, 52
32
114
compound action
40
parameter
condition
44
predicate
connector
48
sub-behavior
constant
67
Descriptor
81
descriptor
82
creating
82
enumerated type
79
renaming
expression
69, 72
DestroyBBoard
26, 32
32
108
31
110, 149, 179
folder
31
DestroyEntity
149, 179
global variable
65
DestroyGroup
111
local variable
63
Displaying
package
parameter
114
20, 22, 26
33
56
polymorphism
85
action
20
predicate in Catalog
22
behavior
26
Canvas
57
project
208
Index
Canvas element
56
class
117
overview
starting
constant
67
enumerated type
79
API methods
145, 175
22
Cheat Sheet
188, 190
predicate
variable
63, 65
29
Drag-and-drop
execution flow
34, 37, 44
31
Entities window
72
Entity
Drawing a connector
48
113
E
Edit menu
Edit->Copy
Edit->Cut
Edit->Delete
Edit->Find
51
32, 52
52
Edit->Paste
50, 51
Edit->Redo
55
Edit->Replace
54
Edit->Undo
55
Editing
action in Catalog
20
34, 57
149, 179
ID number
148, 178
scheduling
Enumerated type
Error handling
Exception handling
Exchanging information between entities
110
class
117
Execution mode
29
95
13
C++ header
constants
HTML
Java class
56
compound action
40
XML
condition
44, 57
Expression
connector
49
autocompleting
constant
67
creating
enumerated type
79
editing
expression
folder
package
File->Exit
32
File->Export Constants
22
56
variable
Editor for SimBionic
Cheat Sheet
108
78
63, 65
1
187
107
172
129, 161
107
69
72
34, 44, 69, 72
34, 44, 74
parameter
sub-behavior
142
129, 161
File menu
predicate
table
87
74
115
15, 18
76
binding
115
Execution
array
26
79, 80
111
Exiting SimBionic
37, 57
95
109
25
behavior on Canvas
95
148, 178
AP module
behavior in Catalog
126
destroying
flow
action on Canvas
creating
147, 177
87
exiting
starting
125, 157
File->Export XML
File->Import AP Module
13
142, 172
107
129, 161
107
25
File->New
File->Open
File->Print
12
209
File->Save
11
editing
65
File->Save As
11
moving
31
92
polymorphic
81
.APD file
25
renaming
31
.BIM file
114
.BTN file
30
.CPP file
.H file
129
129, 142
.HTML file
107
.JAVA file
161, 172
.SBP file
type
Group
Header file for naming actions & predicates
Home button
.XML file
107
33
If 18, 72
Final
43
52
Importing
Finding
52
4
52
87
Folder
25
behavior declarations--BTNs
30
constants
67
15, 18
111
110
31
Initial
deleting
32
Initial/Final toolbar
organizing contents of
31
Initialize
renaming
31
Insert menu
Forward button
33
Game or simulation
88
creating
107
Find tab
142
HTML documentation
90
92
project
111
Hooking SimBionic into your simulation/game103, 125, 126, 145, 157, 175
.SIM file
42
11
.TPD file
Canvas elements
60
Green rectangle
42
42, 43
145, 150, 175, 180
Insert->New Action...
20
Insert->New Behavior...
26
40
coding actions
128, 160
Insert->New Condition...
44
144, 174
Insert->New Global...
65
coding predicates
128, 158
Insert->New Local...
63
hooking into SimBionic103, 125, 126, 127, 145, 157, 158, 175
Insert->New Predicate...
22
relationship to SimBionic
Insert->New Rectangle...
34, 37
Generating
HTML documentation
skeleton interface code
XML
GetEntityGlobal
GetEntityID
Installing SimBionic
107
129, 161
107
149, 179
18
GetLastError
GetMsgData
111
GetMsgSender
111
GetMsgType
111
GetVersion
150, 180
Global variable
binding
Interruptible
Invalid data type
IsBBoard
IsDone
IsEntityFinished
110
88
150, 180
111
IsValid
18
J
Java run-time engine
API methods
coding predicates
creating
65
interfacing with
deleting
32
logging in
210
IsMsg
coding actions
65, 69, 72
3
29
157
175
142, 160
158, 172
157, 158, 161
177
Index
shutting down
177
starting
175
Message
111
JoinGroup
K
Keystroke shortcuts for SimBionic editor
147
111
15, 18
111, 152, 182
via virtual blackboards110, 148, 149, 152, 178, 179, 181, 182
13
Message queue
33
Moving
33
74
111
74
Canvas element
51
50
Catalog item
31
22
polymorphism tab
85
34, 37, 44
project
52
sub-behavior
93
65
Multi-tick
54
Multi-user development
26
44
11
108
33
29
107
N
Navigating behaviors
33
63
NextMsg
40
Non-interruptible
29
56
111
NullData
18
12
NullEntityID
18
34
NumMembers
11
20
31, 50, 51
O
One-tick
Operators available for expressions
55
Output window
55
32, 52
90
Debug tab
93
52
F5 for Build->Debug
93
Find tab
90
F8 for Quick-Zoom
34
Label
4
70
Build tab
F7 for Build->Compile
L
29
Opening a project
51
111
97
Parameter
57
LoadPackage
151, 181
LoadPackageFile
151, 181
creating
20, 22, 26
deleting
editing
Local variable
binding
creating
69, 72
63
144
174
50, 51
editing
63
renaming
31
creating
85
type
60
moving page of
85
Log
151, 181
147, 177
renaming
85
PostBBoard
M
Main behavior
MakeEntity
30
151, 181
59, 81
Predicate
coding in C++
128, 144
211
coding in Java
core
158
18, 152, 182
Reordering
binding attached to Canvas element
74
creating in Catalog
22
Reorganizing a folder
31
deleting
32
54
Repositioning
44
editing
22
Canvas element
51
importing
25
Catalog item
31
in AP module
25
polymorphism tab
85
organizing
31
project
11
renaming
31
33
Printing
printing your project
Prioritizing a connector
12
12
Resume
116
49
Rethrow
116
Project
compiling
90
creating
debugging
93
documenting
Retry
Reversing your previous choice
55
55
116
55
Revising
action in Catalog
20
exiting
13
action on Canvas
34
finding
behavior in Catalog
26
opening
behavior on Canvas
37
printing
12
binding
74
saving
11
56
11
condition
44
settings
93
connector
49
constant
67
Project window
Catalog tab
15
folder
31
Descriptors tab
81
predicate
22
sub-behavior
111
variable
93
Right-clicking
34
QuitGroup
111
Quitting SimBionic
13
R
ReadBBoard
115
to create action
to create AP module
to create behavior
108
63, 65
20, 34
25
26, 37
31
40
to create condition
44
to create constant
67
29
to create descriptor
82
42
65
42
63
40
to create polymorphism
85
116
42
182
56
Renaming
to create predicate
to create sub-behavior
22
108
Run
button
93
in one tick
29
Catalog item
31
multi-tick
29
descriptor
31
until blocked
29
212
Index
Run-time engine
1, 125, 157
engine
125, 157
API methods
145, 175
exiting
13
Cheat Sheet
188
files generated by
92
87
flow of execution
87
execution flow
exiting
starting
147, 177
103, 145, 175
115
Half-Life
Pac-Man
Saving a project
starting editor
Counter-Strike
126
Hello World
installing
4
103, 145, 175
system requirements
visual approach
Simulation or game
1
103
97
11
coding actions
128, 160
coding predicates
128, 158
hooking into SimBionic103, 125, 126, 127, 145, 157, 158, 175
relationship to SimBionic
SB_Config
157, 175
SB_Engine
157, 175
project in editor
115
run-time engine
SB_Exception
SB_Interface
SB_Param
SBP file
Scheduling entity updates
Searching the Canvas
SendMsg
Starting
Sub-behavior
SwapProject
108
154, 184
System requirements
T
Table
77, 78
TableAddCol
77
SetBehavior
153, 183
TableAddRow
77
SetEntityGlobal
153, 183
TableAppend
77
Setting
action as final
42
TableColSize
77
TableCopy
77
77
29
TableDeleteCol
behavior interruptibility
29
TableDeleteRow
77
breakpoint
97
TableGetCol
77
57
144, 174
TableGetEntry
77
TableGetRow
77
77
rectangle as always
116
TableInsertCol
rectangle as catch
115
TableInsertRow
77
rectangle as initial
42
TableRowSize
77
144, 174
126
157
TableSetCol
77
TableSetEntry
77
TableSetMinSize
77
SetUpdateFreq
154, 184
TableSetRow
77
SetUpdatePriority
154, 184
TableSetSize
77
187
147, 177
Terminate
90
Add text
57
1, 3
Always
116
187
Back
188, 190
Bindings
155, 185
Toolbar buttons
Comment
33
72
115
56
213
Compile
90
UpdateEntity
Connect
93
Updating SimBionic
Copy
50
Cut
51
155, 185
13
113, 114
126
Expression
69
Final
43
Forward
33
binding
Initial
42
65
63
Variable
Main
33
New
deleting
Open
editing
Paste
50, 51
type
12
Variables window
Quick-Run
93
Version control
View menu
59
65, 69, 72
32
63, 65
60
96
107
Redo
55
Reminder
56
View->Breakpoint List
96
Save
11
View->Go
33
Undo
55
View->Quick-Zoom
34
TPD files
92
96
Entities window
95
60
95
117
33
Variables window
96
79
U
Undoing your previous choice
Viewing
49
Transition
UnloadAll
155, 185
UnloadPackage
155, 185
Update
155, 185
XML
Update frequency
109
Update priority
109
214
W
107
107
Y
Yellow rectangle
116