Sei sulla pagina 1di 222

SimBionic User Guide

SimBionic
version 2.1

Copyright 2000-2005 by Stottler Henke Associates, Inc.


All Rights Reserved.
March 15, 2005

Copyright 2000-2005 by Stottler Henke Associates, Inc. All rights reserved.


Information in this document is subject to change without notice and does not represent a commitment on the part of
Stottler Henke Associates, Inc. The software described in this document is furnished only under a license or nondisclosure agreement. The software may be used only in accordance with the terms of the agreement. Any
unauthorized duplication is a violation of U.S. copyright and other laws and may result in severe monetary and criminal
charges.
SimBionic is a trademark of Stottler Henke Associates, Inc.
Stottler Henke Associates, Inc.
951 Mariners Island Blvd., Suite 360
San Mateo, CA 94404
Tel:

650-931-2700

Fax:

650-931-2701

Web:

www.simbionic.com

Sales: Keith Weinberger keithw@stottlerhenke.com


Support:support@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

Autocompleting an expression .................................................................................................................................. 72


Working with Bindings .................................................................................................................................................. 72
Attaching bindings to a Canvas element ................................................................................................................... 72
Revising a Canvas element's bindings...................................................................................................................... 75
Using Arrays and Tables .............................................................................................................................................. 78
Using arrays ............................................................................................................................................................. 78
Editing arrays............................................................................................................................................................ 79
Array values as text expressions............................................................................................................................... 80
Using tables.............................................................................................................................................................. 80
Editing tables ............................................................................................................................................................ 81
Using Enumerated Types ............................................................................................................................................. 82
Understanding enumerated types ............................................................................................................................. 82
Creating and editing enumerated types..................................................................................................................... 82
Using enumerated types ........................................................................................................................................... 84
Working with Descriptors ................................................................................................................................................. 85
Understanding descriptors............................................................................................................................................ 85
Descriptors and global variables ............................................................................................................................... 86
Examples of descriptors............................................................................................................................................ 86
More examples of descriptors ................................................................................................................................... 87
Creating and revising descriptors ................................................................................................................................. 88
Creating first-level descriptor categories ................................................................................................................... 88
Creating lower-level descriptors................................................................................................................................ 90
Renaming descriptors ............................................................................................................................................... 90
Deleting descriptors .................................................................................................................................................. 90
Repositioning descriptors.......................................................................................................................................... 90
Creating polymorphisms............................................................................................................................................... 91
Creating Programs........................................................................................................................................................... 93
Understanding SimBionic's flow of execution................................................................................................................ 93
Understanding the execution stack ........................................................................................................................... 93
Typical flow of execution........................................................................................................................................... 93
Exceptions to the rule ............................................................................................................................................... 94
Checking for completed behaviors ............................................................................................................................... 94
Implicit IsDone .......................................................................................................................................................... 95
An IsDone example .................................................................................................................................................. 95
Exploring IsDone more deeply .................................................................................................................................. 96
Compiling your project.................................................................................................................................................. 96
Files generated by SimBionic ....................................................................................................................................... 99
Debugging your Project................................................................................................................................................ 99
Debugging your project............................................................................................................................................. 99
Configuring the debugger ....................................................................................................................................... 100
Enabling debugging for your application ................................................................................................................. 101
Launching the debugger ......................................................................................................................................... 101
Using the Debugger................................................................................................................................................ 101
Exploring the Sample Programs ................................................................................................................................. 104
Exploring the sample Pac-Man program ................................................................................................................. 105
Exploring the sample "Hello World" program........................................................................................................... 110
Using Advanced Features.............................................................................................................................................. 115
Exporting XML............................................................................................................................................................ 115
Creating HTML documentation................................................................................................................................... 115

iii

Table of Contents

Working with multiple authors..................................................................................................................................... 115


Command-line options ............................................................................................................................................... 115
Creating and editing sub-behaviors ............................................................................................................................ 116
Creating a sub-behavior.......................................................................................................................................... 116
Editing a sub-behavior ............................................................................................................................................ 117
Destroying a sub-behavior ...................................................................................................................................... 117
Changing the execution mode of a sub-behavior .................................................................................................... 117
Sub-behaviors versus invoked behaviors................................................................................................................ 117
Extracting a behavior .............................................................................................................................................. 118
Controlling the entity scheduler .................................................................................................................................. 118
Enabling Entities to Communicate.............................................................................................................................. 118
Communicating via virtual blackboards ................................................................................................................... 118
Communicating via group messages ...................................................................................................................... 120
Dynamically Loading Behaviors.................................................................................................................................. 121
Dynamically loading and unloading behaviors......................................................................................................... 121
Working with behavior packages............................................................................................................................. 122
Handling Run-time Errors ........................................................................................................................................... 125
Understanding error handling.................................................................................................................................. 125
The catch rectangle ................................................................................................................................................ 126
Recovery actions .................................................................................................................................................... 126
The always rectangle.............................................................................................................................................. 127
Using Java Classes.................................................................................................................................................... 127
Understanding classes............................................................................................................................................ 127
Creating and editing classes ................................................................................................................................... 127
Importing classes.................................................................................................................................................... 130
Using classes ......................................................................................................................................................... 131
Understanding automatic casting ............................................................................................................................ 131
Working with the C++ Run-Time Engine ........................................................................................................................ 135
Understanding the C++ run-time engine ..................................................................................................................... 135
Using SimBionic with other languages........................................................................................................................ 136
Setting up your C++ project........................................................................................................................................ 136
Implementing Actions & Predicates ............................................................................................................................ 137
Implementing your application interface in C++....................................................................................................... 137
Subclassing AI_Interface ........................................................................................................................................ 137
Coding actions in C++............................................................................................................................................. 138
Coding predicates in C++ ....................................................................................................................................... 138
Generating skeleton code for C++ .......................................................................................................................... 139
Sample skeleton code for C++................................................................................................................................ 141
Creating C++ symbolic names for actions & predicates .......................................................................................... 152
Accessing and setting parameter values in C++...................................................................................................... 155
Using the API ............................................................................................................................................................. 156
Using the C++ engine's API methods...................................................................................................................... 156
Starting and controlling the C++ run-time engine .................................................................................................... 156
Managing AP modules in the C++ run-time engine ................................................................................................. 157
Shutting down the C++ run-time engine .................................................................................................................. 157
Logging your project's execution in C++.................................................................................................................. 158
Memory management in the C++ engine ................................................................................................................ 158
The C++ API........................................................................................................................................................... 159
Working with the Java Run-Time Engine ....................................................................................................................... 167

iv

Table of Contents

Understanding the Java run-time engine .................................................................................................................... 167


Setting up your Java project ....................................................................................................................................... 167
Implementing Actions & Predicates ............................................................................................................................ 168
Implementing your application interface in Java ...................................................................................................... 168
Subclassing SB_Interface....................................................................................................................................... 168
Coding predicates in Java....................................................................................................................................... 168
Coding actions in Java............................................................................................................................................ 170
Generating skeleton code for Java.......................................................................................................................... 171
Sample skeleton code for Java ............................................................................................................................... 173
Creating Java symbolic names for actions & predicates.......................................................................................... 183
Accessing and setting parameter values in Java..................................................................................................... 185
Using the API ............................................................................................................................................................. 186
Using the Java engine's API methods..................................................................................................................... 186
Starting and controlling the Java run-time engine.................................................................................................... 186
Managing AP modules in the Java run-time engine ................................................................................................ 187
Shutting down the Java run-time engine ................................................................................................................. 188
Logging your project's execution in Java................................................................................................................. 188
The Java API .......................................................................................................................................................... 189
Using the SimBionic Cheat Sheets ................................................................................................................................ 199
SimBionic Editor Cheat Sheet .................................................................................................................................... 199
SimBionic C++ Engine Cheat Sheet ........................................................................................................................... 200
SimBionic Java Engine Cheat Sheet .......................................................................................................................... 202
Index ............................................................................................................................................................................. 205

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.

SimBionic User Guide

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

Full Java class support (Java engine only)

Compound actions

Action-predicate (AP) modules

Run-time exception handling

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.

CPU: Pentium 100 MHz or higher.

Hard disk space: 20MB (50MB of free space required for the installation process).

RAM: 14MB for the SimBionic editor.

Display: SVGA, 800 x 600 resolution, 256 colors.

CD drive: Required if SimBionic is installed from a CD.

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 powerful, flexible editor that allows you to create behaviors visually.

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):

SimBionic User Guide

To begin creating SimBionic programs, do the following:

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.

Specify the folder and filename for your project.


For detailed information on using this dialog box, see the topic Opening files with the File Chooser dialog
box.

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:

SimBionic User Guide

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:

The bars five menus are:

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:

These eight toolbars are:

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.

Build: Provides buttons for compiling and debugging your project.

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:

SimBionic User Guide

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:

SimBionic User Guide

For more information, see the What is the Canvas? topic.


Tip #1: A project 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 #2: 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 border of the Canvas and, while holding down
your mouse button, dragging the border to resize the Canvas. The Project and Output windows will automatically
resize to fit the new amount of space youve allocated to them.
Tip #3: If you need to refresh your memory about the meaning of a particular element on the Canvas, simply hover
your mouse cursor over it. After a moment, a tooltip will appear with any comments or reminders youve specified for
that element.
The Output window
The sub-window that runs across along the bottom of the SimBionic editor is called the Output window. It houses three
panes that display, or output, the results of actions you perform in SimBionic, as in this example:

The three panes are:

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.

Click the File menu and select the Save As option.


A Save As dialog box like this appears:.

2.

Specify the path and filename for your project.

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.

Repeat Step 1 periodically (e.g., every 10 minutes).


Saving frequently guards against data accidents by ensuring that your work is preserved on disk.

11

SimBionic User Guide

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.

Click the Print dialog boxs OK button.


Your pages are printed using the settings you selected.

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

Working with the Catalog


What is the Catalog?
The Catalog is the pane on the left side of SimBionics editor window that you access by clicking the Catalog tab at the
bottom of the Project window (which resides directly to the left of the Canvas). It looks like this:

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:

Action: See the Declaring an action topic.

Predicate: See the Declaring a predicate topic.

Behavior: See the Declaring a behavior topic.

Global variable: See the Creating and editing global variables topic.

Constant: See the Creating and editing constants topic.

Enumerated type: See the Creating and editing enumerated types topic.

Class: See the Creating and editing classes 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

SimBionic User Guide

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

Working with the Catalog

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

SimBionic User Guide

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

Working with the Catalog

(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

SimBionic User Guide

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.

Right-click on an AP module in the Catalog.


After you do so, a menu appears that includes an Insert Action option.

2.

Click the Insert Action option.


This Insert Action Declaration dialog box appears:

Working with the Catalog

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.

Click the Insert button (directly below the Parameters box).


The following Insert Parameter dialog box appears:

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

SimBionic User Guide

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.

10. 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.
11. Optionally repeat Steps 5-10 to create additional parameters.
Repeat this step until youve created all of the necessary parameters for your action. When youre done, all
the actions parameters are listed in the Parameters box.
12. Click the OK button of the Insert Action Declaration dialog box.
The Insert Action Declaration dialog box closes, and the action youve declared is saved and displayed
under the Actions header in the Catalog.
If you ever change your mind about the name, description, and/or parameters of a declared action, 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 Action 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 action in the Catalog using the Ctrl-T shortcut.
Tip #2: You dont necessarily have to create all of your action declarations manually. If an existing SimBionic project
contains action 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 actions, you must declare any predicates and behaviors used in your project. To learn how,
see the Declaring a predicate and Declaring a behavior topics.
Declaring a predicate
The primary building blocks of a SimBionic project are its actions and behaviors, which move execution forward.
However, your program must constantly gather information to determine if and when to trigger a particular action or
behavior. That data-gathering is performed by predicates.
More specifically, a predicate is a mini-program that probes the status of some aspect of your SimBionic programs
simulated world and then returns a value. Examples of predicates include checking whether a weapon has run out of
ammunition, checking whether an entity has messages waiting, reading a message, checking whether a behavior has
finished executing, etc.
A predicate consists of three basic components:

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

Working with the Catalog

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.

Right-click an AP module in the Catalog.


After you do so, a menu appears that includes an Insert Predicate option.

2.

Click the Insert Predicate option.


This Insert Predicate Declaration dialog box appears:

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

SimBionic User Guide

6.

Click the Insert button (directly below the Parameters box).


The following Insert Parameter dialog box appears:

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

Working with the Catalog

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.

Right-click the Actions header in the Catalog.


After you do so, a menu appears that includes a New Module option.

2.

Click the New Module option.


A new AP module named "Module" will be created in the Catalog, with its name selected.

3.

Type the name you want to give the AP module.


Hit Enter when youre done. Your new AP module is now complete.

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.

Click the Open button.


The dialog box closes, and any action and predicate declarations in the file that arent already present in
your current project are added to the Catalog under a new AP module heading. If any actions or predicates
from the imported file have the same name as those in your current project, you will be prompted to rename
them to avoid unwanted duplication.

4.

Use the imported actions and predicates.


The imported declarations will be identical to any you create manually.

25

SimBionic User Guide

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.

Right-click the Behaviors header in the Catalog.


Be sure to click using your right mouse button. After you do so, a menu appears that includes an Insert
Behavior option.

2.

Click the Insert Behavior option.


This Insert Behavior Declaration dialog box appears:

Working with the Catalog

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.

Click the Insert button (directly below the Parameters box).


The following Insert Parameter dialog box appears:

27

SimBionic User Guide

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.

10. 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.
11. Optionally repeat Steps 5-10 to create additional parameters.
Repeat this step until youve created all of the necessary parameters for your behavior. When youre done,
all the behaviors parameters are listed in the Parameters box.
12. Finally, you must specify how you want your behavior to execute by selecting its execution mode and
interruptibility. The default settings (multi-tick interruptible) will provide "normal" behavior execution.
13. Click the OK button of the Insert Behavior Declaration dialog box.
The Insert Behavior Declaration dialog box closes, and the behavior youve declared is saved and displayed
in alphabetical order under the Behaviors header in the Catalog.
If you ever change your mind about the name, description, execution mode, and/or parameters of a declared behavior,
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 Behavior Declaration dialog box. You can then revise the text in the Name
and/or Description boxes, and/or click a different execution mode.
You can also select any listed parameter by clicking it in the Parameters box. You can then click the Edit button to
revise the selected parameter; click the Up and Down buttons to reposition the parameter in the Parameters list; or
click the Delete button to permanently remove the parameter.
Tip #1: You can also create a new behavior in the Catalog using the Ctrl-I shortcut.

28

Working with the Catalog

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.

Setting the execution mode


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 its execution mode, follow these steps:
1.

Double-click the behaviors name in the Catalog.


An Edit Behavior Declaration dialog box appears that displays all of the behaviors settings. Notice that
execution mode options for run multi-tick, run in one tick, and run until blocked appear in the bottom of the
box.

2.

Click the behavior execution option you want.


A bullet appears to the left of the option to show that its been selected.

3.

Click the OK button.


Your change is saved. The next time you run your program, the behavior will execute based on the option
you selected.

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

SimBionic User Guide

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.

Double-click the behaviors name in the Catalog.


An Edit Behavior Declaration dialog box appears that displays all of the behaviors settings. Notice that the
interruptibility mode options appear in the bottom of the box.

2.

Click the interruptibility mode option you want.


A bullet appears to the left of the option to show that its been selected.

3.

Click the OK button.


Your change is saved. The next time you run your program, the behavior will execute based on the option
you selected.

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.

Right-click the Behaviors header in the Catalog.


Be sure to click using your right (not left) mouse button. After you do so, a menu appears that includes an
Import option.

2.

Click the Import option.


An Open dialog box appears that allows you to browse your hard disk or network for BTN files.

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.

Click the Open button.


The dialog box closes, and any behavior declarations in the file that arent already present in your current

Working with the Catalog

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.

Use the imported behaviors.


The imported declarations will be identical to any you create manually.

Managing Catalog Items


Renaming a Catalog item
If you arent satisfied with the name youve assigned a Catalog item, you can quickly rename it. The method you use
depends on what kind of item youre renaming.
To rename an action, predicate, behavior, global variable, constant, enumerated type or class, follow these steps:
1.

Double-click the item.


A dialog box appears with a Name text box at its top and the current name of the item highlighted.

2.

Type the new name.


Your new text replaces the old name.

3.

Click the OK button.


Your new name for the item is saved.

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.

Type the new name.


Your new text replaces the old name.

3.

Press Enter, or click anywhere outside the item.


Your new name for the item is saved.

Organizing Catalog items


If you have a number of items in the Catalog, its important that you organize them to eliminate clutter and enhance
clarity. You can do so by using folders, whichlike paper folderslet you order your items into conceptually related
groups.
To organize a Catalogs actions, predicates, behaviors, global variables, constants, enumerated type, or class using
folders, follow these steps:
1.

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.

Press Enter, or click anywhere outside the folder.


Your folder name is saved.
Tip: If you later change your mind, right-click the folder and select the Rename option to give your folder a
different name.

5.

Drag-and-drop each item you want to move into the folder.


That is, click each item and, while keeping your mouse button pressed, drag it until the folder is highlighted,
and then release your mouse button. The item is moved from its previous location into the folder. Repeat
this step until youve moved all pertinent items into the folder.
Alternatively, you can move multiple Catalog items at once by holding down the Ctrl or Shift key, selecting
the items you wish to move, and then dragging them into the folder.
Note: SimBionic does not support moving Catalog items via the Edit menus Cut and Paste commands, only
drag-and-drop.
Tip: If you later change your mind about any item youve moved, drag-and-drop the item from the current
folder to a different folder; or to the lists header (e.g., to the Actions header) if you want the item to reside
outside of any folder.

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

SimBionic User Guide

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.

Right-click on the parameter you wish to modify and select Edit.


In the Edit Parameter dialog box that appears, you can modify the name, type, binding, and description of
the parameter. When you are satisfied with your changes, click OK to save them. The Catalog will
automatically display the modifications to the parameter.

To delete a parameter from the Catalog, follow these steps.


1.

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.

Right-click on the parameter you wish to modify and select Delete.


The parameter will be deleted from the Catalog.
Note: this operation cannot be undone, so make sure that you really want to delete the parameter.

To reorder the parameters of an item in the Catalog, follow these steps.


1.

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

Working with the Canvas


What is the Canvas?
The Canvas is the large white drawing area on the right of SimBionics editor window that allows you to create your
programs visually.
There are five objects, or elements, you can place on the Canvas:

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

SimBionic User Guide

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

Working with the Canvas

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).

An expression that specifies the operation the action will perform.

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.

Creating an action rectangle


There are two ways to insert a new action rectangle on the Canvas. Which method you use depends on whether the
action has already been declared in the Catalog:

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.

Editing an action rectangle


After youve created an action on the Canvasthat is, inserted a rectangle to represent ityou typically need to edit
the actions expression. For example, if you dragged an action that requires parameters from the Catalog, you have to

35

SimBionic User Guide

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.

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 type Ctrl-E. You see an Edit Action Expression dialog box like this:

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

Working with the Canvas

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.

Click the OK button.


The Edit Action Expression dialog box closes, and the expression youve created is saved and displayed in
the action rectangle.

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

SimBionic User Guide

To learn how to create and edit invoked behaviors on the Canvas, read the next two sections.

Creating an invoked behavior


To create an invoked behavior on the Canvas, follow these steps:
1.

Locate the behavior in the Catalog.


The behavior must be declared in the Catalog before you can use it in another behavior. (If it hasnt been
declared, first follow the instructions in the Declaring a behavior topic.)

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:

If the behavior requires no parameters, then youre done.


If the behavior does require one or more parameters, however, then an asterisk appears within the
parentheses following its namee.g., FindBestPath(*)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.

Editing an invoked behavior


Many behaviors dont require parameters. In such cases, all you need to do to create an invoked behavior on the
Canvas is insert a rectangle to represent it.
If a behavior does require parameters, however, then you must additionally edit the behaviors rectangle and replace
the asterisk placeholder (in the parentheses following the behaviors name) with the appropriate parameters. To do so,
follow these steps:
1.

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:

Working with the Canvas

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.

Type a closing (right) parenthesis to complete the expression.


The Parameters box clears to indicate that youve finished creating the expression for your behavior.

39

SimBionic User Guide

6.

Click the OK button.


The Edit Behavior Expression dialog box closes; and the full name of the behavior, including all its
parameters, is saved and displayed in the behaviors rectangle.

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:

A compound action is made up of several components:

Two stacked rectangles (as opposed to a regular action, which appears on the Canvas as a single
rectangle).

A list of expressions consisting of any combination of the following three elements:

Actions to be executed,

Behaviors to be invoked, and

Variable bindings to be applied.

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.

Creating a compound action


To insert a new compound action on the canvas, right-click the blank area of the Canvas where you want to create the
compound action, and then click the Insert Compound Action option from the menu that appears. The new compound
action appears on the Canvas as a blank stacked rectangle, as shown here:

Tip: You can also use the Ctrl-M shortcut to create a new compound action on the Canvas.

40

Working with the Canvas

Adding an action or behavior expression


A new compound action starts off with an empty expression list, so you will probably want to add one or more
expressions to it. To add an action or behavior expression to a compound action, follow these steps:
1.

Right-click the compound action and select Edit Expression.


Alternatively, select the compound action and hit Ctrl-E. You will see an Edit Compound Action dialog box
like this one:

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.

Click the New Action button.


The Edit Action Expression dialog box will appear.

3.

Type the desired expression in the Expression box.


See Creating and editing actions on the Canvas for more on creating action expressions.

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.

Adding a variable binding


A compound action may have any number of variable bindings interspersed throughout its list of action and behavior
expressions. To add a variable binding to a compound action, follow these steps:
1.
2.

Right-click the compound action and select Edit Expression.


Alternatively, select the compound action and hit Ctrl-E. The Edit Compound Action dialog box will appear.
Click the New Binding button.
The Edit Binding dialog box will appear.

3.

Create the desired variable binding.

41

SimBionic User Guide

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.

Right-click the compound action and select Edit Expression.


Alternatively, select the compound action and hit Ctrl-E. The Edit Compound Action dialog box will appear.

2.

Click the expression you want to change in the Expressions list box.
The row is highlighted to show that its selected.

3.

Click the Edit button.


If you are editing an action or behavior expression, the Edit Action Expression dialog box will appear. If you
are editing a variable binding, the Edit Binding dialog box will appear.

4.

Edit the expression.


For more on editing expressions, see Creating and editing actions on the Canvas and Attaching bindings to
a Canvas element.

5.

When youre done editing the expression, click the OK button.


Your changes are saved; the first dialog box closes; and the edited expression is updated in the Edit
Compound Action dialog box.

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.

Right-click the compound action and select Edit Expression.


Alternatively, select the compound action and hit Ctrl-E. The Edit Compound Action dialog box will appear.

2.

Click the expression you want to eliminate.


The row is highlighted to indicate that its selected.

3.

Click the Delete button.


The expression is removed from the compound action and is no longer listed in the dialog box.

4.

Optionally repeat Steps 2-3 to delete any other expressions that have become obsolete.

5.

When youre finished deleting expressions, click the OK button.


Your changes are saved; the dialog box closes; and the expressions youve deleted are no longer displayed
within the compound action.

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.

Right-click the compound action and select Edit Expression.


Alternatively, select the compound action and hit Ctrl-E. The Edit Compound Action dialog box will appear.

2.

Click an expression you want to reposition in the list.


The row is highlighted to indicate that its selected.

Working with the Canvas

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.

Repeat Steps 2-4 for each expression you want to reorder.


When youre done, the dialog box lists the expressions in the order you want.

6.

Click the OK button.


Your changes are saved; the dialog box closes; and the expressions are displayed within the compound
action in the order you want.

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.

Move to the behavior whose initial rectangle you want to change.


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 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

SimBionic User Guide

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.

Therefore, a final action always looks like this:

To create one or more final actions, follow these steps:


1.

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.

Right-click a blank area of the Canvas.


Be sure to click using your right (not left) mouse button. After you do so, a menu appears that includes the
option Insert Action.

3.

Click the Insert Action option.


A new action is inserted with no expression (as indicated by the word None displayed inside it) and no
bindings (as indicated by no variable names displayed inside it).
Note: If this is the first rectangle youve created for the current behavior, then SimBionic automatically
makes it an initial rectangle and displays it as green. If this occurs, simply repeat Steps 2-3; any subsequent
actions you create will be normal None actions.

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.

Optionally repeat Steps 2-4 to create additional final actions.


Alternatively, you can make copies of the first final action you created. To learn how, see the Copying a
Canvas element topic.

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:

An oval that represents it on the Canvas.

An expression that specifies the test the condition will perform.

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

Working with the Canvas

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

SimBionic User Guide

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.

Creating a conditions oval


There are two ways to insert a new conditions oval on the Canvas. Which method you use depends on whether your
condition includes a predicate thats been declared in the Catalog:

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

Working with the Canvas

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

SimBionic User Guide

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.

Click the OK button.


The Edit Condition Expression dialog box closes, and the expression youve created is saved and displayed
in the conditions oval.

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

Working with the Canvas

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.

Changing a connectors shape


If you have many connectors coming out of and/or going into a rectangle, you may experience trouble distinguishing
them visually on the Canvas. To fix this, you can select a connector and then click one of the Connector toolbars two
Elbow buttons (to the right of the "A" button), as shown here:

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

SimBionic User Guide

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.

Right-click the connector you want to adjust.


A menu appears that includes a Set Priority option.

2.

Click the Set Priority option.


A submenu appears that displays the priority number assigned to each connector coming of your selected
connectors rectangle. The priority number assigned to your selected connector is indicated with a
checkmark.

3.

Click the priority number you want to assign the connector.


The connector is instantly reprioritized, as indicated by the number you selected now appearing next to the
connector on the Canvas.

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

Working with the Canvas

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).

Moving a Canvas element


You can move any Canvas elementi.e., behavior, action, condition, or connector by simply clicking it and, while
keeping your mouse button pressed, dragging the element to its new location and then releasing your mouse button.
This method is called clicking-and-dragging.
You can also move a group of Canvas elements at the same time. To do so, first hold down the Ctrl key and, while
keeping it pressed, click each element you want to include until all the relevant elements are selected. You can then
click any selected element and, while keeping your mouse button pressed, drag the entire group of elements to its new
location.
Clicking-and-dragging works fine as long as youre moving within the same window. If you want to move one or more
elements to a different Canvas window, however, you need to use the Cut command instead.
To move a single Canvas element to a different window, follow these steps:
1.

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

SimBionic User Guide

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).

Deleting a Canvas element


You can remove any Canvas elementi.e., behavior, action, condition, or connector by simply right-clicking it and
selecting the Delete option from the menu that appears. Alternatively, you can click the element to select it and then
press the Del key.
You can also remove a group of Canvas elements at the same time. To do so, first hold down the Ctrl key and, while
keeping it pressed, click each element you want to include until all the relevant elements are selected. You can then
press the Del key to eliminate the entire group of elements simultaneously.
If you change your mind directly after making a deletion, you can reverse your action by clicking the Edit menu and
selecting the Undo option, or by pressing Ctrl+Z. Your deleted element(s) will then reappear on the Canvas.
Searching the Canvas
If you need to locate 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 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 Find option that searches for any Catalog item or local variable you specify and then
displays a comprehensive list of every occurrence of the item in your project.
Alternatively, you can use the Find option to locate all instances of whatever text you specify, in which case SimBionic
will display a comprehensive list of every expression and binding in your project that contains the text.
The next two sections step you through using both search methods.

Searching for a variable, action, predicate, constant, or invoked behavior


To find all occurrences of a particular variable, action, predicate, constant, or invoked behavior youve placed on the
Canvas, follow these steps:

52

Working with the Canvas

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.

Right-click the item you want to search for on the Canvas.


Be sure to click using your right (not left) mouse button. After you click, a menu appears that includes a Find
option.

3.

Click the Find option.


Every occurrence of the item youve selected is listed in the Find pane of the Output window (near the
bottom of your SimBionic window).
For each listed item, the Find pane tells you the behavior in which it occurs; the polymorphism in which it
occurs (i.e., what descriptor(s) appear on the tab of the Canvas window that houses it); the name of the
item; and the parameters assigned to the item (if any).

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.

Review and/or edit the item, as needed.


The Find pane remains unaffected by any changes you make. However, you can always refresh the panes
results by repeating Step 2.

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.

Searching for text


To find occurrences of any text that appears in a behavior, follow these steps:
1.

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

SimBionic User Guide

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.

Click the Find button.


Every occurrence of the text youve entered fitting the matching criteria youve selected is listed in the Find
pane of the Output window (near the bottom of your SimBionic window).
For each listed item, the Find pane first tells you the behavior in which the text occurs and the polymorphism
in which it occurs (i.e., what descriptor(s) appear on the tab of the Canvas window housing the text). 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.

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.

Review and/or edit the item, as needed.


The Find pane remains unaffected by any changes you make. However, you can always refresh the panes
results by repeating Step 2.

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:

Working with the Canvas

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

SimBionic User Guide

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.

Click the Canvas element to select it.


For example, if you want to document an action on the Canvas, click the appropriate rectangle; while if you
want to document a condition, click the pertinent oval. After you do so, the element is highlighted to show its
been selected.

2.

Click the Standard toolbars Comment button.


That is, click the ninth icon below the menu bar, which looks like a pencil writing on a sheet of paper. An Edit
Comment dialog box appears.

3.

Type your comment.


The box will accept as much text as you care to write. However, only the first 190 characters or so will be
displayed onscreen, so its best to keep your comment relatively short. If you make a mistake, use the
Backspace or Del key to erase your error and then type the correct text.

4.

When youre done, click the OK button or press Enter.


Your comment is saved and attached to the Canvas element you selected.

Working with the Canvas

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.

Click the Canvas element to select it.


For example, if you want to place a reminder on an action on the Canvas, click the appropriate rectangle;
while if you want to place one on a condition, click the pertinent oval. After you do so, the element is
highlighted to show its been selected.

2.

Click the Standard toolbars Reminder button.


That is, click the tenth icon below the menu bar, which looks like a pencil writing on a blue sheet of paper.
An Edit Reminder dialog box appears.

3.

Type your reminder.


The box will accept as much text as you care to write. However, only the first 190 characters or so will be
displayed onscreen, so its best to keep your reminder relatively short. If you make a mistake, use the
Backspace or Del key to erase your error and then type the correct text.

4.

When youre done, click the OK button or press Enter.


Your reminder is saved and attached to the Canvas element you selected. If the element is a rectangle or
condition, a small blue square will appear on the right-hand side of the rectangle or condition to indicate that
a reminder is present.

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

SimBionic User Guide

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.

Click the Connector toolbars A button.


That is, click the fifth button from the right (which looks like the letter "A") on the second toolbar from the
top.

2.

Click the spot on the Canvas where you want to place the description.
A text box appears.

3.

Type your description into the text box.


The box will accept as much text as you care to write. You can also press Enter to create new lines. If you
make a mistake, use the Backspace or Del key to erase your error and then type the correct text.
You can also paste text into the text box by typing Ctrl-V or by right-clicking in the text box and selecting
Paste.

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

Working with Variables


Understanding variables
A variable is a named area in memory into which you can store, or assign, a value. Variables are invaluable tools for
holding bits of data until you need them.
Technically, you can name a variable anything you want. However, to ensure that your program code will be easily
understood by other members of your development teamor, for that matter, yourself several months after youve
written ityour should give each variable a name that clearly identifies the information its designed to hold.
SimBionic supports two basic kinds of variables: local and global.
Local variables
A local variable is affected only by the operations that occur within a single behavior of an entity (i.e., is local to that
behavior). The vast majority of variables youre likely to create are local, because they allow you to focus on whats
happening in a particular behavior without having to worry that some operation in a different behavior might change
the variables value without your realizing it.
For example, if you created a local variable named Hero_Location in Behavior A and another local variable named
Hero_Location in Behavior B, any value you assigned to Hero_Location in Behavior A would have no effect on the
contents of Hero_Location in Behavior B, and vice versa.
You can examine and edit the variables youve created for a particular behavior at any time by displaying the behavior
on the Canvas and then clicking the Locals button in the upper-right of your SimBionic window. After you do so, a
dialog box like this appears:

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

SimBionic User Guide

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

Working with Variables

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

"My name is " + "Bond."

would result in the string value

"My name is Bond."

In addition, you can compare strings. For example, the expression

"My name is " + "Bond." == "My name is Bond."

would evaluate as true.


Note: A backslash followed by certain characters has special meaning within a string. These characters and their
meanings are as follows:

\\

represents a single backslash within a string

\"

represents a double quote within a string

\t

represents a tab character within a string

\n

represents a newline character within a string

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

[1, -3, 2] + [3, 3, 3]

would result in the vector

[4, 0, 5]

You can also perform multiplication with vectors. For example, either of the expressions

[1, -3, 2] * [3, 3, 3] or [1, -3, 2] * 3

would result in the vector

[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

SimBionic User Guide

(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

Working with Variables

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):

var: any [in]

It returns a value of data type Boolean.


For example, if you wanted to check on whether a valid value was received when an entity requested information from
a blackboard named Target_Locations and a section of the board named Enemy_Headquarters, you could declare a
variable X of the same type as the data in Enemy_Headquarters, and then include the following two expressions as
part of your program:
X=ReadBBoard("Target_Locations", "Enemy_Headquarters")
IsValid(X)
If all went well, ReadBBoard would return whatever information was stored in the Enemy_Headquarters section of the
Target_Locations blackboard, and IsValid would return a value of true. On the other hand, if the blackboard
Target_Locations and/or its section Enemy_Headquarters didnt actually exist, ReadBBoard would return a value of
invalid, and IsValid would return a value of false.
Its recommended that you always check for errors by using IsValid directly following the use of a predicate that can
potentially return an invalid value.
For more information on creating customized actions and predicates, see the Coding actions in C++ and Coding
predicates in C++ topics, or the Coding actions in Java and Coding predicates in Java topics,
Creating and Editing Variables
Creating and editing local variables
If youve read the Understanding variables and Choosing a data type topics, youre now ready to create, review, edit,
delete, and reposition local variables. The following four sections tell you how.

Creating local variables


To create one or more local variables, follow these steps:
1.

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

SimBionic User Guide

Notice that the box starts out empty except for a Locals header.
3.

Right-click the Locals header.


Be sure to click using your right (not left) mouse button. After you do so, an Insert Local option pops up.

4.

Click the Insert Local option.


You see this Insert Local dialog box:

Notice that the dialog box contains options for naming and describing your variable and selecting its data
type.

64

5.

Type the name for your variable in the Name box.


To ensure the readability of your program code, give the variable a name that clearly describes the kind of
data youll be using it to store (e.g., Health_Rating, Bullets_Left, HQ_Location).

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.

Working with Variables

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.

Click the OK button.


The variable is created, and is displayed in the Local Variables palette in alphabetical order with the name
and data type you specified.

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.

Reviewing and editing local variables


After youve created your local variables, you can view and optionally revise them at any time. To do so, follow these
steps:
1.

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.

Double-click a local variable that youd like to revise.


An Edit Local dialog box appears that allows you to revise the variables name and data type.

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.

Deleting local variables


If a local variable ever becomes obsolete, you can delete it. To do so, follow these steps:
1.

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.

Right-click a local variable you want to eliminate.


A menu pops up that includes Find and Delete options.

4.

Click the Find option.


Every occurrence of the variable in the current behavior is listed in the Find pane of the Output window (near
the bottom of your SimBionic window).

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.

Click the Delete option.


The variable is removed from the Local Variables palette and is no longer associated with the behavior.

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.

Creating global variables

65

SimBionic User Guide

To create one or more global variables, follow these steps:


1.

Right-click the Globals header in the Catalog.


Be sure to click using your right (not left) mouse button. After you do so, an Insert Global option appears.

2.

Click the Insert Global option.


You see this Insert Global dialog box:

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.

Type the name for your variable in the Name box.


To ensure the readability of your program code, give the variable a name that clearly describes the kind of
data youll be storing in it. Also, to make it easy for you to distinguish global from local variables in your
program code, its a good idea to place the letter g in front of the name (e.g., gHero, gVillain,
gHealth_Rating).

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

Click the OK button.


Your variable is created, and is displayed under the Globals header in alphabetical order with the name and
data type you specified.

Working with Variables

8.

Optionally repeat Steps 1-7 to create additional global variables.

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.

Editing global variables


If you change your mind about any decisions youve made regarding your global variables, you can revise them
quickly and easily. (The only exceptions are the special variables in the Polymorphic folder, which must be changed
via the Descriptors pane; for more information, see the Creating and revising descriptors topics.)
To edit one or more global variables, follow these steps:
1.

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.

Double-click a global variable that youd like to revise.


An Edit Global dialog box appears that allows you to revise the variables name, its data type, and (if the
data type is integer, float, string, vector, boolean, array, or table) its initial value.

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.

Optionally repeat Steps 2-7 to revise additional global variables.

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.

Right-click the Constants header in the Catalog.


After you do so, an Insert Constant option appears.

2.

Click the Insert Constant option.


You see an Insert Constant dialog box like this:

67

SimBionic User Guide

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.

Type the name for your constant in the Name box.


To ensure the readability of your program code, give the constant a name that clearly describes the value
youll be assigning to it.

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.

Click the OK button.


Your constant is created, and is displayed under the Constants header in alphabetical order with the name
and data type you specified.

8.

Optionally repeat Steps 1-7 to create additional constants.

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.

Double-click a constant that youd like to revise.


An Edit Constant dialog box appears that allows you to revise the constants name, data type, and value.

Working with Variables

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.

Optionally click in the Value box and change the value.

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.

Optionally repeat Steps 2-7 to revise additional constants.

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.

Right-click on the Constants header in the Catalog.


After you do, an Import Constants option will be displayed.

7.

Select the Import Constants option.


An Open dialog box appears that allows you to browse your hard disk or network for constant definition files.

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.

Click the Open button.


The dialog box closes, and the constants in the specified file will be imported into SimBionic. They may then
be used like any other constant.

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"

% The next line specifies the number of days in a year.


daysInYear

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.

50/NumMembers("GoodGuys"): This expression consists of a number (50); the built-in predicate


NumMembers, which returns a value of data type integer; the string parameter "GoodGuys" that specifies
which group membership should be counted; and the operator for division. If the group "GoodGuys" contains
10 members, then the NumMembers predicate returns a value of 10 and 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

SimBionic User Guide

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.

There are several areas in SimBionic where you create expressions.


First, you can create an expression that results in a value to be assigned, or bound to, a variable. Such a binding can
be used to create an initial value for a global variable; for more information, see the Creating and editing global
variables topic.
You can also create and attach an unlimited number of bindings to any Canvas element, which allows you to set
values for variables at any point during your programs execution. For more information, see the Attaching bindings to
a Canvas element topic.
Most importantly, you can assign predicate expressions to conditions and action expressions to actions on the
Canvas. In fact, this is what much of your programming work will consist of, because this is your primary method of
instructing SimBionic to test the status of your virtual world and then act upon it appropriately. You can assign just one
expression per condition or action on the Canvas. (Alternatively, you can assign no expression, in which case the
condition or action will do nothing except execute whatever bindings youve attached to it; or, in the case of a final
action, end the current behavior.) To learn more, see the Creating and editing actions on the Canvas and Creating and
editing conditions topics.
Using operators in expressions
When creating expressions in SimBionic, you can use standard C++ operators, following C++ rules for operator
precedence, relations and associativitye.g., operators are evaluated left to right, expressions within parentheses are
evaluated before expressions outside parentheses, operators with higher precedence are evaluated before those with
lower precedence, and so on. (These rules are identical for Java expressions.)
For example, the expression 3 - 2 + 5 would evaluate as 6, while the expression 3 - (2 + 5) would evaluate as -4. On
the other hand, the expression 2 + 3 * 5 and the expression 2 + (3 * 5) would both return a result of 17, because
multiplication has precedence over addition.
SimBionic also supports Boolean expressions. For example, if you wanted to create an expression in which both
variables X and Y must be true, youd use the double ampersand operatorX&&Yto "and" the variables. The result
would either be true or false.
Below are SimBionics operators, listed in order of precedence (with those grouped together having the same
precedence). Each operator is followed by the key you type to enter it; its function; the data types on which it operates
(aside from array and table, which dont support mathematical operations, and any, which encompasses all data
types); and examples of its use:

. (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.

Working with Variables

% (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

SimBionic User Guide

?: (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

Working with Variables

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.

To attach one or more bindings to a Canvas element, follow these steps:


1.

Right-click the Canvas element.


Be sure to click using your right mouse button. After you do so, a menu pops up that includes the option Edit
Bindings. Alternatively, select the Canvas element and hit Ctrl-B.

2.

Click the Edit Bindings option.


You see this Edit Bindings dialog box:

Notice that the dialog box includes a button for inserting (i.e., creating and attaching) a new binding.
3.

Click the Insert button.


You see this second Edit Bindings dialog box:

73

SimBionic User Guide

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

Working with Variables

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.

Click the OK button.


The second dialog box closes, and the binding youve created is listed in the first dialog box.

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.

When youre done creating bindings, click the OK button.


The first dialog box closes; and each variable youve specified to be assigned a value is displayed within the
Canvas element (for a rectangle or oval) or next to the Canvas element (for a line).

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.

Right-click the Canvas element.


Be sure to click using your right mouse button. After you do so, a menu pops up that includes the option Edit
Bindings. Alternatively, select the Canvas element and hit Ctrl-B.

2.

Click the Edit Bindings option.


You see an Edit Bindings dialog box like this one:

75

SimBionic User Guide

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.

Click the binding you want to change.


The binding is highlighted to show that its selected.

4.

Click the Edit button.


You see an Edit Binding dialog box like this one:

Working with Variables

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

SimBionic User Guide

7.

When youre done editing the binding, click the OK button.


The second dialog box closes, and the revised binding youve created is listed in the first dialog box.

8.

Optionally repeat Steps 3-7 to edit any other listed bindings.

9.

When youre done editing bindings, click the OK button.


Your changes are saved; the first dialog box closes; and each variable youve specified to be assigned a
value is displayed within the Canvas element (for a rectangle or oval) or next to the Canvas element (for a
line).

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.

Click a binding you want to eliminate.


The binding is highlighted to indicate that its selected.

3.

Click the Delete button.


The binding is removed from the Canvas element and is no longer listed in the dialog box.

4.

Optionally repeat Steps 2-3 to delete any other bindings that have become obsolete.

5.

When youre finished deleting bindings, click the OK button.


Your changes are saved; the dialog box closes; and the variables for the bindings youve deleted are no
longer displayed within or next to the Canvas element.

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.

Click a binding you want to reposition in the list.


The binding is highlighted to indicate that its selected.

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.

Repeat Steps 2-4 for each binding you want to reorder.


When youre done, the dialog box lists the bindings in the order you want.

6.

Click the OK button.


Your changes are saved; the dialog box closes; and the bound variables are displayed within or next to the
Canvas element in the order you want.

Using Arrays and Tables


Using arrays
One of the most fundamental data structures in programming is the array, which is used to store a series of
conceptually related data elements (e.g., a entitys name, strength level, intelligence level, health level, etc.). In
SimBionic, the elements can be any combination of data types, including other arrays (i.e., you can have sub-arrays
within a parent array). You can access any element by referring to its position in the array.
You can set a parameter or variable to handle an array by declaring it to be an array data type. (For more information,
see the Choosing a data type topic.)
Tip: When youre creating a global array or a binding on an array variable, SimBionic provides a dialog box that makes
it easy for you to enter the arrays initial values. To learn more, see the Editing arrays topic.
After creating an array, you can manipulate it via SimBionics built-in array 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 Arrays (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 arrays are as follows:

78

Working with Variables

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

SimBionic User Guide

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.

Working with Variables

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

SimBionic User Guide

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

Working with Variables

To create a new enumerated type in the Catalog, follow these steps:


1.

Right-click on the Types header in the Catalog.


After you do so, a menu appears that includes an Insert Enum Type option.

2.

Click the Insert Enum Type option.


This Insert Enumerated Type dialog box appears:

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.

Click the Insert button to add a value.


A new row will be added to the Values list box, with the Name field selected.

7.

Type the name you want to give the value.


To ensure the readability of your program, enter a name that clearly describes the value (e.g., winter,
purple).

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.

Optionally repeat Steps 6-8 to create additional values.


Repeat this step until youve created all of the necessary values for your enumerated type.

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

SimBionic User Guide

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

Working with Descriptors


Understanding descriptors
A descriptor is an identifier or attribute describing the possible state of an entity. You can associate descriptors with
behaviors to define polymorphisms. A descriptor can a physical or mental attribute of an entity such as happy, sad,
healthy, armed, or hungry. It can also refer to the fundamental characteristics of an entity, such as its type (e.g.,
Toyota, Honda, Ford), its role on a team (e.g., leader, scout, medic) or its nationality (e.g., Russian, Australian,
American).
You create descriptors via the Descriptors pane of the SimBionic editor, as shown here:

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

SimBionic User Guide

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

Working with Descriptors

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

SimBionic User Guide

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

Click the Descriptors tab in the Project window.


The Descriptors tab is on the left side of the SimBionic editor window (directly to the right of the Catalog tab).
After you click, you see a Descriptors pane like this:

Working with Descriptors

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.

Click the Insert Descriptor Category option.


A first-level descriptor category is added with the temporary name New Descriptor Category. The name is
highlighted, indicating that whatever you type will replace it.

89

SimBionic User Guide

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.

Creating lower-level descriptors


After youve created your first-level descriptor categories, youre ready to add specific descriptors to each category.
Note: You can add descriptors to any descriptor, not just those on the first level. The lower the level of a descriptor,
the most specific it should bee.g., if the first level of a category is TV_Shows, a second-level descriptor could be
Sitcoms, a third-level descriptor could be Friends, and a fourth level descriptor could be Friends_Episode_86.
SimBionics run-time engine will search for behaviors starting with the lowest level (i.e., most specific) descriptors of a
category and, if no matches are found, then work its way up to higher (i.e., more generic) levels.
To create lower-level descriptors, follow these steps:
1.

Right-click the descriptor to which you want to add a descriptor.


A menu appears that includes an Insert Descriptor option.

2.

Click the Insert Descriptor option.


A descriptor is added one level below your selected descriptor (as indicated by it appearing below the
selected descriptor and indented to the right) and given the temporary name New Descriptor. The name is
highlighted, which means that whatever you type will replace it.

3.

Type the name you want to give your new descriptor.


To ensure the readability of your program, choose a name that clearly represents the entity or attribute to
which the descriptor refers.

4.

Press Enter, or click anywhere outside the name youve just typed.
Your descriptor is created with the name you specified.

5.

If you want to create additional lower-level descriptors, repeat Steps 1-4.


Theres no limit to the number of descriptors you can create, so add as many as makes sense for your
particular project

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.

Right-click the descriptor.


A menu appears that includes a Rename option.

2.

Click the Rename option.


The descriptors name is highlighted.

3.

Type the new name you want to give the descriptor.


What you type replaces the previous text.

4.

Press Enter, or click anywhere outside the name.


The descriptor is listed with the new name you specified.

5.

If you want to rename additional descriptors, repeat Steps 1-4.

Deleting descriptors
If an descriptor becomes obsolete, you can remove it with a couple of mouse clicks. To do so, follow these steps:
1.

Right-click the descriptor.


A menu appears that includes a Delete option.

2.

Click the Delete option.


The descriptor is eliminated. In addition, any descriptors at lower levels in the descriptors hierarchy are also
removede.g., if you delete a first-level category, both the category and all the descriptors within the
category are deleted.

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

Working with Descriptors

1.

Right-click the descriptor you want to reposition.


A menu appears that includes Move Up and Move Down options.

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.

Repeat Steps 1-3 for each descriptor you want to reposition.


When youre done, each level displays its descriptors in the order you want.

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.

Right-click the tab at the bottom of the Canvas.


Be sure to click using your right mouse button. After you do so, a menu appears that includes a Duplicate
Polymorphism option.

4.

Click the Duplicate Polymorphism option.


Another page is added to the Canvas, as indicated by another tab appearing in the Canvas area. (You can
switch among pages by clicking their respective tabs.) Notice that the tab of your new page starts off with
the names of your top-level descriptor categories. This new page will have the exact same Canvas elements
as the original behavior.

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.

Understanding the execution stack


A stack is a data structure in which the last item added is the first one removed (similar to the way you always first
wash the top dish from a stack of dirty dishes). Stacks are typically used in programs that employ procedure
structures, because a stack enables the program to invoke a procedure, discard or pop the procedure when the
procedure has completed executing, and then resume execution at the point where the program left off before invoking
the procedure.
In SimBionic, when an entity kicks off its initial behavior, all the pertinent data related to that behavior is placed, or
pushed, on the execution stack as an object called an execution frame. If that behavior then invokes another behavior,
the second behavior is pushed on the stack as a second execution frame. If the second behavior also invokes a
behavior, that third behavior is pushed on the stack as a third execution frame; and so on.
When the top behavior is completed (i.e., has reached a final action), SimBionic will pop it off the stack and return to
where it left off in the previous, invoking behaviorwhich then becomes the top execution frame. The new top
behavior will then continue executing until its also completed and poppedunless it invokes another behavior before
completion, in which case the new invoked behavior gets pushed on the stackand so on. This cycle can continue
until all behaviors are popped from the stack (in which case the entitys activities terminate); or it may continually
fluctuate between pushing and popping behaviors, depending on how your program is written.
One other way an execution frame can be popped is if a behavior below it is aborted. For example, assume Behavior
A invokes Behavior B, Behavior B invokes Behavior C, and Behavior C invokes Behavior D meaning Behavior D is
currently at the top of the stack. However, during every clock tick, SimBionic evaluates the connectors coming out of
every behavior on the stack, not just the top one. So if, say, Behavior B has a connector coming out of it that suddenly
evaluates as true, execution will immediately flow out of Behavior B to the new rectangle (i.e., invoked behavior or
action) at the other end of the connector. In addition (assuming the connector isnt an interrupt), Behavior B will be
popped from the stackand so will all the behaviors it invoked. As a result, SimBionic will pop Behaviors B, C, and D
simultaneously. (Further, if the rectangle on the other side of the connector happens to be a behavior, it will then take
Behavior Bs place on the stack)
Typical flow of execution
The run-time engine typically moves forward an entitys behavior one action every clock ticka tick being an artificial
measure of time the engine uses to designate update periods. (The actual time required to execute a clock tick in the
run-time engine varies depending upon the number of entities in your program, the complexity of their behaviors, and
the complexity of your action and predicate code.)
When an entity is updated, the engine starts by executing the bindings (if any) attached to the current rectangle of the
topmost behavior on the entitys execution stack; and then executes the current rectangle itself (which well call
rectangle A).
If the rectangle is an action, the engine simply executes the action.
If the rectangle is an invoked behavior, then the engine pushes that behavior onto the stack and sets the current
rectangle for the newly-invoked behavior to be its initial rectangle.
The engine then evaluates the connectors coming out of rectangle A in order of priority (see the Changing a
connector's priority topic). What the engine does next depends on the circumstances:

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

SimBionic User Guide

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

SimBionic User Guide

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.

Open the project you want to compile.


For example, press Ctrl+O, and locate and double-click the project file via the Open dialog box. Your project
appears in the SimBionic editor.
SimBionics default is to save your compiled project file with the same name and in the same folder as your
project. (Package files will also be saved in this location.) If this is what you want, then you dont need to
specify your project files name and folder location and can skip to Step 9. Otherwise, proceed to Step 2.

2.

96

Click the Build menu and select Project Settings.


A Project Settings dialog box like this appears:

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

SimBionic User Guide

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.

Optionally turn off the display of compile warnings.


By default, the editor will display all warnings and errors generated during the compilation process. If you
wish to ignore the warnings (perhaps because you would like to deal with the critical errors first), you can
turn them off by checking the Suppress Compile Warnings checkbox. If you later decide you want to see the
warnings, you can always turn them back on by clearing this checkbox.

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.

Files generated by SimBionic


When you save a project in the SimBionic editor, you automatically generate four types of files with the following
extensions:

.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.

Debugging your Project


Debugging your project
After youve compiled your behaviors (as described in the Compiling your project topic), you can test out your
compiled project file by executing it via the run-time engine. If no problems appear, then youre set.

99

SimBionic User Guide

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.

Open the project you want to debug.


For example, press Ctrl+O, and locate and double-click the project file via the Open dialog box. Your project
appears in the SimBionic editor.

2.

Click the Build menu and select Project Settings.


A Project Settings dialog box appears. Select the Debug tab, which looks like this:

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.

Enabling debugging for your application


Before you can use the interactive debugger, you must first enable debugging in your application by following these
steps:
1.

Enable debugging mode for the SimBionic run-time engine.


You must do this before calling the Initialize API method to start up the engine. To enable debugging, set
debugEnabled = true in the AI_Config or SB_Config object that you pass to the run-time engine during
initialization.

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

Using the debugger


When the interactive debugger is activated, the Project window is replaced with an Entities window, and the Output
window is replaced with the Execution Stack and Variables windows. (You can also optionally bring up a Breakpoint
List window.)
In addition, a Debug toolbar is added that contains debugging commands; and the Build menu is replaced with a
Debug menu. As a result, you see a debugging window like this:

101

SimBionic User Guide

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.

Execution stack window


The Execution Stack window in the interactive debugger is a visual representation of the execution stack that
SimBionics run-time engine has assigned to the entity that is currently selected in the Entities window. (Every entity is
automatically assigned its own individual stack to track its particular behaviors.)
Every behavior thats run for the entity is implemented by an execution frame that the engine pushes onto the entitys
stack. Therefore, this window devotes a row to each execution frame, and provides data about the frame via the
following five columns:

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.

For more information, see the Understanding variables topic.

103

SimBionic User Guide

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.)

Setting and removing breakpoints


The SimBionic editor provides several ways to set or clear breakpoints.

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

Exploring the sample Pac-Man program


To help show you how to create programs using SimBionic, weve included a demonstration program modeled after
Namcos classic Pac-Man arcade game. Our instructional version of Pac-Man is driven by a few relatively simple
behaviors created using SimBionic. We then completed the game via C++ code to provide the sound, graphics, user
interface, and hooks to SimBionics engine.
Although SimBionic is capable of creating the AI, or "brains," of much more complex simulations, we chose Pac-Man
for our demo because virtually everyone is already familiar with how this game operates; and because the lessons you
learn from creating a relatively simple game are the same ones you need to master for larger projects.
Note: This topic assumes that youre already familiar with the basic concepts involved in creating SimBionic projects. If
anything mentioned isnt clear to you, locate the topic that covers it via the Understanding SimBionic topic or this Help
systems Index pane.

Playing the sample game


To experience the sample Pac-Man game, follow these steps:
1.

Launch the game by locating and double-clicking program file PacMan.exe.


The file is stored within your SimBionic folder. After you double-click, an instructional version of Namcos
classic Pac-Man game appears.

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.

Press the F key, and then continue playing.


The game identifies Pac-Mans potential new directions, based on the direction hes currently facing. You
can toggle this display off by pressing the F key again.

5.

Press the T key, and then continue playing.


The game identifies the directions from which Pac-Man is fleeing (i.e., his trailing paths). You can toggle this
display off by pressing the T key again.

6.

Press the 1 key, and then continue playing.


The game identifies Blinkys most likely path for trying to trap Pac-Man, which can change from moment to
moment based on Pac-Mans movement and Blinkys current location. You can toggle this display off by
pressing the 1 key again.

7.

Press 2, 3, and 4 keys in turn, and then continue playing.


The game identifies the most likely paths at any given moment for Pinky, Inky, and Clyde.

8.

Complete the game (or simply press P to pause it).


With the action ended, take some time to more carefully consider what youve just seen.

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.

Identifying the sample games entities


The first thing you should typically do when designing the AI for any simulation or game is identify the AI entities to
which youll be assigning behaviors.
At first blush, you might think the title character of the game belongs at the top of this list. However, all of Pac-Mans
decisions are made by the human player, not AI. As a result, Pac-Man can be handled entirely by the C++ code of the
game, which reads the input from the keyboard and then generates the appropriate graphics to reflect the players
keystrokes. So while youll be extremely interested in Pac-Mans location and direction at any given moment, we dont
recommend including him as an entity in your SimBionic project.
In contrast, the four ghostsBlinky, Pinky, Inky, and Clydeare very much AI entities. Their movement decisions are
driven by the "brains" of the program, not a human player; and they exhibit dynamic behavior, responding to changing
conditions on a moment-by-moment basis and in somewhat unpredictable ways.
Further, the bouncing fruit, although its not a "character" in the dramatic sense, also exhibits dynamic behavior (e.g.,
its movements vary in unpredictable ways depending on the games conditions), and so is every bit as much an entity
as the ghosts.

105

SimBionic User Guide

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.

Exploring the sample Main behavior


Now that youve identified the entities in the game, think again about the behaviors youll need to create for these
entities to make Pac-Man operate properly; and also think about the actions and predicates youd need to build these
behaviors.
When youre ready, launch the SimBionic editor, press Ctrl+O to open an existing project, and locate and double-click
the project named PacMan.sbp. After you do so, you should see the following Main behavior on the Canvas:

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.)

Exploring the sample invoked behaviors


As youve just seen, the sample Main behavior invokes another behavior called PickDirection. If you either hold down
the Ctrl key while double-clicking PickDirections rectangle, or double-click PickDirection in the Catalog, the Main
behavior is replaced on the Canvas with this behavior, which has been declared to run in one tick:

107

SimBionic User Guide

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

SimBionic User Guide

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

SimBionic User Guide

#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

int main(int argc, char* argv[])


{
// create the interface to SimBionic
HelloWorldInterface* bfInterface = new HelloWorldInterface();
// set configuration parameters for the engine
AI_Config* config = new AI_Config();
config->behaviorFilename = "HelloWorld.sim";
// create an instance of the engine
AI_Engine engine;
// attempt to load and initialize the engine
EAI_Err errCode = engine.Initialize(bfInterface, config);
if (errCode != kOK)
{
if (errCode == kNoDLL)
printf("Failed to load SimBionic DLL.\n");
else
printf("Initialization error: %s\n",engine.GetLastError());
return -1;
}
// create an entity
AI_Entity friendlyGuy = engine.MakeEntity( "Friendly Guy" );
if (friendlyGuy == INVALID_ID)
{
printf("Entity creation error: %s\n", engine.GetLastError());
return -1;
}
// set Friendly Guy's initial behavior
errCode = engine.SetBehavior(friendlyGuy, "Main", AI_ParamVec());
if (errCode != kOK)
{
printf("Error setting behavior: %s\n", engine.GetLastError());
return -1;
}
// update the entity several times
for (int tick=0; tick < 5; tick++)
{
if (engine.Update() != kOK)
{
printf("Update error: %s\n", engine.GetLastError());
return -1;
}

113

SimBionic User Guide

}
// 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

Using Advanced Features


Exporting XML
SimBionic has the ability to export your entire project as an XML document. The resulting document can be displayed
in any XML viewing program (e.g., Internet Explorer) or read by any standard XML parser. Note that while SimBionic
currently does not have the ability to load a project from XML, this capability might be provided in future versions.
To export your project in XML, follow these steps:
1.

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.

Specify the folder and filename for your header file.


For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.

4.

Click Save.
The XML file is saved in the folder and under the name you specified.

Creating HTML documentation


When working on a large project or a project with many developers, it is crucial to carefully document your work. Good
documentation makes it easier for other people to understand the behaviors that youve created; it also can remind
you later on why you did things the way you did. Unfortunately, writing documentation can often be tedious and timeconsuming. SimBionic thus provides the ability to automatically generate comprehensive hyperlinked HTML
documentation for a project. This documentation includes every Catalog item, descriptor, and behavior that youve
created for your project, along with their descriptions. It also includes hyperlinked images of each polymorphism.
To export HTML documentation for your project, follow these steps:
1.

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.

Working with multiple authors


On a large project, you may wish to have several developers working with SimBionic at the same time. The SimBionic
editor has several features designed to support simultaneous multi-user development within a single project:

Each behavior is stored in a separate .BTN file.


This means that each individual behavior can be placed under source-code control so that only the
developer responsible for that behavior can modify it.

Action and predicate declarations are stored in a separate .APD file.


Thus, the programmers who are implementing the actions and predicates for your project can update the
action and predicate declarations without getting a lock on the entire project.

The editor automatically checks for updated behavior files.


You can update your project files from the source-code repository while the editor is running and SimBionic
will automatically detect any modified behaviors and ask if you wish to reload them.

Read-only files cannot be modified in the editor.


This means that you can load and view files that are currently locked for editing by other developers without
worrying about accidentally changing them. The editor automatically detects if the read-only status of a
behavior file changes and will allow or disallow editing accordingly.

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

SimBionic User Guide

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:

Using Advanced Features

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

SimBionic User Guide

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.

For example, suppose you create four entities:

A has update frequency 0 and update priority 3.

B has update frequency 0 and update priority 2.

C has update frequency 1 and update priority 1.

D has update frequency 1 and update priority 4.

The run-time engines scheduler will schedule these entities as follows:

Clock tick 1: entity C, then entity B, then entity A

Clock tick 2: entity B, then entity A, then entity D

Clock tick 3: entity C, then entity B, then entity A

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

Using Advanced Features

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:

Sharing any information of type data.

Storing information that can be accessed by any number of entities at any time.

Storing information that must be remain available indefinitely.

Having the option of instantly and completely destroying all of a boards stored information.

119

SimBionic User Guide

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")).

Using Advanced Features

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:

Sending messages of any data type.

Sending messages directly to a group of entities.

Sharing information rapidly among a group of entities.

Sharing information rapidly between two or more groups of entities.

Restricting messages to a select group.

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

SimBionic User Guide

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.)

Compiled project and package files


Once you have created one or more packages in your project, compiling your project (as described in the Compiling
your project topic) will generate multiple files:

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.

Starting the run-time engine


Using dynamic behavior loading does not require any changes to the normal method of starting up the run-time engine
from your code. You still need to specify the compiled project file to be loaded by the engine; you do not need to
specify any package files at startup. When you call the Initialize API method, the run-time engine will load all action,
predicate, descriptor, and global variable declarations from the compiled project file. It will also load any behaviors not
contained in any package.

Loading a behavior package


Once the run-time engine is running in your application, you can direct it to load a package file using the LoadPackage
and LoadPackageFile API methods. The engine will load the behaviors in the file, which can then be invoked just like a
behavior that was loaded on startup.
Note: You should be careful not to load a package again after you have already loaded it. This may cause undesirable
results. You can, however, reload a package after unloading it.

Unloading a behavior package


When you no longer need the behaviors in a particular package, you can direct the run-time engine to unload that
package to free up memory. To do so, use the UnloadPackage API method. Alternatively, if you wish to unload all
currently-loaded behaviors at once, you can use the UnloadAll API method. Note that this method will also unload any
behaviors that were loaded from the compiled project file on startup.
Working with behavior packages
By default, a SimBionic project contains no behavior packages, and thus all of the behaviors in your project are stored
in your compiled project file. If you want to take advantage of SimBionics dynamic behavior loading capability in your
application, however, you will need to create one or more behavior packages. There are two ways to do this: you can
choose to automatically place each behavior in its own package, or you can manually group your behaviors into a set
of packages that you specify.
To assign each behavior to its own package, follow these steps:
1.

122

Select the Build menu and then select Project Settings.


The Project Settings dialog box appears. It looks like this.

Using Advanced Features

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).

To manually assign behaviors to packages, follow these steps:


1.

Select the Build menu and then select Project Settings.


The Project Settings dialog box appears.

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.

Click the Packaging button.


The Behavior Packaging dialog appears:

123

SimBionic User Guide

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:

Using Advanced Features

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

SimBionic User Guide

The always rectangle enables you to ensure that certain actions are always executed at a behaviors
termination. See The always rectangle for details.

The catch rectangle


The heart of SimBionics error-handling facility is the catch rectangle. A catch rectangle in a behavior can "catch" an
exception thrown by any action or predicate in that behavior, much like the catch block of a try-catch statement in
Java. When an exception is thrown during the execution of a behavior containing a catch rectangle, the catch
rectangle becomes the current rectangle for that behavior, and the execution mode for the behavior is set temporarily
to non-interruptible (because error recovery should be treated as a critical section). Execution continues normally from
that point, executing the catch rectangle and any subsequent rectangles (also known as a catch block). Typically the
catch block is used to log and possibly clean up after the error, but you can do whatever you wish there.
A catch rectangle is depicted as a blue-shaded rectangle on the Canvas:

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.

Creating and removing catch rectangles


To turn an existing rectangle into a catch rectangle, right-click on the desired rectangle and select the Catch option
from the pop-up menu. The rectangle will be shaded blue to indicate its new catch status. If the behavior already
contains a catch rectangle, then that rectangle will turn white to indicate that it is no longer a catch rectangle.
To remove a catch rectangle from a behavior, right-click on the rectangle and select the Catch option from the pop-up
menu. The rectangle will turn white to indicate it is not a catch rectangle any more.
Recovery actions
The catch rectangle allows you to deal with exceptions in a graceful manner. Common uses might be to select an
alternate execution path, clean up any "loose ends" left behind by the error (e.g., open files), or simply to log the error.
Three new core actions are provided to simplify the authoring of common exception-recovery tasks. These can all be
found in the Core AP module in the folder named Exceptions.

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

Using Advanced Features

The always rectangle


The always rectangle is a special construct that allows you to ensure that a particular sequence of actions is always
executed at the termination of a behavior, regardless of how that termination occurs. It is very similar to the finally
block of a try-catch statement in Java. Whenever a behavior is about to be popped from the stack for any reason, the
always rectangle becomes the current rectangle of the behavior, and the execution mode for the behavior is set
temporarily to non-interruptible (because it should be treated as a critical section). Execution continues normally from
that point, executing the always rectangle and any subsequent rectangles (known as an always block).
An always rectangle is indicated by yellow shading on the Canvas:

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:

normal completion: The behavior has executed a final rectangle.

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.

Creating and removing always rectangles


To turn an existing rectangle into an always rectangle, right-click on the desired rectangle and select the Always option
from the pop-up menu. The rectangle will be shaded yellow to indicate its new always status. If the behavior already
contains an always rectangle, then that rectangle will turn white to indicate that it is no longer an always rectangle.
To remove an always rectangle from a behavior, right-click on the rectangle and select the Always option from the popup menu. The rectangle will turn white to indicate it is not an always
rectangle any more.
Using Java Classes
Understanding classes
When using SimBionic with complex applications, it is often convenient to create behaviors that manipulate the
underlying code-level objects. These objects are retrieved from the application using custom predicates and stored as
variables of type data. To access their member variables and methods, you can define more custom predicates and
actions. For example:
GetField(myobject,"color")
CallMethodUpdate(myobject,arg1,arg2)
When you have many types of objects with many methods and member variables, this approach can become tedious
and cumbersome, since it requires the definition of large numbers of actions and predicates. It can also result in
authoring errors, since SimBionic doesnt know anything about the underlying objects and thus cannot do any typechecking.
If you are using the Java SimBionic run-time engine, however, you can forgo the above scheme and make use of
SimBionics class functionality. A SimBionic class is a user-defined data type that corresponds to a Java class in your
application. A SimBionic class has the same methods and member variables as the underlying Java class (or a subset
of them). 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, without having to define any intermediary actions or predicates. When your
behaviors are frequently manipulating Java objects, using classes can greatly simplify authoring.
There are several ways to create user-defined classes in SimBionic. If you have not already created the underlying
Java class, then you can define the class by hand in SimBionic (see Creating and editing classes) and then export
Java skeleton code for the class (see Generating skeleton code for Java). If the Java class already exists, you can still
create the SimBionic class by hand, but it is generally easier to import the Java class directly (see Importing classes).
Note: The C++ run-time engine does not currently support user-defined classes. Attempting to load a compiled project
file containing classes in the C++ engine will result in an error and termination of the engine.
Creating and editing classes
To create a user-defined class from scratch, follow these steps:

127

SimBionic User Guide

1.

Right-click on the Types header in the Catalog.


After you do so, a menu appears that includes an Insert Class option.

2.

Click the Insert Class option.


This Insert Class dialog box appears:

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.

Using Advanced Features

7.

Type the name you want to give the variable.


This name must be identical to the name of the member variable in the underlying Java class.

8.

Select the data type for the variable.


This data type must exactly match the type of the member variable in the underlying Java class. Note that if
the variable 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 data type for the variable.

9.

If the member variable is static, click the checkbox in the S field.


For non-static variables, leave this box unchecked.

10. Optionally click Edit Variable to add a description of the variable.


An edit dialog will appear in which you can type a description of the variable.
11. Optionally repeat Steps 6-10 to create additional member variables.
Repeat this step until youve created all of the desired member variables for your class.
12. To add a method, click the Insert button next to the Methods list box.
A new row will be added to the list box, with the Name field selected.
13. Type the name you want to give the method.
This name must be identical to the name of the method in the underlying Java class.
14. Select the return data type for the method.
This data type must exactly match the return type of the method in the underlying Java class. Note that if the
methods return 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 return type for the method.
15. If the method is static, click the checkbox in the S field.
For non-static methods, leave this box unchecked.
16. Optionally click Edit Method to add parameters and a description to the method (otherwise skip to
step 23).
An Edit Method dialog will appear:

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

SimBionic User Guide

21. Select the binding for the parameter.


For more information on parameter bindings, see here.
22. Optionally click in the Description field, and type a description of the parameter.
23. Optionally repeat Steps 12-22 to create additional methods.
Repeat this step until youve created all of the desired methods for your class.
24. Click the OK button of the Insert Class dialog box.
The dialog box closes, and the class youve declared is saved and displayed under the Types header in the
Catalog.
If you ever change your mind about the name, description, member variables, and/or methods of a class, 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 Class dialog box. You can then revise the text in the Name and/or Description boxes and
revise any listed member variable or method.
Note: You cannot edit the built-in classes provided with SimBionic. These classes are stored in the Core Classes
folder.
Importing classes
Instead of defining classes by hand in the SimBionic editor, you may also import them from an existing Java class or a
SimBionic class specification file. To import directly from a Java class, follow these steps:
1.

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.

Click the Ok button.


The dialog box closes, and the editor will attempt to import the specified class. If it cannot find the class, it
will display a dialog box with an error message. If the imported class has the same name as an existing
class, SimBionic will ask you if you wish to overwrite the existing class. Overwriting the class will replace all
of its methods and member variables with those of the newly-imported class. Upon a successful import, the
new class will appear under the Types header in the Catalog.

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.

Using Advanced Features

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.

Click the Open button.


The dialog box closes, and the editor will attempt to import the specified class. If it cannot find the class, it
will display a dialog box with an error message. If the imported class has the same name as an existing
class, SimBionic will ask you if you wish to overwrite the existing class. Overwriting the class will replace all
of its methods and member variables with those of the newly-imported class. Upon a successful import, the
new class will appear under the Types header in the Catalog.

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)

Limitations of SimBionic Classes


SimBionics Java class integration is a complex feature, and there are a few limitations to be aware of:

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

SimBionic User Guide

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

Using Advanced Features

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

SimBionic User Guide

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

each element in Vector is


wrapped in SB_Param; this
happens automatically

Vector

each element in array is


unwrapped to a bare Java object
(no SB_Param); SimBionic
primitive types are boxed; this
happens automatically

no conversion needed

Working with the C++ Run-Time Engine


Understanding the C++ run-time engine
After youve used the SimBionic editor to create and compile your project, you can execute your work via SimBionics
C++ run-time engine. The features of this sophisticated AI engine 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.

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_Allocator.h: Defines advanced memory allocation functionality.

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.

AI_SmartPtr.h: Defines advanced memory allocation functionality.

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

SimBionic User Guide

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_Allocator.h: Defines advanced memory allocation functionality.

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.

AI_SmartPtr.h: Defines advanced memory allocation functionality.

If you want to use the SimBionic dynamic library, skip to Step 4.


2.

Define the symbol AI_LOAD_STATIC in your project settings.


This will instruct SimBionic to invoke its API methods as direct method calls into the statically-linked library.

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.

Define the symbol AI_LOAD_DYNAMIC in your project settings.

Skip to Step 6 to complete your setup.

136

Working with the C++ Run-Time Engine

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.

Place Simbion.dll in your DLL search path.


The most common place to place the DLL is in the same directory as your application executable. You can
also place it in your Windows system directory, where it will be available to all applications using SimBionic,
but we recommend against this since it can make it difficult to switch between the different versions of the
library.
As with the static library, there are two versions of the dynamic 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 use the appropriate one for your application.

6.

Your project is now set up to compile with SimBionic.


Youre not quite ready to run your application yet, though. You still need to implement your actions and
predicates and also invoke the proper API methods to start up the SimBionic run-time engine. See the topics
Coding actions in C++, Coding predicates in C++, and Starting and controlling the C++ run-time engine for
information on how to do this.

Implementing Actions & Predicates


Implementing your application interface in C++
Before you can successfully run your SimBionic program, you must write the underlying C++ code that implements
every action and predicate youve declared in the Catalog. How you go about this depends on how you are using AP
modules in your project:

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++.)

If your project uses more than the two default AP modules:


a.

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.

Implement the GetModuleName, GetModuleActions, and GetModulePredicates methods of each


subclass. These methods are called by the run-time engine to find out what actions and predicates are
contained in each AP module. While you can do this by hand, it is far easier to let the SimBionic editor
generate this code for you. See Generating skeleton code for C++ for details. The Template sample
project also provides an example of an AI_Interface class with these methods.

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

SimBionic User Guide

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
//

params[0] refers to the first parameter of the action

//

params[0].String indicates that you want a value of type "string"

//

(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

Working with the C++ Run-Time Engine

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

SimBionic User Guide

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.

3.

Make sure that the C++ code option is selected.


This option is in the lower left corner of the dialog box.

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

Note that exporting vector constants is not currently supported.

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.

Click the Export button.

Working with the C++ Run-Time Engine

An Export dialog box like this appears:

8.

Specify the folder and filename for your skeleton code.

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.

Make sure that the C++ code option is selected.

4.

Make sure that the Open files after export box is checked.

5.

Click the Export button.

6.

Specify the folder and filename for your skeleton code.


Make sure that you specify a different filename or folder than the location of your existing interface code so
that you dont overwrite it.

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:

the action or predicate invocation in the switch statement in DoAction or DoPredicate

the action or predicate declaration in the header file

the action or predicate definition in the .cpp file

Sample skeleton code for C++


The following is an example of the skeleton code generated by SimBionic for the sample PacMan project.
**********
// PacMan_Interface.h : behavior editor generated header file
#include <Interface\AI_Interface.h>
// sim revision number

141

SimBionic User Guide

#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

Working with the C++ Run-Time Engine

void DrawPath(AI_String path);


void FindDestination(AI_Vector location, AI_String direction, AI_Vector& destination);
void FindPMFacing(AI_Vector& dest1, AI_Vector& dest2, AI_Vector& dest3, AI_Integer& count);
void FindPMTrailing(AI_Vector& dest1, AI_Vector& dest2, AI_Vector& dest3, AI_Integer& count);
void GetPathTurn(std::string& path, std::string& turn);
void PostDest(AI_String name, AI_Vector dest);
void RankDirections(AI_Vector target, std::string& direction1, std::string& direction2, std::string& direction3,
std::string& direction4);
void SetDirection(AI_String direction);
// predicates
AI_Param ABS(AI_Float number);
AI_Param AdjacentToPM(AI_Boolean allowreverse);
AI_Param Direction();
AI_Param Direction_PM();
AI_Param IsActive();
AI_Param IsAtIntersection();
AI_Param IsBlocked(AI_String direction, AI_Vector location);
AI_Param IsFleeing();
AI_Param IsGameOver();
AI_Param IsPlaying();
AI_Param IsPMOnNewLane();
AI_Param IsReverse(AI_String direction);
AI_Param Location();
AI_Param Location_PM();
AI_Param Name();
AI_Param Opposite(AI_String direction);
AI_Param Random();
AI_Param SameLane(AI_Vector loc1, AI_Vector loc2);
AI_Param SameLoc(AI_Vector loc1, AI_Vector loc2);
AI_Param X(AI_Vector location);
AI_Param Y(AI_Vector location);
};
**********
// PacMan_Interface.cpp : behavior editor generated implementation file
#include "PacMan_Interface.h"
void PacMan_Interface::DoAction(AI_ProcId actionId, AI_Entity entityId, AI_ParamVec& params)
{
switch (actionId)
{
case PACMAN_ACTION_CalcShortestPath:
{
std::string param2( params[2].String() );
CalcShortestPath(params[0].Vector(), params[1].Boolean(), param2, params[3].Integer());
params[2].SetString( param2.c_str() );
}

143

SimBionic User Guide

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

Working with the C++ Run-Time Engine

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

SimBionic User Guide

// ---- 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 PacMan_Interface::CalcShortestPath(AI_Vector target, AI_Boolean allowreverse, std::string& path, AI_Integer&
pathlength)
{
// your CalcShortestPath implementation here
}
/**
* Draw path from current thing to
* @param path : string [in]
*/
void PacMan_Interface::DrawPath(AI_String 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 PacMan_Interface::FindDestination(AI_Vector location, AI_String direction, AI_Vector& destination)
{
// your FindDestination implementation here
}
/**
* 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]

146

Working with the C++ Run-Time Engine

*/
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

SimBionic User Guide

*/
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

Working with the C++ Run-Time Engine

}
/**
* 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

SimBionic User Guide

*/
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

Working with the C++ Run-Time Engine

/**
* 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

SimBionic User Guide

}
/**
* 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

Working with the C++ Run-Time Engine

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.

Specify the folder and filename for your header file.


For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.

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

SimBionic User Guide

#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

Working with the C++ Run-Time Engine

#define PACMAN_PRED_SameLoc 146


#define PACMAN_PRED_AdjacentToPM 148
#define PACMAN_PRED_ReadDest 147
#define PACMAN_PRED_IsPMOnNewLane 149
**********
The number at the end of each action or predicate line is the ID number SimBionic will use internally to refer to the
action or predicate; while the text name in front of each ID number is the name SimBionic will use instead when
generating code for you to read. For example, the header file above tells you that whenever SimBionic uses the
CreateBBoard action, it will refer to it internally as action 2 but will refer to it externally as
PACMAN_ACTION_CreateBBoard.
The ID number assigned to each core action and core predicate in a project never changes (and always ranges
between 0 and 127). However, the ID numbers for the custom actions and predicates created for a specific project are
assigned by SimBionics editor on the fly. These number assignments are also inserted in the project file thats
generated when you compile your projectwhich in turn provides them to the SimBionic engine.
To learn how to compile a project, see the Compiling your project topic.
For sample code that shows how to include a header file, see the Starting and controlling the C++ run-time engine
topic.
Accessing and setting parameter values in C++
As explained in the Coding actions in C++ and Coding predicates in C++ topics, you must create underlying C++ code
for each custom action and predicate in your project. As part of that code, youll typically need to access and/or set
parameter values. To accomplish this, use the syntax specified below.
To access a SimBionic parameter via C++ code, use the following syntax:

params[0].Integer()

for data type Integer

params[0].Float()

for data type Float

params[0].String()

for data type String

params[0].Vector()for data type Vector

params[0].Boolean()

for data type Boolean

params[0].Entity()

for data type Entity

params[0].Array()

for data type Array or Table

params[0].Data()

for data type Data

params[0].Any()

for data type Any

params[0].Invalid()for data type Invalid

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

SimBionic User Guide

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:

Administrative methods: initialize, getLastError, getVersion, swapProject, terminate

Communication methods: createBBoard, destroyBBoard, postBBoard, readBBoard, sendMsg

Entity management methods: createEntity, destroyEntity, getEntityGlobal, isEntityFinished, makeEntity,


setBehavior, setEntityGlobal, setUpdateFreq, setUpdatePriority

Execution control methods: update, updateEntity

Logging methods: log

Package management methods: loadPackage, loadPackageFile, unloadPackage, unloadAll

AP module management methods: loadAPModule, unloadAPModule

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

Working with the C++ Run-Time Engine

// create a single test entity


AI_ParamVec parms;
AI_Entity id;
// add some parameters for the behavior
parms.push_back( AI_Param(10) );

// a integer parameter

parms.push_back( AI_Param("second parameter") ); // a string parameter


parms.push_back( AI_Param(2,5,7) );

// a vector parameter

id = engine.CreateEntity("MyEntity","SomeBehavior",parms,0,0);
engine.Update();
engine.Terminate();

// make the engine tick one time


// shut down the engine

}
**********
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.

When to load an AP module


You must be sure to load an AP module before any of the actions or predicates in it are invoked by a behavior,
otherwise an error will be generated by the run-time engine. If you are not using behavior packages, this generally
means that you should load all of your AP modules immediately after initialization to be safe. If you are using behavior
packages, then you can wait to load an AP module until the behaviors that reference it are loaded. Thus, behavior
packages and AP modules together enable you to modularize your AI so that you have complete control over when it
is loaded into the run-time engine.

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();

// shut down the engine

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

SimBionic User Guide

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:

kLogAction: Logs the invocation of all core and custom actions.

kLogAll: Records all content to the log file.

kLogBehavior: Logs behavior invocations, completions, and abortions.

kLogBinding: Logs the application of variable bindings.

kLogCondition: Logs condition evaluations and changes in the current rectangle.

kLogDebugger: Logs information about the operation of the interactive debugger, including messages
exchanged with the editor.

kLogEntity: Logs the creation, destruction, or other administrative operations on entities.

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.

kLogPredicate: Logs the invocation of all core and custom predicates.

kLogSchedule: Logs information about the operation of the entity scheduler.

kLogTick: Logs basic information about the flow of execution on each clock tick.

kLogWarning: Logs any warning messages.

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.

Working with the C++ Run-Time Engine

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:

name: string [in]

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

SimBionic User Guide

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:

name: string [in]

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

Working with the C++ Run-Time Engine

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

SimBionic User Guide

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

Working with the C++ Run-Time Engine

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:

name: string [in], key: string [in], value: any [in]

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:

name: string [in], key: string [in]

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

SimBionic User Guide

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

Working with the C++ Run-Time Engine

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 User Guide

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

Working with the Java Run-Time Engine


Understanding the Java run-time engine
After youve used the SimBionic editor to create and compile your project, you can execute your work via SimBionics
Java run-time engine. The features of this sophisticated AI engine 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 a small footprint.

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 release version (simbionic.jar), which is optimized for maximum efficiency.

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.

SB_ParamType: Defines constants for the different types of parameters.

SB_Error: Defines interface return values for various errors.

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.

Setting up your Java project


Before you can use the SimBionic run-time engine with your Java application, youll first need to set up your Java
project to work with SimBionic. This involves only a few simple steps:
1.

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

SimBionic User Guide

2.

Your project is now set up to compile with SimBionic.


Youre not quite ready to run your application yet, though. You still need to implement your actions and
predicates and also invoke the proper API methods to start up the SimBionic run-time engine. See the topics
Coding actions in Java, Coding predicates in Java, and Starting and controlling the Java run-time engine for
information on how to do this.

Implementing Actions & Predicates


Implementing your application interface in Java
Before you can successfully run your SimBionic program, you must write the underlying Java code that implements
every action and predicate youve declared in the Catalog. How you go about this depends on how you are using AP
modules in your project:

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.)

If your project uses more than the two default AP modules:


a.

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.

Implement the getModuleName, getModuleActions, and getModulePredicates methods of each


subclass. These methods are called by the run-time engine to find out what actions and predicates are
contained in each AP module. While you can do this by hand, it is far easier to let the SimBionic editor
generate this code for you. See Generating skeleton code for Java for details.

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

Working with the Java Run-Time Engine

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

SimBionic User Guide

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

Working with the Java Run-Time Engine

***************
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

SimBionic User Guide

3.

Make sure that the Java code option is selected.


This option is in the lower left corner of the dialog box.

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.

Click the Export button.


An Export dialog box like this appears:

9.

Specify the folder and filename for your skeleton code.


For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.

10. Click Save.


SimBionic will generate the specified skeleton code file(s), including one subclass of SB_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.
11. Import the file(s) into 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:

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.

Make sure that the Java code option is selected.

4.

Make sure that the Open files after export box is checked.

5.

Click the Export button.

Working with the Java Run-Time Engine

6.

Specify the folder and filename for your skeleton code.


Make sure that you specify a different filename or folder than the location of your existing interface code so
that you dont overwrite it.

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:

the action or predicate invocation in the switch statement in doAction or doPredicate

the action or predicate body

Sample skeleton code for Java


The following is an example of the skeleton code generated by SimBionic for the sample PacMan project.
**********
// PacMan_Interface.java : behavior editor generated Java class
package com. // your package here
import com.stottlerhenke.simbionic.api.*;
import java.util.ArrayList;
public class PacMan_Interface extends SB_Interface
{
// sim revision number
public static final int SIM_REV = 16;
// actions
public static final int ACTION_CalcShortestPath = 133;
public static final int ACTION_DrawPath = 136;
public static final int ACTION_FindDestination = 129;
public static final int ACTION_FindPMFacing = 131;
public static final int ACTION_FindPMTrailing = 132;
public static final int ACTION_GetPathTurn = 134;
public static final int ACTION_PostDest = 135;
public static final int ACTION_RankDirections = 130;
public static final int ACTION_SetDirection = 128;
// predicates
public static final int PRED_ABS = 141;
public static final int PRED_AdjacentToPM = 148;
public static final int PRED_Direction = 133;
public static final int PRED_Direction_PM = 135;
public static final int PRED_IsActive = 131;
public static final int PRED_IsAtIntersection = 144;
public static final int PRED_IsBlocked = 137;
public static final int PRED_IsFleeing = 132;
public static final int PRED_IsGameOver = 130;
public static final int PRED_IsPlaying = 129;
public static final int PRED_IsPMOnNewLane = 149;
public static final int PRED_IsReverse = 143;
public static final int PRED_Location = 134;

173

SimBionic User Guide

public static final int PRED_Location_PM = 136;


public static final int PRED_Name = 128;
public static final int PRED_Opposite = 142;
public static final int PRED_Random = 138;
public static final int PRED_SameLane = 145;
public static final int PRED_SameLoc = 146;
public static final int PRED_X = 139;
public static final int PRED_Y = 140;
// constants
// How fast the ghosts move
public static final int GHOST_SPEED = 15;
public PacMan_Interface()
{
}
public void doAction(int actionId, long entityId, ArrayList params)
{
switch (actionId)
{
case ACTION_CalcShortestPath:
CalcShortestPath((SB_Param)params.get(0), (SB_Param)params.get(1),
(SB_Param)params.get(2), (SB_Param)params.get(3));
break;
case ACTION_DrawPath:
DrawPath((SB_Param)params.get(0));
break;
case ACTION_FindDestination:
(SB_Param)params.get(2));

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

Working with the Java Run-Time Engine

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

SimBionic User Guide

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

Working with the Java Run-Time Engine

}
/**
* 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

SimBionic User Guide

}
/**
* 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

Working with the Java Run-Time Engine

}
/**
* 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

SimBionic User Guide

SB_Param IsBlocked(SB_Param direction, SB_Param location)


{
// your IsBlocked implementation here
return new SB_Param();
}
/**
* Checks if current thing is fleeing (during power up for ghost,
* and always for
* @return boolean
*/
SB_Param IsFleeing()
{
// your IsFleeing implementation here
return new SB_Param();
}
/**
* Checks if game is
* @return boolean
*/
SB_Param IsGameOver()
{
// your IsGameOver implementation here
return new SB_Param();
}
/**
* Checks if game is
* @return boolean
*/
SB_Param IsPlaying()
{
// your IsPlaying implementation here
return new SB_Param();
}
/**
* Checks if pacman has just entered new
* @return boolean
*/
SB_Param IsPMOnNewLane()
{
// your IsPMOnNewLane implementation here
return new SB_Param();
}
/**
* Checks if given direction is reverse of current thing's most

180

Working with the Java Run-Time Engine

* 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

SimBionic User Guide

}
/**
* 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

Working with the Java Run-Time Engine

* Returns y coordinate of given


* @param location : vector [in]
* @return float
*/
SB_Param Y(SB_Param location)
{
// your Y implementation here
return new SB_Param();
}
};
Creating Java symbolic names for actions & predicates
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 Java 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 Java code of your simulation or game.
The group of symbolic names for your projects actions and predicates will be created as a class in a Java file (e.g.
MyProject.java). Youll typically give the file the same name as your project as in the example; 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 Java 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 Java 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 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.

Specify the folder and filename for your Java file.


For detailed information on using this dialog box, see the topic Saving files with the File Chooser dialog box.

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

SimBionic User Guide

**********
// 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

Working with the Java Run-Time Engine

public static final int PRED_Y = 140;


public static final int PRED_ABS = 141;
public static final int PRED_IsReverse = 143;
public static final int PRED_IsBlocked = 137;
public static final int PRED_Opposite = 142;
public static final int PRED_IsAtIntersection = 144;
public static final int PRED_SameLane = 145;
public static final int PRED_SameLoc = 146;
public static final int PRED_AdjacentToPM = 148;
public static final int PRED_ReadDest = 147;
public static final int PRED_IsPMOnNewLane = 149;
}
**********
The number at the end of each action or predicate line is the ID number SimBionic will use internally to refer to the
action or predicate; while the text name in front of each ID number is the name SimBionic will use instead when
generating code for you to read. For example, the header file above tells you that whenever SimBionic uses the
CreateBBoard action, it will refer to it internally as action 2 but will refer to it externally as
PACMAN_ACTION_CreateBBoard.
The ID number assigned to each core action and core predicate in a project never changes (and always ranges
between 0 and 127). However, the ID numbers for the custom actions and predicates created for a specific project are
assigned by SimBionics editor on the fly. These number assignments are also inserted in the project file thats
generated when you compile your projectwhich in turn provides them to the SimBionic engine.
To learn how to compile a project, see the Compiling your project topic.
For sample code that shows how to include the exported Java file, see the Starting and controlling the Java run-time
engine topic.
Accessing and setting parameter values in Java
As explained in the Coding actions in Java and Coding predicates in Java topics, you must create underlying Java
code for each custom action and predicate in your project. As part of that code, youll typically need to access and/or
set parameter values. To accomplish this, use the syntax specified below.
To access a SimBionic parameter via Java code, use the following syntax:

((SB_Param) params.get(0)).getInteger()

((SB_Param) params.get(0)).getFloat() for data type Float

((SB_Param) params.get(0)).getString()

for data type Integer


for data type String

((SB_Param) params.get(0)).getVector()

for data type Vector

((SB_Param) params.get(0)).getBoolean()

for data type Boolean

((SB_Param) params.get(0)).getEntity()

for data type Entity

((SB_Param) params.get(0)).getData()

for data type Data

((SB_Param) params.get(0)).getArray()

for data type Array or Table

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)).setFloat (your_float_variable+1.25);

((SB_Param) params.get(0)).setString(your_string_variable+"sample string");

((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

SimBionic User Guide

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:

Administrative methods: initialize, getLastError, getVersion, swapProject, terminate

Communication methods: createBBoard, destroyBBoard, postBBoard, readBBoard, sendMsg

Entity management methods: createEntity, destroyEntity, getEntityGlobal, isEntityFinished, makeEntity,


setBehavior, setEntityGlobal, setUpdateFreq, setUpdatePriority

Execution control methods: update, updateEntity

Logging methods: log, registerLogPrintStream

Package management methods: loadPackage, loadPackageFile, unloadPackage, unloadAll

AP module management methods: loadAPModule, unloadAPModule

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

Working with the Java Run-Time Engine

// 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) != EAI_Err.kOK)
{
System.out.println("Engine failed to initialize: " + engine.getLastError());
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

parms.add( new SB_Param("second parameter") );


parms.add( new SB_Param(2,5,7) );

// a string parameter

// a vector parameter

id = engine.createEntity("MyEntity","SomeBehavior",parms,0,0);
engine.update();

// make the engine tick one time

engine.terminate();

// shut down the engine

}
**********
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

SimBionic User Guide

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.

When to load an AP module


You must be sure to load an AP module before any of the actions or predicates in it are invoked by a behavior,
otherwise an error will be generated by the run-time engine. If you are not using behavior packages, this generally
means that you should load all of your AP modules immediately after initialization to be safe. If you are using behavior
packages, then you can wait to load an AP module until the behaviors that reference it are loaded. Thus, behavior
packages and AP modules together enable you to modularize your AI so that you have complete control over when it
is loaded into the run-time engine.

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();

// shut down the engine

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.

Open a log stream in your application code.


The code below shows an example:
PrintStream logPrintStream = null;
try
{
logPrintStream = new PrintStream( new FileOutputStream("MyProject.log") );
}
catch(Exception ex)
{
ex.printStackTrace();
}
if( logPrintStream != null )
{
engine.registerLogPrintStream( logPrintStream );
}

3.

188

Configure the run-time engine to use your log stream by calling SB_Engine.registerLogPrintStream.

Working with the Java Run-Time Engine

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:

ACTION: Logs the invocation of all core and custom actions.

ALL: Records all content to the log file.

BEHAVIOR: Logs behavior invocations, completions, and abortions.

BINDING: Logs the application of variable bindings.

CONDITION: Logs condition evaluations and changes in the current rectangle.

DEBUGGER: Logs information about the operation of the interactive debugger, including messages
exchanged with the editor.

ENTITY: Logs the creation, destruction, or other administrative operations on entities.

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.

PREDICATE: Logs the invocation of all core and custom predicates.

SCHEDULE: Logs information about the operation of the entity scheduler.

TICK: Logs basic information about the flow of execution on each clock tick.

WARNING: Logs any warning messages.

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:

name: string [in]

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

SimBionic User Guide

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].

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:

name: string [in]

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

Working with the Java Run-Time Engine

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

SimBionic User Guide

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

Working with the Java Run-Time 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
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:

name: string [in], key: string [in], value: any [in]

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:

name: string [in], key: string [in]

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

SimBionic User Guide

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

Working with the Java Run-Time Engine

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

SimBionic User Guide

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

Working with the Java Run-Time Engine

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

Using the SimBionic Cheat Sheets


SimBionic Editor Cheat Sheet
Heres how to perform the most common activities in the SimBionic editor:

Launch the editor: Double-click the SimBionic icon on your desktop; or click the Start button and select
Programs->SimBionic->SimBionic Editor.

Open a new project: Press Ctrl+N.

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: Press Ctrl+S.

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.

Select a Canvas element: Click the element.

Select all Canvas elements: Press Ctrl+A.

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

SimBionic User Guide

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.

Zoom out on the Canvas: Press F8.

Undo your previous action(s) on the Canvas: Press Ctrl+Z.

Redo your previous action(s) on the Canvas: Press Ctrl+Y.

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.

Compile your project: Press F7.

Debug your project: Press Ctrl+F5.

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

Using the SimBionic Cheat Sheets

AI_Allocator.h: Defines advanced memory allocation functionality.

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.

AI_SmartPtr.h: Defines advanced memory allocation functionality.

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:

Administrative methods: initialize, getLastError, getVersion, swapProject, terminate

Communication methods: createBBoard, destroyBBoard, postBBoard, readBBoard, sendMsg

Entity management methods: createEntity, destroyEntity, getEntityGlobal, isEntityFinished, makeEntity,


setBehavior, setEntityGlobal, setUpdateFreq, setUpdatePriority

Execution control methods: update, updateEntity

Logging methods: log

Package management methods: loadPackage, loadPackageFile, unloadPackage, unloadAll

AP module management methods: loadAPModule, unloadAPModule

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

SimBionic User Guide

// initialize the engine


if (engine.Initialize(myInterface,myConfig) != kOK)
return -1;
// create a single test entity
AI_ParamVec parms;
AI_Entity id;
// add some parameters for the behavior
parms.push_back( AI_Param(10) );

// an integer parameter

parms.push_back( AI_Param("second parameter") ); // a string parameter


parms.push_back( AI_Param(2,5,7) );

// a vector parameter

id = engine.CreateEntity("MyEntity","SomeBehavior",parms,0,0);
engine.Update();
engine.Terminate();

// make the engine tick one time


// shut down the engine

}
**********
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

Administrative methods: initialize, getLastError, getVersion, swapProject, terminate

Communication methods: createBBoard, destroyBBoard, postBBoard, readBBoard, sendMsg

Entity management methods: createEntity, destroyEntity, getEntityGlobal, isEntityFinished, makeEntity,


setBehavior, setEntityGlobal, setUpdateFreq, setUpdatePriority

Using the SimBionic Cheat Sheets

Execution control methods: update, updateEntity

Logging methods: log, registerLogPrintStream

Package management methods: loadPackage, loadPackageFile, unloadPackage, unloadAll

AP module management methods: loadAPModule, unloadAPModule

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

SimBionic User Guide

{
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

parms.add( new SB_Param("second parameter") );


parms.add( new SB_Param(2,5,7) );

// a string parameter

// a vector parameter

id = engine.createEntity("MyEntity","SomeBehavior",parms,0,0);
engine.update();

// make the engine tick one time

engine.terminate();

// shut down the engine

}
**********
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

Adding text to the Canvas


Adjusting
project settings

93

ArraySet

76

ArraySetMinSize

76
76

AI_Config

126, 145

ArraySetSize

AI_Engine

126, 145

ArraySize

AI_Exception

115, 126

Assigning value to variable

AI_Interface

126, 127, 128, 129, 145

AI_Param

126, 128, 144

Always rectangle

115, 116

Annotating a Canvas element


AP module
APD files
API methods for SimBionic engine
CreateBBoard

56

25, 128, 146, 158, 160, 176


25, 92
145, 175

Attaching a binding to a Canvas element

76
59, 72
72

Authoring tool
Autocompleting an expression

1
72

B
Back button

33

Behavior execution mode

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

setting to run in one tick

29

205

SimBionic User Guide

setting to run uninterrupted

29

Final

43

setting to run until blocked

29

Forward

33

Initial

42

72

Main

33
4

Behavior on Canvas
attaching binding to
changing label of

57

New

checking for completed execution

88

Open

commenting on

56

Paste

50, 51

copying

50

Print

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

126, 127, 129

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

34, 37, 44, 48

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

20, 22, 26, 65, 67

57

deleting

32

Back

33

editing

Bindings

72

organizing

31

Comment

56

renaming

31

Compile

90

Catch rectangle

Connect

93

Changing

20, 22, 26, 65, 67

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

comment on a Canvas element

56

labeling

48, 56

condition

44

moving

51

connector

49

placing a reminder on

56

constant

67

turning green to identify its rectangle

48

descriptor

82

Constant

folder

31

binding

label for a Canvas element

67, 69, 72

57

creating

67

predicate

22, 32

deleting

32

variable declaration

63, 65

editing

67

Cheat Sheets

importing

67

for SimBionic C++ run-time engine

188

moving

31

for SimBionic editor

187

renaming

31

for SimBionic Java run-time engine

190

type

60

88

Copying

Checking for completed behaviors


Checking for invalid values

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

110, 148, 178


110, 149, 179

via group messages

111

DestroyBBoard

via virtual blackboards

110

DestroyEntity

149, 179

Compiling your project

90

DestroyGroup

111

Completed behavior checking

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

111, 152, 182

deleting

52

SetUpdatePriority

editing

44

TableAddCol

77

moving

51

TableAddRow

77

placing a reminder on

56

TableAppend

77

Connecting SimBionic to simulation/game103, 125, 126, 145, 157, 175


TableDeleteCol

77

Connecting the debugger to the engine

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

SimBionic User Guide

TableSetRow

77

reminder on a Canvas element

56

TableSetSize

77

sub-behavior

Core predicates

18

symbolic names for actions & predicates

ArrayCopy

76

ArrayGet

76

ArrayPop

76

ArraySize

76

CreateEntity

148, 178

Cutting Canvas element

108
142, 172
51

D
Data exchanges between entities

15, 18

via group messages

111

via virtual blackboards

110

GetMsgData

111

Data types supported

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

110, 148, 178


18, 148, 178

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

code for parameter values

144, 174

constant

67

code for predicate

128, 158

enumerated type

behavior on Canvas
class
code for action

comments on a Canvas element

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

previous or next behavior


Documenting

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

Double border rectangle for behavior on Canvas

29

Drag-and-drop

Engine for SimBionic

execution flow

34, 37, 44
31

Entities window

variable to Canvas element

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

comment on a Canvas element

56

skeleton interface code

compound action

40

XML

condition

44, 57

Expression

connector

49

autocompleting

constant

67

creating

enumerated type

79

editing

expression
folder
package

34, 37, 44, 74


31
114

File->Exit

32

File->Export Constants

22

File->Export HTML Doc

reminder on a Canvas element

56

File->Export Skeleton Code

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

Execution stack window


Exporting

74

115
15, 18

via virtual blackboards

76

binding

115

Execution

array

26

79, 80

111

Exiting SimBionic

37, 57

95
109

via group messages

25

behavior on Canvas

95
148, 178

AP module
behavior in Catalog

126

destroying

flow

action on Canvas

103, 145, 175

creating

placing on Watch list


50

147, 177

using with non-C++ simulations or games

Catalog items between folders

Dynamically loading and unloading behaviors

87

exiting
starting

Catalog item to Canvas

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

SimBionic User Guide

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

Files generated by SimBionic

.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

Implicit IsDone condition

52

Importing

Finding
52
4
52
87

Folder

25

behavior declarations--BTNs

30

constants

67

Information exchanges between entities

15, 18

via group messages

111

via virtual blackboards

110

31

Initial

deleting

32

Initial/Final toolbar

organizing contents of

31

Initialize

renaming

31

Insert menu

Forward button

33

Game or simulation

88

action & predicate declarations--AP modules

creating

107

Find tab

Flow of execution of run-time engine

142

HTML documentation

90
92

project

111

Hooking SimBionic into your simulation/game103, 125, 126, 145, 157, 175

.SIM file

text on the Canvas

42

11

.TPD file

Canvas elements

60

Green rectangle

42
42, 43
145, 150, 175, 180

Insert->New Action...

20

Insert->New Behavior...

26

Insert->New Compound Action...

40

coding actions

128, 160

Insert->New Condition...

44

coding parameter values

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

145, 150, 175, 180

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

63, 144, 174

IsMsg

coding actions
65, 69, 72

3
29

157
175
142, 160
158, 172
157, 158, 161
177

Index

shutting down

177

Memory management in the C++ engine

starting

175

Message

111

Message exchanges between entities

JoinGroup
K
Keystroke shortcuts for SimBionic editor

via group messages


187

147
111
15, 18
111, 152, 182

via virtual blackboards110, 148, 149, 152, 178, 179, 181, 182

Alt+F4 for File->Exit

13

Message queue

Alt+Left Arrow for View previous behavior

33

Moving

Alt+Right Arrow for View next behavior

33

binding attached to Canvas element

74

111

Ctrl+B for Edit Bindings dialog box

74

Canvas element

51

Ctrl+C for Edit->Copy

50

Catalog item

31

Ctrl+D for Insert->New Predicate

22

polymorphism tab

85

Ctrl+E for Edit Expression dialog box

34, 37, 44

project

Ctrl+F for Edit->Find

52

sub-behavior

Ctrl+F5 for Build->Quick-Run

93

to the previous or next behavior

Ctrl+G for Insert->New Global

65

Multi-tick

Ctrl+H for Edit->Replace

54

Multi-user development

Ctrl+I for Insert->New Behavior

26

Ctrl+K for Insert->New Condition

44

11
108
33
29
107

N
Navigating behaviors

33

Ctrl+L for Insert->New Local

63

NextMsg

Ctrl+M for Insert->New Compound Action

40

Non-interruptible

29

Notating a Canvas element

56

Ctrl+N for File->New

111

Ctrl+O for File->Open

NullData

18

Ctrl+P for File->Print

12

NullEntityID

18

Ctrl+R for Insert->New Rectangle

34

NumMembers

Ctrl+S for File->Save

11

Ctrl+T for Insert->New Action

20

Ctrl+V for Edit->Paste


Ctrl+X for Edit->Cut

31, 50, 51

O
One-tick
Operators available for expressions

Ctrl+Y for Edit->Redo

55

Output window

Ctrl+Z for Edit->Undo

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

Del for Edit->Delete

111

Pac-Man sample game written using SimBionic

97

Parameter
57

accessing and setting via C++ code

LoadPackage

151, 181

accessing and setting via Java code

LoadPackageFile

151, 181

creating

20, 22, 26

deleting

20, 22, 26, 32

editing

20, 22, 26, 32

Local variable
binding
creating

69, 72
63

Pasting a Canvas element


Polymorphism

144
174

50, 51

editing

63

renaming

31

creating

85

type

60

moving page of

85

Log

151, 181

polymorphic global variable

Logging in the run-time engine

147, 177

renaming

85

PostBBoard

110, 152, 181

M
Main behavior
MakeEntity

30
151, 181

59, 81

Predicate
coding in C++

128, 144

211

SimBionic User Guide

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

Replacing text on the Canvas

54

Repositioning

dragging and dropping to Canvas element

44

editing

22

Canvas element

51

importing

25

Catalog item

31

in AP module

25

polymorphism tab

85

organizing

31

project

11

renaming

31

to the previous or next behavior

33

Printing
printing your project
Prioritizing a connector

12

Resetting SimBionic to its previous state

12

Resume

116

49

Rethrow

116

Project

Retrieving a deleted Canvas element

compiling

90

creating

debugging

93

documenting

Retry
Reversing your previous choice

55

55
116
55

Revising

56, 57, 107

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

comment on a Canvas element

56

SBP filename extension

11

condition

44

settings

93

connector

49

constant

67

Project window
Catalog tab

15

folder

31

Descriptors tab

81

predicate

22

sub-behavior

Queue for each entity's messages


Quick-Run option
Quick-Zoom

111

variable

93

Right-clicking

34

QuitGroup

111

Quitting SimBionic

13

R
ReadBBoard

110, 152, 182

Rectangle types on Canvas


blue for catch rectangle

115

to create action
to create AP module
to create behavior

108
63, 65
20, 34
25
26, 37

to create Catalog folder

31

to create compound action

40

to create condition

44

to create constant

67

double border for run in one tick behavior

29

to create descriptor

82

green for initial action

42

to create global variable

65

red for final action

42

to create local variable

63

40

to create polymorphism

85

stacked for compound action


yellow for always rectangle
Red rectangle
RegisterLogPrintStream
Reminder

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

using with non-C++ simulations or games


Run-time error handling

115

starting run-time engine

Half-Life

Pac-Man
Saving a project

starting editor

Counter-Strike

relationship to simulation or game

126

Sample program written using SimBionic

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

103, 145, 175

SB_Exception
SB_Interface
SB_Param
SBP file
Scheduling entity updates
Searching the Canvas
SendMsg

158, 160, 161


174
11
109, 154, 184
52
111, 152, 182

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

behavior execution mode

29

TableDeleteCol

behavior interruptibility

29

TableDeleteRow

77

breakpoint

97

TableGetCol

77

label for Canvas element

57

parameter values in code

144, 174

TableGetEntry

77

TableGetRow

77
77

rectangle as always

116

TableInsertCol

rectangle as catch

115

TableInsertRow

77

rectangle as initial

42

TableRowSize

77

Setting parameter values


Setting up your C++ project
Setting up your Java project

144, 174
126
157

TableSetCol

77

TableSetEntry

77

TableSetMinSize

77

SetUpdateFreq

154, 184

TableSetRow

77

SetUpdatePriority

154, 184

TableSetSize

77

Shortcut keystrokes for SimBionic editor


Shutting down the run-time engine
SIM file
SimBionic
Cheat Sheet for using editor
Cheat Sheet for using run-time engine

187
147, 177

Terminate

90

Add text

57

1, 3

Always

116

187

Back

188, 190

Bindings

connecting to your simulation or game103, 125, 126, 145, 157, 175Catch


editor

155, 185

Toolbar buttons

Comment

33
72
115
56

213

SimBionic User Guide

Compile

90

UpdateEntity

Connect

93

Updating SimBionic

Copy

50

Using dynamic behavior loading

Cut

51

Using SimBionic with other languages

155, 185
13
113, 114
126

Expression

69

Final

43

Forward

33

binding

Initial

42

creating global variable

65

creating local variable

63

Variable

Main

33

New

deleting

Open

editing

Paste

50, 51

type

Print

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

Adjusting priorities for


Types of data supported
class
enumerated type

Breakpoint List window

96

Entities window

95

60

Execution Stack window

95

117

previous or next behavior

33

Variables window

96

79

U
Undoing your previous choice

Viewing

49

Transition

Visual approach of SimBionic editor


55

Working with multiple authors

UnloadAll

155, 185

UnloadPackage

155, 185

Update

155, 185

XML

Update frequency

109

Update priority

109

214

W
107
107

Y
Yellow rectangle

116

Potrebbero piacerti anche