diff --git a/utils/grid_node.gd b/utils/grid_node.gd index 1bca244..ee2e78b 100644 --- a/utils/grid_node.gd +++ b/utils/grid_node.gd @@ -31,3 +31,7 @@ func _enter_grid() -> void: func _init(_location = Vector2.ZERO, _offset = Vector2.ZERO): location = _location offset = _offset + +static func random_at(_location): + var rand_offset = Vector2(randf_range(60, 240), randf_range(90, 270)) + return GridNode.new(_location, rand_offset) diff --git a/vines_petals/bud.gd b/vines_petals/bud.gd index 4bd3b02..7462bd9 100644 --- a/vines_petals/bud.gd +++ b/vines_petals/bud.gd @@ -23,5 +23,5 @@ func spread(): # Grow a vine func grow_to_next_bud(dir): var target_location = Global.vec_mod(location + dir, Grid.num_collumns, true) - var target = vine.random_vine_node_at(target_location) + var target = GridNode.random_at(target_location) await vine.grow_vine_sequence(self, target, true, false) diff --git a/vines_petals/vine.gd b/vines_petals/vine.gd index 697d548..fb94b6e 100644 --- a/vines_petals/vine.gd +++ b/vines_petals/vine.gd @@ -31,7 +31,7 @@ var status_params : Dictionary = {} # When max depth is reached, everything is active from then on. var active_depth = -1 var fully_active = false -var max_depth = 10 +var max_depth = 50 # Array containings lists of sprites, using their depths as index var vine_data = [] @@ -86,21 +86,29 @@ func grow_vine_sequence(start : GridNode, target: GridNode, grow_bud = false, qu if not quick_spawn: await get_tree().create_timer(0.2).timeout + # If growing while active, place buds if active_depth >= depth + num_segments or fully_active: if grow_bud and target.location.y > 0 and target.location.y <= Grid.max_bud_height: spawn_bud(target.location, target.offset, depth + num_segments) else: + # Otherwise, remember the spot to spawn a bud later. + # Further, note that the previous location is no longer a leaf unless it is the petal. if target.location.y > 0 and target.location.y <= Grid.max_bud_height: for i in range(vine_end_data.size()): - if vine_end_data[i].location == start.location: + if vine_end_data[i].location == start.location and not vine_end_data[i] is Petal: vine_end_data.remove_at(i) break target.depth = depth + num_segments vine_end_data.append(target) + + # Register the new vine segment in the grid Grid.add_vine_to(self, target.location) vine_locations.append(Global.vec_mod(target.location, Grid.num_collumns, true)) +# Generates a random function on (segment_count - 1) +# many grid points with bounded second derivative func generate_random_offsets(segment_count, max_second_derivative): + # First, randomize the derivative of the desired function var differences = [] var last_diff = 0 for i in range(segment_count): @@ -108,11 +116,15 @@ func generate_random_offsets(segment_count, max_second_derivative): differences.append(new_diff) last_diff = new_diff var sum = 0.0 + + # Shift that derivative by a constant to add up to 0 for i in range(segment_count): sum += differences[i] var correction = - sum / segment_count for i in range(segment_count): differences[i] += correction + + # Return the partial sums over the derivative constructed above var ret = [] var next_val = 0 for i in range(segment_count): @@ -120,6 +132,7 @@ func generate_random_offsets(segment_count, max_second_derivative): next_val += differences[i] return ret +# Instantiates a bud func spawn_bud(location, offset, depth): var bud = bud_resource.instantiate() bud.location = location @@ -128,9 +141,13 @@ func spawn_bud(location, offset, depth): bud.depth = depth get_tree().get_root().get_node("main").add_child(bud) +# Upon activation start the process of slowly increasing the active depth func activate(): - update_active_depth() + if active_depth < 0: + update_active_depth() +# Progressively activate the vine by retexturing its sprites and spawning buds if neccessary +# Once max_depth is reached, fully activate the vine func update_active_depth(): if active_depth < max_depth: await get_tree().create_timer(0.15).timeout @@ -138,12 +155,13 @@ func update_active_depth(): 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) + for node in vine_end_data: + if node.depth == active_depth and not node is Petal: + spawn_bud(node.location, node.offset, node.depth) update_active_depth() else: fully_active = true +# Upon entering the scene, select the applied status, then spawn the inactive vine func _enter_tree() -> void: var data : Dictionary = status_data.pick_random() status_name = data.name @@ -151,27 +169,21 @@ func _enter_tree() -> void: img_path_active = data.img_path init_random() -func random_vine_node_at(location): - var offset = random_offset() - return GridNode.new(location, offset) - +# Initializes a random vine func init_random(): + # First, include the petal Grid.add_vine_to(self, petal.location) vine_locations.append(petal.location) vine_end_data.append(petal) - for i in range(randi_range(2,2)): + # Attempt to grow a new vine for a total 6 - 12 times + var grow_attempts = randi_range(6,12) + while grow_attempts > 0: + # Attempt to grow from a random end to 1 - 4 random directions var end = vine_end_data.pick_random() - var branches_count = 0 - for branch in range(ceil(randf() * 4)): + for branch in range(min(ceil(randf() * 4), grow_attempts)): + grow_attempts -= 1 var dir = [Vector2.UP, Vector2.DOWN, Vector2.RIGHT, Vector2.LEFT].pick_random() var target_location = Global.vec_mod(end.location + dir, Grid.num_collumns, true) if target_location.y <= Grid.max_bud_height + 1 and Grid.get_vines_at(target_location).is_empty(): - if not (target_location.y <= 0 or target_location.y > Grid.max_bud_height): - branches_count += 1 - var target = random_vine_node_at(target_location) + var target = GridNode.random_at(target_location) grow_vine_sequence(end, target, true, true) - if i==0 and branches_count == 1: - vine_end_data.append(petal) - -func random_offset(): - return Vector2(randf_range(60, 240), randf_range(90, 270))