Skip to main content

The boards system

If you set out to make a video game, you may quickly find yourself coding a custom tool for editing data objects such as game levels or monster movements. Such editors can be a lot of work, and they tend to be specialized programs. For example, a text adventure game needs quite different data structures than a car racing game. For stereotypical game genres such as platformers or RPGs, generic level designer apps do exist—but even then, you'll probably still find yourself coding an exporter or plugin to convert that editor's objects into custom data structures that fit your requirements. Video games are just one example. Many other programming problems face the same need for a data editor.

To help you get going faster, the Hybrix designer features a sophisticated built-in visual editor. It is based around the concept of drawing boards. The drawings on these boards are made from art resources such as your sprites and tilemaps, as well as geometrical shapes and text labels. The board objects can then get emitted to produce Hybrix DATA blocks. "Emitting" simply means automatically generating program code.

Although the boards system will never be as good as a handcrafted special-purpose editor, quite a lot of interesting data structures can be modeled this way, even non-visual material such as logic flowcharts or questionnaires. Boards are also useful for making non-emitted diagrams (that won't be part of your program at all). You might use boards for sketching ideas and notes, for testing out how sprite/tilemap objects look when arranged together, or for adding illustrated documentation to a tutorial project.

A crash course: In this section, we'll start by introducing all the major concepts, showing how they fit together. Then the subsequent sections will explain each concept in detail.

Classes

As a motivating example, suppose that our program needs to display a smiley face with two eyes: The face is a sprite, and so is each eye. The eyes will be positioned relative to the face, so that when the smiley face moves, its eyes move, too. Our program will also display a "response" message when the user moves their mouse over a sprite, something like "You touched the left eye."

In the program code, we can define a single class to represent the three shapes:

CLASS S_SHAPE
# LOCATION ON THE SCREEN. FOR CHILD OBJECTS,
# THE LOCATION IS MEASURED RELATIVE TO THE PARENT'S LOCATION.
VAR X: INT
VAR Y: INT

# THE SPRITE IMAGE
VAR IMAGE: CLIP

# WHAT TO SHOW WHEN THE MOUSE IS OVER THIS SHAPE
VAR RESPONSE: STRING

# OTHER SHAPES THAT ARE "PART OF" THIS SHAPE
VAR CHILDREN: S_SHAPE[]
END CLASS

We could have defined two members LEFT_EYE and RIGHT_EYE, of course. The reason for an array CHILDREN is to anticipate more complex nesting, such as pupils inside the eyes. The S_ prefix is a handy convention to remind you that this class gets emitted by the boards system. ("S" stands for "symbol", introduced below.)

DATA blocks

If we created the smiley face data by hand, it might look like this:

MODULE SYMBOLS
VAR SMILEY: S_SHAPE
END MODULE

DATA SYMBOLS::SMILEY
{
X: 100,
Y: 100,
IMAGE: ID_CLIP::HEAD,
RESPONSE: "YOU TOUCHED THE FACE",

CHILDREN: [
{
X: 10,
Y: 30,
IMAGE: ID_CLIP::EYE,
RESPONSE: "YOU TOUCHED THE LEFT EYE"
},
{
X: 20,
Y: 30,
IMAGE: ID_CLIP::EYE,
RESPONSE: "YOU TOUCHED THE RIGHT EYE"
},
]
}
END DATA

Making this by hand is not difficult... except for the X and Y geometry. To position the eyes nicely, you would need to plot the coordinates by hand on graph paper, or else run your program repeatedly using trial and error. Instead, let's use the boards system to emit this data from a visual diagram.

Symbols

The designer's boards are like big rectangular pages or drawing canvases. You can create as many boards as you like. The objects on the board are called symbols. The symbols can all go at the top level of the board, or they can be nested as "children" of other symbols. In the editor, this nesting relationship appears as a collapsible tree on the SYMBOLS tab. If a parent symbol is moved, all its child symbols move with it.

To make our SMILEY data structure, the face's symbol will have two child symbols, one for each eye—similar to the S_SHAPE nesting in the DATA block.

Figures

What does a symbol look like? For our example, it should show the image from a sprite animation clip, corresponding to the framework's CLIP class. The visual portrayal of a symbol on the board is called the symbol's figure. Each symbol has exactly one figure. There are various possible figure kinds such as point, line, oval, clip, tilemap, etc. Our three symbols will all have the "clip" figure kind.

The figure also embodies other visual attributes such as color, theme, a text caption, and horizontal/vertical flipping. Different figure kinds have different attributes.

Symbols on the board
SMILEY symbol with two child symbols LEFT_EYE and RIGHT_EYE

Symbol types

On the board, the above concepts are enough to make a smiley face consisting of three sprites. But we still haven't described how to make the data for our S_SHAPE class. How does the designer know to emit its location as X and Y instead of some other variable name like LEFT or TOP? How does it know we want a CHILDREN array, instead of separate LEFT_EYE and RIGHT_EYE variables? The answer is that every symbol has a symbol type. In practice, you define your symbol types first, then make board drawings by creating symbols with appropriate symbol types.

Symbol type editor
Editing the S_SHAPE symbol type

The symbol type determines all these things for a symbol:

  • The kind of figure to show: point, line, oval, clip, tilemap, etc.
  • What type of children it can have (allowable symbol types)
  • The fields that are members of this symbol, such as X, Y, IMAGE, RESPONSE, CHILDREN
  • Which of these fields should get emitted as code; for example, you might add an informational text field named MY_NOTES that does not get emitted
  • The emitted class name (S_SHAPE); by default, it is the same as the symbol type name
  • Some initial parameters; for example, what figure color to use for newly created symbols

Field types

Most of the information of a symbol is stored in its fields. The boards system provides over 20 different field types to help you represent all sorts of data.

Examples of field types:

  • A number field, which can be emitted to BYTE, PAIR, or INT variables.
  • A text string field, which can be emitted to STRING variables
  • Various field types for art objects such as CLIP, TILEMAP, TILESET, etc.
  • "Metric" fields, that emit measurements such as the figure's width or relative position
  • Figure-based fields that emit various attributes such the figure's color, theme, caption, etc.
  • A field that stores a pointer to other symbols, which you can link up using the visual editor
  • A field that emits a pointer to the parent of the symbol
  • A field that automatically collects the symbol's children into an array

Field type chooser
Field type choices when creating a new field

Here's how we might design the fields for our smiley face shape:

Field nameField typeEmitted variable type
XmetricINT
YmetricINT
IMAGEfigure clipCLIP
RESPONSEstringSTRING
CHILDRENsymbol childrenS_SHAPE[]
MY_NOTESstring(not emitted)

Symbol picks

We're still missing one final ingredient: how to tell the boards system to put this data into the SYMBOLS::SMILEY variable? For just one variable, this can be specified directly on the symbol itself: On the BOARDS screen, click the smiley's face object, set its symbol name to be SMIILEY, and then check the box for EMIT A "PICKS" VAR. A pick instructs the designer to "pick out" one particular symbol from the diagram and emit a global variable. Now that symbol will appear on the PICKS tab on the Hybrix DATA screen, where you can see all your picked symbols.

The emitted variable can be found on the CODE screen, in the special source file named [GENERATED]:

MODULE SYMBOLS
# PICKS:
VAR SMILEY: S_SHAPE
END MODULE

A DATA SYMBOLS::SMILEY block gets emitted as well, but for brevity it doesn't appear in the code editor. You can view it on the DATA screen, though.

Symbol queries

What if we had hundreds of shapes, not just a single smiley? It would be cumbersome to have to manage a separate MODULE SYMBOLS member variable for each object. For this situation, the DATA screen provides a second concept called queries, which build lists of symbols from your diagram. For example, if you defined a GAME_LEVEL symbol type, you could use a query to collect all symbols of this type into an array called SYMBOLS::GAME_LEVELS.

Symbol queries
Querying the SMILEY symbol and its children

Summary

Here's a quick recap:

  • Boards are filled with nesting trees of symbols.
  • A symbol's visual appearance is called its figure.
  • A symbol's underlying data is stored in fields.
  • If two symbols have the same symbol type, then they will have the same fields and same kind of figure.
  • Symbols can optionally be emitted as Hybrix DATA blocks, where the symbol's fields get mapped to VAR members of your class (CLASS definition).
  • Generally you will define a separate symbol type for each class, but it's possible for multiple symbol types to emit the same class.
  • The emitted objects always go into the SYMBOLS module, found in the [GENERATED] source file.
  • Use a pick to emit an individual symbol.
  • Use a query to emit an array, built by collecting all symbols with a specified symbol type.

That's it! Now you've seen all the major concepts of the Hybrix boards system. The following sections will explain each concept in detail.