class_name Vine extends Node2D @export var petal_location : Vector2 @export var petal_offset : Vector2 @export var vine_locations : Array[Vector2] @export var bud_resource : PackedScene var img_path_inactive = "res://vines_petals/vine_inactive.png" @export var img_path_active : String const status_data = [ { "name": "Slow", "params" : {}, "img_path": "res://vines_petals/vine_active_green.png" }, { "name": "Vulnerable", "params" : {}, "img_path": "res://vines_petals/vine_active_purple.png" },] var status_name : String var status_params : Dictionary = {} var active_depth = -1 var fully_active = false var vine_data = [] var max_depth = 150 var vine_end_data = [] func _ready() -> void: var data : Dictionary = status_data.pick_random() status_name = data.name status_params = data.params if data.has("params") else {} img_path_active = data.img_path func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int): var sprite = Sprite2D.new() get_tree().get_root().get_node("main").add_child(sprite) if active_depth >= depth: sprite.texture = ResourceLoader.load(img_path_active) else: sprite.texture = ResourceLoader.load(img_path_inactive) while depth + 1 > vine_data.size(): vine_data.append([]) vine_data[depth].append(sprite) sprite.position = (pos1 + pos2)/2.0 sprite.rotation = (pos1 - pos2).angle() + PI/2 sprite.scale *= (pos1 - pos2).length() * 1 / sprite.texture.get_width() sprite.scale.x = 3 sprite.z_index = -1 func grow_vine_sequence(location1 : Vector2, offset1 : Vector2, location2: Vector2, offset2 : Vector2, num_segments: int, depth: int, grow_bud = false, quick_spawn = false): depth = min(depth, max_depth) var pos1 = Grid.get_world_position(location1, offset1) var pos2 = Grid.get_world_position(location2, offset2) var positions = [] positions.append(pos1) var segment_length = (pos1 - pos2).length() / num_segments var offsets = generate_random_offsets(num_segments, 0.6 * segment_length) for i in range(num_segments - 1): var t = (i + 1) * 1.0/num_segments var center = t * pos2 + (1 - t) * pos1 var offset = offsets[i + 1] * (pos2 - pos1).normalized().rotated(PI/2) positions.append(center + offset) positions.append(pos2) for i in range(num_segments): draw_vine(positions[i], positions[i+1], depth + i + 1) if not quick_spawn: await get_tree().create_timer(0.2).timeout if active_depth >= depth + num_segments: if grow_bud and location2.y > 0 and location2.y <= Grid.max_bud_height: spawn_bud(location2, offset2, depth + num_segments) else: if location2.y > 0 and location2.y <= Grid.max_bud_height: for i in range(vine_end_data.size()): if vine_end_data[i].location == location1: vine_end_data.remove_at(i) break vine_end_data.append({"location": location2, "offset": offset2, "depth": depth+num_segments}) Grid.vines_per_node[location2.x][location2.y].append(self) vine_locations.append(Global.vec_mod(location2, Grid.num_collumns)) func generate_random_offsets(segment_count, max_second_derivative): var differences = [] var last_diff = 0 for i in range(segment_count): var new_diff = last_diff + randf_range(-max_second_derivative, max_second_derivative) differences.append(new_diff) last_diff = new_diff var sum = 0.0 for i in range(segment_count): sum += differences[i] var correction = - sum / segment_count for i in range(segment_count): differences[i] += correction var ret = [] var next_val = 0 for i in range(segment_count): ret.append(next_val) next_val += differences[i] return ret func spawn_bud(location, offset, depth): var bud = bud_resource.instantiate() bud.location = location bud.offset = offset bud.vine = self bud.depth = depth get_tree().get_root().get_node("main").add_child(bud) func activate(): update_active_depth() func update_active_depth(): if active_depth < max_depth: await get_tree().create_timer(0.15).timeout active_depth += 1 if vine_data.size() > active_depth: for sprite in vine_data[active_depth]: sprite.texture = ResourceLoader.load(img_path_active) for data in vine_end_data: if data.depth == active_depth: spawn_bud(data.location, data.offset, data.depth) update_active_depth() func init_random(): Grid.vines_per_node[petal_location.x][petal_location.y].append(self) vine_locations.append(petal_location) vine_end_data.append({"location": petal_location, "offset": petal_offset, "depth": 0}) for i in range(randi_range(2,2)): var end = vine_end_data.pick_random() var branches_count = 0 for branch in range(ceil(randf() * 4)): var dir = [Vector2.UP, Vector2.DOWN, Vector2.RIGHT, Vector2.LEFT].pick_random() var target = Global.vec_mod(end.location + dir, Grid.num_collumns) if target.y <= Grid.max_bud_height + 1 and Grid.vines_per_node[target.x][target.y].is_empty(): if not (target.y <= 0 or target.y > Grid.max_bud_height): branches_count += 1 var target_offset = random_offset() var pos1 = Grid.get_world_position(end.location, end.offset) var pos2 = Grid.get_world_position(target, target_offset) var num_seg = floor((pos1-pos2).length() / 96) grow_vine_sequence(end.location, end.offset, target, target_offset, num_seg, end.depth, true, true) if i==0 and branches_count == 1: vine_end_data.append({"location": petal_location, "offset": petal_offset, "depth": 0}) func random_offset(): return Vector2(randf_range(60, 240), randf_range(90, 270))