Backgrounds in the Butano Game Engine, like Sprites, must be added to your project as bitmap images. You can view the basics of the Butano project structure here: Butano Project Structure for Making GBA games. The width and height of your background must both be multiple’s of 256px. With limit being above 4096×4096.
With your bitmap created, and added to the “graphics” folder, you should create a matching .json file. There are multiple types of assets in the Butano Game Engine, as you can see here: Butano Docs – Importing Assets. For this tutorial, we’ll be using a regular background. Here’s a basic background i found online, and edited slightly in Aseprite. It’s 256x156px in size.
I’ll name it clouds.bmp, and create a matching clouds.json.
Important Note: All graphics (sprites and backgrounds) must have all lowercase names. Also if you see an error, like “oceanbackground.bmp error: Invalid bits per pixel: 24” make sure you are exporting with an indexed palette.
{
"type":"regular_bg"
}
Including your regular background in your code
After you run your project’s ‘make’ command, you’ll have a new bn_regular_bg_items_clouds.h file (in your project’s “build” folder). Include that, and the “bn::regular_bg_ptr” class into your main.cpp file:
#include <bn_regular_bg_ptr.h>
#include "bn_regular_bg_items_clouds.h"
Creating a background Pointer
Important Reminder: This should be done AFTER your call to “bn::core::init()“
bn::regular_bg_ptr clouds = bn::regular_bg_items::clouds.create_bg();
Once you recompile and run your ROM file, you should have a basic background:
Background translation
Like with sprites, we can move the background around on the x or y axis. It’s graphics will loop around as your scroll. However, with regular backgrounds, we cannot scale or rotate them.
bn::regular_bg_ptr clouds = bn::regular_bg_items::clouds.create_bg();
while(true)
{
bn::core::update();
clouds.set_x(clouds.x()+bn::fixed(.2));
}
once compiled, you would see your background moving to the right, like so:
Multiple Backgrounds
The Game Boy Advance supports a total of 4 different backgrounds. Each can be individually controlled. Transparency is also supported on each background, allowing for very cool layer effects. Let’s add two more backgrounds on top! The other half of the previous ocean background, and a ground background,. Below i have “ground.bmp“ and “water.bmp“.
Note: The purple is the first color in the palette, and will be transparent.
I’ll need to create a matching “ground.json” and “water.json” file. Both of which, are the same:
{
"type":"regular_bg"
}
We’ll include them create pointers, and move them to the right also (but at different speeds).
#include "bn_core.h"
#include <bn_keypad.h>
#include <bn_regular_bg_ptr.h>
#include <bn_camera_ptr.h>
#include <bn_sprite_ptr.h>
#include "bn_sprite_items_testplayer.h"
#include "bn_regular_bg_items_water.h"
#include "bn_regular_bg_items_clouds.h"
#include "bn_regular_bg_items_ground.h"
int main()
{
bn::core::init();
bn::regular_bg_ptr water = bn::regular_bg_items::water.create_bg();
bn::regular_bg_ptr ground = bn::regular_bg_items::ground.create_bg();
bn::regular_bg_ptr clouds = bn::regular_bg_items::clouds.create_bg();
while(true)
{
bn::core::update();
clouds.set_x(clouds.x()+bn::fixed(.2));
water.set_x(water.x()+bn::fixed(1));
ground.set_x(ground.x()+bn::fixed(4));
}
}
The result is a layered parallax scroll effect:
By default, they are drawn in the order you create the pointers. You can change which order they are rendered using the “bn::regular_bg_ptr::set_z_order(int)” function.
Removing Backgrounds
Like with sprites, backgrounds will automatically remove themselves when they go out of scope. Alternatively, you can use “bn::optional“s or hold the pointers in a bn::vector.
#include <bn_core.h>
#include <bn_keypad.h>
#include <bn_vector.h>
#include <bn_regular_bg_ptr.h>
#include <bn_camera_ptr.h>
#include <bn_sprite_ptr.h>
#include "bn_sprite_items_testplayer.h"
#include "bn_regular_bg_items_water.h"
#include "bn_regular_bg_items_clouds.h"
#include "bn_regular_bg_items_ground.h"
// Vector from #include <bn_vector.h>
bn::vector<bn::regular_bg_ptr,3> vectorOfRegularBackgrounds;
// Optional is part of #include <bn_core.h>
bn::optional<bn::regular_bg_ptr> optionalGround;
int main()
{
// We NEVER create anything before this!
bn::core::init();
{
// The clouds background will only last inside of the this scope (defined by the curly brackets)
bn::regular_bg_ptr clouds = bn::regular_bg_items::clouds.create_bg();
// The water background will last until it's removed from the tree
vectorOfRegularBackgrounds.push_back(bn::regular_bg_items::water.create_bg());
// The ground background is optional, with it's value set it will last until we change that value or reset the optional
optionalGround = bn::regular_bg_items::ground.create_bg();
// Wait for a to be pressed
while(!bn::keypad::a_pressed())bn::core::update();
}
// When this part of the code is reached, the clouds background has gone out of scope and will be removed
while(true)
{
bn::core::update();
// Wait for 'A' to be pressed
if(bn::keypad::a_pressed()){
// This will remove the water background, whose pointer was in this vector
vectorOfRegularBackgrounds.clear();
}
// Wait for 'B' to be pressed
if(bn::keypad::b_pressed()){
// This will remove the ground background, which was optional
// Make sure to always test for an actual value
if(optionalGround.has_value())optionalGround.reset();
}
}
}
Conclusion
That’s the basics of drawing backgrounds. for the sake of clarity the graphics were all separate bitmaps. But you could have them all defined a single bitmap, and use the “height” property to let Butano know how to split them.
Be sure to check out the tutorial on drawing sprites to add objects to your world.