-
-
Notifications
You must be signed in to change notification settings - Fork 33
bricksets
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 three elements: image, script and collision mask.
No brickset would ever exist without the image in which the bricks are drawn. 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 was increased in Open Surge 0.5.2. Open Surge 0.2.0 (legacy) had no hard limit, but it was not hardware accelerated.
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 to know what exactly the bricks are. The physics subsystem take care of the rest once you're done placing the bricks in your levels.
The brickset script references the brickset image. It specifies 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.
In addition to the artwork, you may specify a collision mask, which is 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. Though optional, having a collision mask is highly recommended. Sometimes collisions require manual inspection, so it's better to create a 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 rgb(255,0,255)
or transparent rgba(0,0,0,0)
means non-solid. You may use black rgb(0,0,0)
as solid. Artwork and mask must be aligned (i.e., share the same position in image space).
Collision masks must be smooth and should have no "holes" in it. Pay attention if your artwork is irregular: in this case you need to adjust the mask. Examples:
- 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.
- 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.
See also: mask.
Creating new scenery is related to 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. Additionally, OpenGameArt 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.
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 create.
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". You may create a separate grid of 128x128 pixels by drawing a custom image and display it on top of your brickset - in a separate layer - while you're working on your art.
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.
Brickset scripts can be written manually or can be generated automatically using tools such as the Quick Brickset Editor. Although written years ago, JBlocks and the Brickset Editor Tool can still be used today.
A brickset script is a text file that has one or more brick definitions.
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.
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.
The type
will tell the physics core how to handle collisions with this brick.
SOLID
means: a solid brick. You can't go through them.
Note
In versions of the engine prior to 0.5.0, the solid brick type was called OBSTACLE.
PASSABLE
means: you can pass through it. It's a non-solid brick, meaning that it doesn't affect collisions. Many scenery elements are passable bricks.
CLOUD
means: you can go to the top of it from below, but not the opposite. Cloud bricks are also known as "one-way platforms".
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 rgb(255,0,255)
or transparent rgba(0,0,0,0)
(if the pixel is non-solid) and black rgb(0,0,0)
(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.
Even though creating a collision mask is optional, it's highly recommended to do so. If this parameter is not specified, the engine will create 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"
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
The behavior
specifies the kind of movement or behavior the brick will adopt.
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
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
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
means: a brick that can be smashed when the player jumps on top of it. Similar to BREAKABLE.
Since: 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
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
is1
: the floating brick falls down after the player steps on top of it
Since: 0.5.0
// syntax: behavior FLOAT [modifier]
type SOLID
behavior FLOAT
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
specifies a brick that swings like a pendulum.
Since: 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
A MARKER
is a brick that is only rendered in the editor. It's used to complement collisions.
Since: 0.5.0
// a marker won't be rendered during gameplay
type SOLID
behavior MARKER
The angle
parameter is deprecated and should no longer be used. It's ignored by current versions of the engine. It was used in the legacy version of Open Surge, 0.2.0.
The angle
parameter told the engine 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, to calculate the angle, you used some basic math. The angle was measured from the positive x-axis. A plain floor would have an angle of 0º. Simple walls/blocks (on which the player can't run through them, vertically) would also have an angle of 0º. For slopes, function atan2(y,x)
would return the angle.