Árbol con L-system
Una cadena reescrita cuatro veces por dos reglas y luego leída como movimientos de tortuga, un Line2D por rama.
El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.
Clases de Godot usadas
Line2DLabel
El código
scripts/main.gd
extends Node
const AXIOM: String = 'X'
const RULE_X: String = 'F+[[X]-X]-F[-FX]+X'
const RULE_F: String = 'FF'
const DEPTH: int = 4
const ANGLE: float = 24.0
const LENGTH: float = 16.0
const PER_FRAME: int = 5
var branches: Array[Line2D] = []
var grown: int = 0
func _ready() -> void:
_add_background()
var view: Vector2 = get_viewport().get_visible_rect().size
_grow(_expand(), Vector2(view.x * 0.5, view.y - 40.0))
for branch in branches:
branch.visible = false
_add_label('axiom %s, depth %d, angle %d degrees' % [AXIOM, DEPTH, int(ANGLE)], Vector2(40, 36))
_add_label('X -> %s' % RULE_X, Vector2(40, 66))
_add_label('F -> %s' % RULE_F, Vector2(40, 96))
print('the string is rewritten %d times and then read as turtle moves' % DEPTH)
func _process(_delta: float) -> void:
var target: int = mini(grown + PER_FRAME, branches.size())
while grown < target:
branches[grown].visible = true
grown += 1
func _expand() -> String:
var text: String = AXIOM
for i in DEPTH:
var next: String = ''
for symbol in text:
next += _rule(symbol)
text = next
return text
func _rule(symbol: String) -> String:
match symbol:
'X':
return RULE_X
'F':
return RULE_F
return symbol
func _grow(text: String, start: Vector2) -> void:
var at: Vector2 = start
var heading: Vector2 = Vector2.UP
var depth: int = 0
var stack: Array = []
for symbol in text:
match symbol:
'F':
var to: Vector2 = at + heading * LENGTH * pow(0.88, depth)
_add_branch(at, to, depth)
at = to
'+':
heading = heading.rotated(deg_to_rad(ANGLE))
'-':
heading = heading.rotated(-deg_to_rad(ANGLE))
'[':
stack.push_back({at = at, heading = heading, depth = depth})
depth += 1
']':
var saved: Dictionary = stack.pop_back()
at = saved.at
heading = saved.heading
depth = saved.depth
func _add_branch(from: Vector2, to: Vector2, depth: int) -> void:
var weight: float = clampf(float(depth) / 6.0, 0.0, 1.0)
var branch: Line2D = Line2D.new()
branch.points = PackedVector2Array([from, to])
branch.width = lerpf(7.0, 1.4, weight)
branch.default_color = Color('#8da5f3').lerp(Color('#8eef97'), weight)
add_child(branch)
branches.append(branch)
func _add_label(text: String, at: Vector2) -> void:
var label: Label = Label.new()
label.text = text
label.position = at
label.add_theme_color_override('font_color', Color('#999999'))
add_child(label)
func _add_background() -> void:
var background: ColorRect = ColorRect.new()
background.color = Color('#12141a')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)