A Magical Tree Generator
In this post, I'll show you how to do what you've always wanted. Namely a magical tree generator - and of course, learn V in the making of this.
This will all be done in exactly 90 lines of code.
V
First of all, what is V? This is easy, I'll just simply refer you to my other post: madco.me/code-in-v
Tree Generator
Let's get started!
As V is much like Go in it's code, we need a module and some imports
module main
import gg
import gx
import math
import rand
import sokol.sapp
These are just a few things V provides for us to use, and that we'll need.
gg
is our drawing tool, think of it as the plain ol' plaint buddy from MS.gx
is the a plalette of colours for us to use.math
is forPI
.rand
to gain some randomness. We do not want the same thing multiple times.sokol.sapp
, to be honest, I have yet to figure this.
const (
win_width = 600
win_height = 600
)
This will be the size of our canvas.
struct App {
mut:
gg &gg.Context
}
This struct
will be in charge of drawing.
struct Branch {
mut:
x f32
y f32
cx f32
cy f32
rad f32
len f32
}
This struct, however, just simply a branch of our tree.
fn main() {
mut app := &App{
gg: 0
}
app.gg = gg.new_context({
bg_color: gx.rgba(255, 155, 155, 0)
width: win_width
height: win_height
use_ortho: true
create_window: true
window_title: 'Tree Vv'
keydown_fn: frame
user_data: app
})
app.gg.run()
}
This is more fun, but to keep this simple, just know that this will create our paint brush.
fn frame(c sapp.KeyCode, m sapp.Modifier, app &App) {
b1 := &Branch{
x: f32(win_width / 2)
y: f32(win_height)
cx: f32(win_width / 2)
cy: f32(win_height)
rad: f32(math.pi / 2)
len: rand.f32n(100)
}
app.gg.begin()
app.draw_branch(b1, 1)
app.draw_branch(b1, -1)
app.gg.end()
}
The frame
is where the fun happens! It's in charge of generating a new tree for every key-press.
We start with a simple branch, on X
& Y
positions, along with the old postions CX
& CY
.
We also generate the start radians, and a random length of the branch.
fn (app &App) draw_branch(b &Branch, mul f32) {
cos := f32(math.cos(b.rad))
sin := f32(math.sin(b.rad))
x_tmp := b.cx - cos * b.len
y_tmp := b.cy - sin * b.len
app.gg.draw_line(b.cx, b.cy, x_tmp, y_tmp, gx.black)
rad := rand.f32n(math.pi / 4)
b1 := &Branch{
x: b.cx
y: b.cy
cx: x_tmp
cy: y_tmp
rad: b.rad + rad * mul
len: b.len - rand.f32n(25)
}
if b1.len > 10 {
app.draw_branch(b1, 1)
app.draw_branch(b1, -1)
} else {
app.gg.draw_circle(b1.cx, b1.cy, 4, gx.white)
}
}
Here we simply calulate the branch's new X
& Y
positions. Re-use our old to as the new CX
& CY
.
We then draw a new line. Randomizes a number between 0
and PI / 4
, and generaets a new rbanch from those values.
If the length of our branch is then above 10
, we does the exact same thing again, becasue insanity, right?
If the branch's length is below or equals to 10
we draw a leaf.
Easy, right? The complete code is below my plug.
Shameless Plug
Before you turn to the complete code, please take a look at this beauty!
I'd recommend you to click on the image to gain access to a tree placeholder!
Our Generator
The generator we've just created will of not be as beautiful as the above out-put, but it's a start nonetheless.
Complete Code
module main
import gg
import gx
import math
import rand
import sokol.sapp
const (
win_width = 600
win_height = 600
)
struct App {
mut:
gg &gg.Context
}
struct Branch {
mut:
x f32
y f32
cx f32
cy f32
rad f32
len f32
}
fn main() {
mut app := &App{
gg: 0
}
app.gg = gg.new_context({
bg_color: gx.rgba(255, 155, 155, 0)
width: win_width
height: win_height
use_ortho: true
create_window: true
window_title: 'Tree Vv'
keydown_fn: frame
user_data: app
})
app.gg.run()
}
fn frame(c sapp.KeyCode, m sapp.Modifier, app &App) {
b1 := &Branch{
x: f32(win_width / 2)
y: f32(win_height)
cx: f32(win_width / 2)
cy: f32(win_height)
rad: f32(math.pi / 2)
len: rand.f32n(100)
}
app.gg.begin()
app.draw_branch(b1, 1)
app.draw_branch(b1, -1)
app.gg.end()
}
fn (app &App) draw_branch(b &Branch, mul f32) {
cos := f32(math.cos(b.rad))
sin := f32(math.sin(b.rad))
x_tmp := b.cx - cos * b.len
y_tmp := b.cy - sin * b.len
app.gg.draw_line(b.cx, b.cy, x_tmp, y_tmp, gx.black)
rad := rand.f32n(math.pi / 4)
b1 := &Branch{
x: b.cx
y: b.cy
cx: x_tmp
cy: y_tmp
rad: b.rad + rad * mul
len: b.len - rand.f32n(25)
}
if b1.len > 10 {
app.draw_branch(b1, 1)
app.draw_branch(b1, -1)
} else {
app.gg.draw_circle(b1.cx, b1.cy, 4, gx.white)
}
}
{ Best, Mads Bram Cordes }