How to use Random's Big Dumb Library: Game Engine 3
This is part 3 of a 3 part tutorial on how to make a basic game with Random's Big Dumb Library.
Other parts: Part 1, Part 2
This tutorial was originally going to expand on the game code from Part 2, but the example quickly became too large to properly show here. So, I'm just going to explain some concepts and functions.
Configuring the Textbox
Let's say you want to change the default font scaling for textboxes to 2. You'd do something like this:
TB$=TBCREATE$() 'Make the textbox parameter dictionary
'Now use TB$
The first two lines just create the dictionary. If you already have one, you don't want to recreate it. The last line sets the value for key "CHRSCL" to 2 in the TB$ dictionary. DICSETI is my library function to store integers by key within the dictionary. A dictionary is like an array that uses string indexes rather that numbers. In other languages, setting values in a dictionary might be as easy as TB["CHRSCL"]=2, but SmileBASIC doesn't have builtin dictionaries so we have to make them ourselves.
The "I" in DICSETI is "integer". There is also DICSETF for floating point values and DICSET for strings.
The textbox automatically adjusts everything for the larger character size. There are other useful settings; for instance, if you want the textbox to snap to the upper left instead of the lower left, you can do:
DICSETI "ANCR",(#UP OR #LEFT),TB$
Always remember to pass the textbox dictionary as the last argument. "ANCR" tells the textbox from which corner the X and Y offsets should go from. It defaults to the bottom left, so without changing X and Y you can move the textbox to the top left with the code above. You can also move the textbox wherever you want on screen (just keep in mind the anchor position).
Major Textbox Configuration Parameters
'Dictionary Key, Default Value 'What it does
"GPAGE", 0 'The GRP page the textboxes are drawn on
"TBX", 12 'Textbox X offset from anchor
"TBY", 12 'Textbox Y offset from anchor
"TBW", 376 'FULL width of the textbox (including borders, etc.)
"TBH", 68 'FULL height of the textbox
"TXTX", 12 'Text horizontal offset WITHIN textbox (so 12 from left border)
"TXTY", 12 'Text vertical offset WITHIN textbox
"TXTW", 352 'Width of text within textbox (warning: must calculate width yourself)
"TXTH", 44 'Height of text within textbox
"BDRW", 4 'Width of the textbox border
"LNSPC", 1 'Amount of extra vertical space between lines (0 means letters may touch)
"ANCR",(#DOWN OR #LEFT) 'Corner used for X and Y offset
"ANIMTM", 8 'Frames of show/hide animation
"SCRLTM", 8 'Amount of frames used to scroll text
"TXTSPD", 2 'Frames between each character of output
"CNTBTN", #A 'Button used for advancing text
"SKPBTN", #B 'Button used for rushing text
"BGCOL", RGB(10,40,100) 'Background color
"CHRCOL", RGB(240,240,250) 'Text color
"BDRCOL", RGB(20,70,200) 'Border color
There are more configuration parameters; if you're interested, search for "TBCREATE" in RNDLIBFULL and find the function definition. It has all the configuration options there.
Setting the background, character, and border colors all the time can be a pain, especially if all you want to do is set a general color. The TBEASYCOL function will set all the colors automatically for you. It takes two parameters: a background color and the textbox (TB$ in our code from earlier). The border will be set to a color close to the chosen background color, and the text will become light or dark depending on the brightness of the color chosen.
Some examples on how to use TBEASYCOL:
TBEASYCOL RGB(68, 252, 101),TB$ 'Textbox background bright green, border slightly darker green, font black
TBEASYCOL RGB(50,50,50),TB$ 'Textbox background dark gray, border slightly lighter gray, font white
There are ways to insert a portrait inside the textbox (for stuff like RPGs), but you'll have to do it manually. It requires overriding the drawing function so you insert the portrait afterwards, then shifting the text over and reducing the width to make room for the portrait.
Terrain Generation + Map Stuff
Terrain is usually created by generating an array of random values called "noise", then using those values to place land and features. For instance, let's say you're making a randomly generated forest. You might generate a 2D array of random noise values from 0 to 1.0, then for each index in the array, if the value is less than 0.5 it's a tree, if it's between 0.5 and 0.6 it's a rock, etc.
The library comes with several functions useful for generating noise. The best one (in my opinion) is DIAMONDSQUARE2D# and its counterpart DIAMONDSQUAREFIT2D. You can play with this generators in the "Noise" option in RNDLIBTEST.
I explain how DIAMONDSQUARE works in Diamond Square Noise and Plasma Effect.
DIAMONDSQUARE2D# produces a 2D array of values ranging from 0 to 1. The size of size array is dependent on the parameters, and it's not perfectly straightforward to make the array the size you want. Instead, you can use DIAMONDSQUAREFIT2D and it will generate an array as close to the size you give as possible (always larger if the size can't be matched).
Here's an example of the difference between DIAMONDSQUARE2D# and DIAMONDSQUAREFIT2D:
DIM DS#[0,0] 'Array to hold noise. Size will be set in function.
DS#=DIAMONDSQUARE2D#(3,16,16,MILLISEC,0.8,1.0) 'Now DS# is an array of noise of size POW(2,3)*16+1
DIM DS#[0,0] 'Still have to initialize array
DIM WD,HT 'You also get the width and height from this function
DIAMONDSQUAREFIT2D 3,100,100,MILLISEC,0.8,1.0 OUT DS#,WD,HT
'Now DS# is array of noise with size WD,HT (which is at least 100x100)
There's almost no reason to use the regular DIAMONDSQUARE2D; it's only there in case you need the absolute raw set count (the second two parameters).
Placing tall BG tiles
It is common in games to have something tall (like a tree) be more than 1 tile tall with the ability to walk "behind" it. It gives the illusion that the thing is tall. Usually this is accomplished by placing the bottom on "this" layer and placing the top on the "next" layer:
Let's say you have a tree that's drawn on GRP5 (the BG definition layer) just like above: 2 tiles tall. If you want to place the bottom on layer 1 like in the example, you can use the following library code:
Where ID is the ID of the top left tile, 1 is the width in tiles, 2 is the height in tiles, X and Y are where you want to put the BOTTOM left tile, 1 is the layer for the bottom tiles, and 16 is the tile size. You can use this function to place any size thing: we used 1,2 here for the 2 tall 1 wide tree, but you can use any values here. Just make sure the ID is always the ID of the top left corner.
This function does proper horizontal and vertical flipping: if you set the vertical flip bit in the passed in ID, that tree would show up upside down instead of only each tile being flipped individually.
There is also a function to clear big tiles. You can call this function on ANY of the lower-row tiles (regardless of flipping or size) and it will properly remove the entire thing. For instance, there is a fancy 2x2 building at ID 177 on the default BG. Let's see how you would place that building at 5,5 on layer 0 and then remove it:
BGPUTTALL 177,2,2,5,5,0,16 'Place fancy building's LOWER LEFT tile at 5,5
CLEARED=BGCLEARTALL(177,2,2,5,50,16) 'Clear the entire building
BGCLEARTALL returns whether or not the tall thing was cleared. This is because the tall thing might not be at the location you specified.
In the above example, it would've also worked if you tried to clear at 6,5: it's still a bottom tile in the set (the lower right).