Making brush scripts, part 7
Main employs an assistant: Minion in command
When it comes to doing the same things over and over, like drawing a hexagon, our function main has better things to do. He’s a chief minion with responsibilities, not just another simple minion like bs_ellipse. Why not hand over this repetitive busywork to some hoodlum … er, henchman... I meant, assistant!
FireAlpaca doesn’t provide a ready-made minion to draw polygons. However, here’s the exciting bit: We can create our own function minion (doesn’t that just give you chills!), more sophisticated than those simple variable-bots, for main to boss around and pass on some of these repetitive tasks.
Let’s create a function minion, called draw_hexagon, to draw a hexagon at 0, 0, move it to the cursor position, and rotate it to the brush direction.
main needs to tell it the current brush width - draw_hexagon could ask for that on its own, but main has already used it to calculate whether to draw or not, so it is a waste asking again.
main also needs to tell it the cursor position (x, y) which it always knows.
We could also get main to give it the rotation angle, the current brush colour, etc. However, we’ll build it smart enough to ask for the colour and the rotation angle itself. All main has to do is say draw_hexagon(width, x, y).
function draw_hexagon(w, x, y)
bs_polygon(0.5, -0.87)
bs_polygon(-0.5, -0.87)
bs_polygon(-1, 0)
bs_polygon(-0.5, 0.87)
bs_polygon(0.5, 0.87)
bs_polygon(1, 0)
bs_polygon_mul(w, w) -- match the brush size
local dx,dy = bs_dir()
local rotation = bs_atan(dx, dy)
bs_polygon_rotate(rotation) -- rotate to follow cursor
bs_polygon_move(x, y) -- put polygon at the cursor location
local r, g, b = bs_fore()
local opacity = bs_opaque() * 255
bs_fill(r, g, b, opacity)
end
You will note that main says draw_hexagon(width, x, y) but draw_hexagon is listening for w, x, and y. Remember, width is a local-variable-memory-bot, a little sphere that hovers around main, it doesn’t get passed to draw_hexagon. However, most minions have their own automatic set of local-variable-bots to remember anything main says to them - these are created inside the parentheses (round brackets) when main tells them what to do.
So, when main says draw_hexagon(width, x, y) main actually says “use a size of ... what was that value, width?” and draw_hexagon says “w, remember that size” to its own memory-bot. main also says position “x, y”, but the x and y that draw_polygon uses, though they have the same name (for our convenience), are its own local-variable-bots, not main’s. main could just as easily say draw_hexagon(25, 250, 120) and draw_hexagon would still understand (and get its w, x, and y bots to remember).
You might also notice I’ve corrected the polygon size, so I don’t need to tweak the size multiplier by multiplying it by 0.1. We still need that size multiplier (using just the brush width on its own) so the brush size will match the pen pressure and current brush size slider.
This all makes main’s work list much simpler, by passing on repetitive work to draw_hexagon.
lastDrawX = 0
lastDrawY = 0
firstDraw = true
function draw_hexagon(w, x, y)
bs_polygon(0.5, -0.87)
bs_polygon(-0.5, -0.87)
bs_polygon(-1, 0)
bs_polygon(-0.5, 0.87)
bs_polygon(0.5, 0.87)
bs_polygon(1, 0)
bs_polygon_mul(w, w) -- match the brush size
local dx,dy = bs_dir()
local rotation = bs_atan(dx, dy)
bs_polygon_rotate(rotation) -- rotate to follow cursor
bs_polygon_move(x, y) -- put polygon at the cursor location
local r, g, b = bs_fore()
local opacity = bs_opaque() * 255
bs_fill(r, g, b, opacity)
end
function main(x, y, p)
local width = bs_width()
local updateDist = width*2
if not firstDraw then
local distance = bs_distance( lastDrawX - x, lastDrawY - y )
if distance < updateDist then
return 0
end
end
draw_hexagon(width, x, y)
lastDrawX = x
lastDrawY = y
firstDraw = false
return 1
end
See how life is simpler for main, now? It’s good to have a henchman an assistant.
In Lua, = is an “assignment” function, x = 25 is like saying make “x, remember 25 for me”
Using double equal signs, such as if x == 25 then, is an equality test, like asking x “hey, x,are you currently remembering 25? if so, then …” or “if x is remembering 25, then ...”
Suggestions for your own script: create two functions, set a variable-bot (outside main) to remember the last shape drawn, and draw alternating shapes, resetting the last drawn shape each time.
Here is some “pseudocode” (not real code you can cut and paste, you have to write your own stuff where it says “draw an ellipse” or “draw a hexagon”).
if lastDrawn == “hexagon” then
draw an ellipse – construct your own function to arrange this
lastDrawn = “ellipse”
else – lastDrawn must have been an ellipse
draw a hexagon
lastDrawn = “hexagon”
end