Bricksets
Contents
Definitions
In Open Surge, levels are built using elements called bricks. A brick is a reusable scenery element. Bricks may be: blocks, floors, walls, ceilings, movable platforms, trees, plants, decorative objects, and so on. Bricks are like tiles, but more flexible:
- Bricks can be of varying sizes (whereas tiles have a fixed size)
- Bricks may be placed anywhere in space, even on top of each other
- Bricks may be endowed with special behavior & movement
Bricks are imported into Open Surge via a brickset. If you want to create new scenery for new levels, you must first create a brickset. A brickset is composed of two elements:
1) The brickset image
No brickset would ever exist without the image in which the bricks are contained. This image features the artwork and may be organized in many ways. It's recommended to align the bricks to a 16x16 grid. This makes things convenient when designing levels and when creating the brickset script.Note: to ensure maximum compatibility with most video cards, brickset images must not exceed 4096x4096 pixels. That's more than enough for most cases, but if you ever run out of space, split the artwork into two or more images.
- Previously, the limit was 2048x2048 pixels. It has been increased in Open Surge 0.5.2.
2) The brickset script
The brickset script specifies how the bricks get put into the game for your use. It connects the artwork with the game. A brickset script is a .brk file in the themes/ folder. The engine reads this script for references on bricks, gets their parameters, and the physics take care of the rest once you're done placing the bricks in your levels.The brickset script contains references to the brickset image(s), how big the bricks are, what part of the image to use as their "face", the animation sequence (if any), the collision mask (if any), and their behavior: whether they react as a plain stepping stone, collapse beneath you once touched, act as a "cloud" (we will discuss this soon), move around in mid-air to make jumping challenges, and so on.
Brickset scripts can be written manually or can be generated automatically using tools. Read section Using automated tools for details.
Design guidelines
While you have great flexibility to design your brickset, experience shows that certain approaches work better than others. We present guidelines that increase the likelihood of creating a brickset that easy to use and easy to write.
Divide the brickset into 3 parts (this division is conceptual):
1) Blocks (you may use bricks numbered from 0 to 127)
These are 128x128 bricks that represent: walls, platforms, ceilings, parts of a loop, and so on. They are the building blocks of your level and will help you build its structure. Make sure that they are tileable (repeatable).
2) Things (you may use bricks numbered from 128 upwards)
These are generally passable/decorative bricks like: flowers, trees, rocks, pipes, and so on. All such bricks must be built within a 16x16 grid (width and height must be divisible by 16, like 64x64, 32x64, etc.)
3) Special (you may use bricks numbered from 255 downwards)
These are special bricks such as: movable platforms, breakable walls, and so on. All such bricks must fit a 16x16 grid (width and height must be divisible by 16).
The brickset image may be a .png image of size 1024x1024, 1024x2048, 2048x2048 or even 4096x4096 pixels (depending on your needs). To make things easier, work with two grids simultaneously:
- A basic grid of 16x16
- A block-level grid of 128x128
Tip!
- Imaging software (such as GIMP) have the ability to work with grids. Enable the 16x16 grid in your software. Activate the option snap to grid, so that your grid becomes "magnetic". Create a separate grid of 128x128 pixels by making a custom image and display it on top of your brickset - in a separate layer - while you're working on your art.
In addition to the artwork, you may specify a collision mask: an image that specifies the solidity of each pixel of the bricks. A collision mask gives you a finer amount of control regarding how the collisions should be handled. Sometimes collisions require manual inspection, so it's better to create a mask.
How to create a collision mask
- Art and collision mask are split into different files. Once the artwork is ready, the mask can be created easily by copying the image and deciding which parts are solid and which aren't. A mask has two basic colors: magenta means non-solid. You may use black as solid. Artwork and mask must be aligned (share the same position in the image).
- Collision masks must be smooth and should have no "holes" in it (see the example on the side). Pay attention if your artwork is irregular: in this case you need to adjust the mask. Examples:
- 1. if you have a grass brick with lots of "spikes" on top of it, smooth it out: you don't really want "spiky" artifacts affecting the collisions.
- 2. if your artwork includes metallic grids or other features with holes in them, fill in the gaps: these artistic features must not affect the collisions.
If you follow these guidelines, writing the brickset script (.brk file) will be a piece of cake and shouldn't take more than a few minutes. You may either write the brickset script yourself or use automated tools.
Creating & finding artwork
Creating new scenery implies creating new artwork. You may create the artwork yourself, work with an artist, or find it online. There are many pixel art tutorials on the Internet, and OpenGameArt.org provides freely licensed art that you can use and remix.
Tip!
- When creating your artwork, you may find inspiration in the artwork that is shipped with Open Surge (explore the images/ folder). You can use that as a base to help you get started with your own artwork.
Using automated tools
When it comes to generating brickset scripts, you can either write them manually or use automated tools to do the job. The Quick Brickset Editor lets you quickly create bricksets. Also, although written some years ago, JBlocks or the Brickset Editor Tool can still be used today.
Writing the brickset
A brickset script is a text file that has one or more brick definitions.
brick
In the brickset script, every brick definition starts with brick and is followed by its number. Following a logical sequence is highly advisable. After the brick number comes a block containing a set of parameters that describe what the brick is.
A brick is defined like this:
brick 16 { type SOLID behavior DEFAULT mask "images/brickset_mask.png" // optional zindex 0.5 // optional sprite { source_file "images/brickset.png" source_rect 16 224 64 64 frame_size 64 64 animation { repeat TRUE fps 8 data 0 } } }
We'll now cover the brick parameters.
sprite
The sprite block describes the graphical properties of the brick - how it's going to be displayed on the screen. For more information, read the Sprites page.
type
The type will tell the physics core how to handle collisions with this brick.
SOLID
SOLID means: a solid brick
Note: in versions of the engine prior to 0.5.0, the solid brick type was called OBSTACLE.
PASSABLE
PASSABLE means: you can pass through it (it's a non-solid brick, meaning that it doesn't affect collisions)
CLOUD
CLOUD means: you can go to the top of it from below, but not the opposite. Also known as "one-way platforms".
mask
A collision mask is a mechanism that specifies which parts of the bricks are solid and which parts aren't. This gives you a finer amount of control regarding how the collisions should be handled. Example: if you have a "grass" brick with lots of "spikes" on the top, most likely you don't want the "spiky" artifacts to affect the collisions. Collision masks must always be smooth and should not have any "holes".
Usually, a collision mask is represented by a .png image with two colors only: magenta (if the pixel is non-solid) and black (if the pixel is solid). The collision mask image must be aligned with the brick image, so that the brick and its mask get to be on the same position (although they are on different images, they share the same position). If the brick is animated, the collision mask of the brick must be at the location of the first frame of the animation.
This is an optional parameter. If not specified, the engine will assign a collision mask automatically: pixels will be solid if they are not transparent (magenta). Depending on your artwork, this may not be desirable, so creating your own mask is a good idea.
// path to the mask image mask "images/brickset_mask.png"
zindex
Usually a value between 0.0 and 1.0, zindex specifies the order in which bricks are rendered to the screen. Bricks with a large zindex will be displayed in front of others. Bricks with a small zindex will be rendered behind others. Finally, a brick will be drawn behind the player if, and only if, its zindex is lower or equal to 0.5.
This is an optional parameter. If not specified, it defaults to 0.5.
// the brick will be rendered in front of others that have a lower zindex zindex 1.0
// bricks with a higher zindex will be rendered in front of this one zindex 0.1
behavior
The behavior specifies the kind of movement or behavior the brick will adopt.
DEFAULT
DEFAULT means: a brick that stands still, with no special behavior. This is the behavior that is likely to be used in most cases. Example:
// a regular brick type SOLID behavior DEFAULT
The syntax above shows just the type and the behavior of a brick; a more complete brick definition would be as follows:
// This is just an example brick 154 { type SOLID behavior DEFAULT zindex 0.5 mask "images/waterworks_mask.png" sprite { source_file "images/waterworks.png" source_rect 512 768 32 32 frame_size 32 32 animation { repeat TRUE fps 8 data 0 } } }
FALL
FALL means: the brick will collapse and be destroyed upon being stepped on. Example:
// syntax: behavior FALL horizontal-pieces vertical-pieces [orientation] // whenever the player steps on the brick, it will collapse into (horizontal-pieces x vertical-pieces) parts type SOLID behavior FALL 8 2
An optional orientation parameter may be specified:
- If orientation is non-negative (e.g., orientation = 1), the brick collapses from the right to the left (default)
- If orientation is negative (e.g., orientation = -1), the brick collapses from the left to the right
BREAKABLE
BREAKABLE means: the player can destroy the brick by rolling on it. Example:
// syntax: behavior BREAKABLE horizontal-pieces vertical-pieces // the brick will be broken in 25 pieces (5x5) of equal size type SOLID behavior BREAKABLE 5 5
SMASHABLE
SMASHABLE means: a brick that can be smashed when the player jumps on top of it. Similar to BREAKABLE.
Note: the SMASHABLE behavior was added in Open Surge 0.5.0.
// syntax: behavior SMASHABLE horizontal-pieces vertical-pieces // a smashable brick that will be broken in 2 pieces, horizontally type SOLID behavior SMASHABLE 2 1
FLOAT
FLOAT means: a brick that goes slightly down when the player steps on top of it. An optional modifier parameter may be specified:
- If no modifier is specified: the floating brick does nothing special
- If modifier = 1: the floating brick falls down after the player steps on top of it
Note: the FLOAT behavior was added in Open Surge 0.5.0.
// syntax: behavior FLOAT [modifier] type SOLID behavior FLOAT
CIRCULAR
CIRCULAR specifies a movable platform that moves along an ellipse.
// // syntax: behavior CIRCULAR x-dist y-dist x-speed y-speed [initial-phase] // // x-dist and y-dist specify how wide/tall is the movement of the brick, in pixels // x-speed and y-speed specify the cycles per second rate // (try setting both to 0.25; the larger the value, the faster the brick) // initial-phase is an optional value in degrees typically set to 0 (default) or 180 (opposite phase) // // Example 1: the brick will move horizontally. The trajectory has an amplitude // of 128 pixels (to left and to right, meaning that it is 256 pixels wide), and // the brick completes 25% of a cycle in a second (meaning it takes 4 seconds // to complete a cycle). type CLOUD behavior CIRCULAR 128 0 0.25 0 0 // Example 2: the brick will move along a circle of radius 128 pixels, // at a rate of 0.25 cycles per second type CLOUD behavior CIRCULAR 128 128 0.25 0.25 0 // Example 3: a brick like example 2, but in the opposite phase type CLOUD behavior CIRCULAR 128 128 0.25 0.25 180
PENDULAR
PENDULAR specifies a brick that swings like a pendulum.
Note: the PENDULAR behavior was added in Open Surge 0.5.0.
// // syntax: behavior PENDULAR radius cycles-per-second [initial-phase [angular-offset [amplitude-offset]]] // // radius is the distance between the brick (e.g., the weight of the pendulum) and the pivot, in pixels // cycles-per-second is typically set to 0.25 (meaning it takes 4 seconds to complete one cycle) // initial-phase is a value in degrees typically set to 0 (default) or 180 (opposite phase) // angular-offset controls the direction of the swing and is typically set to 0 (default) or 180 degrees // amplitude-offset controls the amplitude of the swing and may be set to 0 (default), -30, -45, -60, -90... // // the following is a standard pendular brick with a radius of 128 pixels // moving at a rate of 0.25 cycles per second (one cycle takes 4 seconds) type CLOUD behavior PENDULAR 128 0.25 // a similar pendular brick, but in the opposite phase type CLOUD behavior PENDULAR 128 0.25 180
MARKER
A MARKER is a brick that is only rendered in the editor. Used to complement collisions.
Note: the MARKER behavior was added in Open Surge 0.5.0.
// a marker won't be rendered during gameplay type SOLID behavior MARKER
angle
The "angle" parameter is deprecated and should no longer be used. It's ignored by current versions of the engine. If, however, you're using a legacy version of Open Surge (0.2.0), then this information still applies. In this case, though, you're strongly encouraged to upgrade.
Previous versions of Open Surge used a parameter called angle. The angle told the system whether the brick was a floor, a wall, a ceiling, or a slope. 0º was usually flat ground, 90º a right wall, 180º a ceiling and 270º a left wall. Anything in between these values were slopes.
Now, how exactly did you calculate the angle? Suppose you have a slope like the one below. To calculate the angle, you used some basic math:
As you can see, the angle was measured from the positive x-axis. A plain floor would have 0 degrees. Simple walls/blocks (on which the player can't run through them, vertically) also would have an angle of 0 degrees. For slopes such as the one displayed on the picture above, function atan2(y,x) would give the angle.