Fundamental adjustments and fixes for vine spawning
This commit is contained in:
parent
8786d30936
commit
49d48da550
14 changed files with 157 additions and 80 deletions
|
|
@ -17,15 +17,14 @@ func _ready() -> void:
|
|||
|
||||
await get_tree().create_timer(0.2).timeout
|
||||
if get_node_or_null("ObjectList") != null:
|
||||
var objects_to_be_placed = $ObjectList.get_children()
|
||||
$ObjectList.reparent(get_tree().get_root().get_node("main"), false)
|
||||
var obj_list = $ObjectList
|
||||
obj_list.reparent(get_tree().get_root().get_node("main"), false)
|
||||
await get_tree().create_timer(0.2).timeout
|
||||
var objects_to_be_placed = obj_list.get_children()
|
||||
for object in objects_to_be_placed:
|
||||
var offset = object.global_position;
|
||||
object.global_position = Grid.get_world_position(location, offset)
|
||||
# some objects, such as petals, require information about their position in the grid.
|
||||
if "location" in object: object.location = Grid.get_location_from_world_pos(object.global_position)
|
||||
if "offset" in object:
|
||||
object.offset = Global.vec_mod(offset, 300)
|
||||
|
||||
# The building remembers these objects: If it is destroyed, so are they.
|
||||
if object is Platform or object is Trap or object is Item:
|
||||
objects.append(object)
|
||||
|
|
@ -33,6 +32,14 @@ func _ready() -> void:
|
|||
# This scales platforms hoizontally to make sure they still form a floor without gaps.
|
||||
if(object.has_method("init_at_horizontal_distortion")):
|
||||
object.init_at_horizontal_distortion(object.position.length() / Grid.ground_radius)
|
||||
grid_entrance_callback(object)
|
||||
|
||||
func grid_entrance_callback(object : Node):
|
||||
# Objects receive a callback when placed, starting from the deepest children
|
||||
for child in object.get_children():
|
||||
grid_entrance_callback(child)
|
||||
if object.has_method("_enter_grid"):
|
||||
object.call_deferred("_enter_grid")
|
||||
|
||||
func overlaps(other : Building):
|
||||
# heights don't overlap
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ static var item_pool = ResourceLoader.load("res://items/generic/item_pool.tres",
|
|||
@export var unique_bonus_multiplier = .05
|
||||
@export var rare_bonus_multiplier = 0
|
||||
|
||||
@export var spawn_petal = false
|
||||
@export var petal_scene : PackedScene = ResourceLoader.load("res://petal.tscn")
|
||||
@export var spawn_petal = true
|
||||
@export var petal_scene : PackedScene = ResourceLoader.load("res://vines_petals/petal.tscn")
|
||||
|
||||
var packed_item_scene : PackedScene
|
||||
|
||||
var remove_after_spawn = false
|
||||
|
||||
|
|
@ -42,12 +44,13 @@ func _ready():
|
|||
# Pick a random pool and a random item from it, then remove it if unique.
|
||||
var pool = choose_pool()
|
||||
var index = randi_range(0, pool.size() - 1)
|
||||
var packed_scene : PackedScene = pool[index]
|
||||
packed_item_scene = pool[index]
|
||||
if remove_after_spawn:
|
||||
item_pool.unique.remove_at(index)
|
||||
|
||||
|
||||
# Place the item, possibly inside a petal
|
||||
var object = packed_scene.instantiate()
|
||||
if packed_item_scene == null: return
|
||||
var object = packed_item_scene.instantiate()
|
||||
add_child.call_deferred(object)
|
||||
object.reparent.call_deferred(get_parent())
|
||||
if spawn_petal: instantiate_petal(object)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://xj0of571aur1"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b8em61mqgdi58" path="res://items/generic/item_spawn.gd" id="1_ms6tn"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhhhvaqhm3ctc" path="res://petal.tscn" id="2_5to52"]
|
||||
[ext_resource type="PackedScene" uid="uid://bhhhvaqhm3ctc" path="res://vines_petals/petal.tscn" id="2_5to52"]
|
||||
[ext_resource type="PackedScene" uid="uid://chs0u61f45nau" path="res://utils/earth_aligner.tscn" id="3_5pwuf"]
|
||||
|
||||
[node name="ItemSpawn" type="Node2D"]
|
||||
|
|
|
|||
|
|
@ -236,6 +236,6 @@ func play_double_jump_animation() -> void:
|
|||
# If there is any vine nearby, gain the corresponding statusses.
|
||||
func update_vine_statuses():
|
||||
var location = Grid.get_location_from_world_pos(global_position)
|
||||
for vine : Vine in Grid.vines_per_node[location.x][location.y]:
|
||||
for vine : Vine in Grid.get_vines_at(location):
|
||||
if vine.active_depth > 0: #TODO: Properly manage procedural activation
|
||||
Status.apply(vine.status_name, self, 0.1, vine.status_params)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ var enemy_damage = 10
|
|||
@onready var dmg_id = Global.next_dmg_id
|
||||
var id_refreshing = false
|
||||
|
||||
func _ready() -> void:
|
||||
func _enter_grid() -> void:
|
||||
# Randomize starting position and rotation direction
|
||||
rotate(randf() * TAU)
|
||||
angular_speed = angular_speed * (2 * randi_range(0,1) - 1)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ var left : Vector2 :
|
|||
get():
|
||||
return global_from_local(Vector2.LEFT)
|
||||
|
||||
func _ready() -> void:
|
||||
func _enter_grid() -> void:
|
||||
align()
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@ static var next_dmg_id : int = 0 :
|
|||
return next_dmg_id
|
||||
|
||||
# Entrywise modulo
|
||||
static func vec_mod(vec : Vector2, modulus : float):
|
||||
return Vector2(fposmod(vec.x, modulus), fposmod(vec.y, modulus))
|
||||
static func vec_mod(vec : Vector2, modulus : float, only_x = false, only_y = false):
|
||||
return Vector2(
|
||||
fposmod(vec.x, modulus) if not only_y else vec.x,
|
||||
fposmod(vec.y, modulus) if not only_x else vec.y)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
class_name Bud extends VineNode
|
||||
signal opened
|
||||
var img_path
|
||||
@export var depth : int
|
||||
|
||||
# Triggers when a bud is hit. Spreads the vine, then removes the bud
|
||||
func _on_opened():
|
||||
|
|
@ -14,14 +13,11 @@ func _on_opened():
|
|||
# Spread in all directions where the given vine is not yet present
|
||||
func spread():
|
||||
for dir in [Vector2.UP, Vector2.DOWN, Vector2.RIGHT, Vector2.LEFT]:
|
||||
if not vine.vine_locations.has(Global.vec_mod(location + dir, Grid.num_collumns)):
|
||||
if not vine.vine_locations.has(Global.vec_mod(location + dir, Grid.num_collumns, true)):
|
||||
grow_to_next_bud(dir)
|
||||
|
||||
# Grow a vine
|
||||
func grow_to_next_bud(dir):
|
||||
var target_offset = vine.random_offset()
|
||||
var target = Global.vec_mod(location + dir, Grid.num_collumns)
|
||||
var pos1 = Grid.get_world_position(location, offset)
|
||||
var pos2 = Grid.get_world_position(target, target_offset)
|
||||
var num_seg = floor((pos1-pos2).length() / 96)
|
||||
await vine.grow_vine_sequence(location, offset, target, target_offset, num_seg, depth, true, false)
|
||||
var target_location = Global.vec_mod(location + dir, Grid.num_collumns, true)
|
||||
var target = vine.random_vine_node_at(target_location)
|
||||
await vine.grow_vine_sequence(self, target, true, false)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
class_name Petal extends Node2D
|
||||
@onready var location : Vector2 = Grid.get_location_from_world_pos(global_position)
|
||||
@onready var offset : Vector2 = Grid.get_offset_from_world_pos(global_position)
|
||||
class_name Petal extends VineNode
|
||||
@export var vine_resource : PackedScene
|
||||
var vine : Vine
|
||||
var activated = false
|
||||
|
||||
# Adding an item here automatically locks it inside the petal
|
||||
var item : Item:
|
||||
set(item_in):
|
||||
item = item_in
|
||||
|
|
@ -12,15 +11,14 @@ var item : Item:
|
|||
item.monitorable = false
|
||||
item.modulate = Color(1,1,1,0.8)
|
||||
|
||||
func _ready() -> void:
|
||||
await get_tree().create_timer(1).timeout
|
||||
# Upon being placed inside a building, create a vine
|
||||
func _enter_grid() -> void:
|
||||
depth = 0
|
||||
vine = vine_resource.instantiate()
|
||||
vine.petal_location = Global.vec_mod(location, Grid.num_collumns)
|
||||
vine.petal_offset = offset
|
||||
vine.petal = self
|
||||
get_parent().call_deferred("add_child",vine)
|
||||
await get_tree().create_timer(1).timeout
|
||||
vine.init_random()
|
||||
|
||||
# Upon interaction, release the item and activate the vine
|
||||
func _on_interaction() -> void:
|
||||
activated = true
|
||||
vine.activate()
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
[gd_scene load_steps=7 format=3 uid="uid://bhhhvaqhm3ctc"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://d15c1exwtp7sc" path="res://vines_petals/bud_open.png" id="1_05pvv"]
|
||||
[ext_resource type="Script" uid="uid://coi26l4ndnaw0" path="res://petal.gd" id="1_ybtdj"]
|
||||
[ext_resource type="Script" uid="uid://coi26l4ndnaw0" path="res://vines_petals/petal.gd" id="1_ybtdj"]
|
||||
[ext_resource type="PackedScene" uid="uid://b7o82cdfwuqd1" path="res://vines_petals/vine.tscn" id="2_4btcp"]
|
||||
[ext_resource type="PackedScene" uid="uid://ds21d77ruuk4y" path="res://utils/interactable_area.tscn" id="2_ybtdj"]
|
||||
[ext_resource type="PackedScene" uid="uid://chs0u61f45nau" path="res://utils/earth_aligner.tscn" id="5_uxqeq"]
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
class_name Vine extends Node2D
|
||||
@export var petal_location : Vector2
|
||||
@export var petal_offset : Vector2
|
||||
# Grid position data of the petal
|
||||
@export var petal : Petal
|
||||
|
||||
# Locations and offsets of all vine segments
|
||||
@export var vine_locations : Array[Vector2]
|
||||
@export var bud_resource : PackedScene
|
||||
|
||||
# Paths for vine segment sprites while active/inactive
|
||||
var img_path_inactive = "res://vines_petals/vine_inactive.png"
|
||||
@export var img_path_active : String
|
||||
|
||||
# The table from which to choose a status effect at random, including the corresponding vine color
|
||||
const status_data = [
|
||||
{
|
||||
"name": "Slow",
|
||||
|
|
@ -17,20 +22,25 @@ const status_data = [
|
|||
"params" : {},
|
||||
"img_path": "res://vines_petals/vine_active_purple.png"
|
||||
},]
|
||||
|
||||
# The chosen status and its data
|
||||
var status_name : String
|
||||
var status_params : Dictionary = {}
|
||||
|
||||
# To which depths vine segments and nodes are active.
|
||||
# When max depth is reached, everything is active from then on.
|
||||
var active_depth = -1
|
||||
var fully_active = false
|
||||
var max_depth = 50
|
||||
|
||||
# Array containings lists of sprites, using their depths as index
|
||||
var vine_data = []
|
||||
var max_depth = 150
|
||||
|
||||
# List of "leaf locations" of the vine tree
|
||||
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
|
||||
|
||||
# Places a sprite for a vine segment from pos1 to pos2 at a given depth,
|
||||
# which might be activated already, depending on the active depth.
|
||||
func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int):
|
||||
var sprite = Sprite2D.new()
|
||||
get_tree().get_root().get_node("main").add_child(sprite)
|
||||
|
|
@ -38,6 +48,7 @@ func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int):
|
|||
sprite.texture = ResourceLoader.load(img_path_active)
|
||||
else:
|
||||
sprite.texture = ResourceLoader.load(img_path_inactive)
|
||||
# If neccessary, extend vine_data to the current depth
|
||||
while depth + 1 > vine_data.size():
|
||||
vine_data.append([])
|
||||
vine_data[depth].append(sprite)
|
||||
|
|
@ -47,37 +58,47 @@ func draw_vine(pos1 : Vector2, pos2 : Vector2, depth : int):
|
|||
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)
|
||||
# Grows a sequence of vine segments from grid position 1 to grid position 2, starting at given depth.
|
||||
func grow_vine_sequence(start : VineNode, target: VineNode, grow_bud = false, quick_spawn = false):
|
||||
var depth = min(start.depth, max_depth)
|
||||
|
||||
var segment_length = (pos1 - pos2).length() / num_segments
|
||||
# Calculate the number and length of segments from the distance of source and target
|
||||
var dist = (start.position - target.position).length()
|
||||
var num_segments = floor(dist / 96)
|
||||
var segment_length = dist / num_segments
|
||||
|
||||
# Build a list of vine segment positions placed horizontally equidistant along the line from the source
|
||||
# to the target, with vertical offset having controlled 2nd derivative to prevent sharp edges.
|
||||
var positions = []
|
||||
positions.append(start.position)
|
||||
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)
|
||||
var center = t * target.position + (1 - t) * start.position
|
||||
var offset = offsets[i + 1] * (target.position - start.position).normalized().rotated(PI/2)
|
||||
positions.append(center + offset)
|
||||
positions.append(pos2)
|
||||
positions.append(target.position)
|
||||
|
||||
# Draw vine segments along the positions determined previously.
|
||||
# Do so slowly unless quick_spawn is specified.
|
||||
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)
|
||||
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:
|
||||
if location2.y > 0 and location2.y <= Grid.max_bud_height:
|
||||
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 == location1:
|
||||
if vine_end_data[i].location == start.location:
|
||||
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))
|
||||
target.depth = depth + num_segments
|
||||
vine_end_data.append(target)
|
||||
Grid.add_vine_to(self, target.location)
|
||||
vine_locations.append(Global.vec_mod(target.location, Grid.num_collumns, true))
|
||||
|
||||
func generate_random_offsets(segment_count, max_second_derivative):
|
||||
var differences = []
|
||||
|
|
@ -122,26 +143,34 @@ func update_active_depth():
|
|||
spawn_bud(data.location, data.offset, data.depth)
|
||||
update_active_depth()
|
||||
|
||||
func _enter_tree() -> 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
|
||||
init_random()
|
||||
|
||||
func random_vine_node_at(location):
|
||||
var offset = random_offset()
|
||||
return VineNode.new(self, location, offset)
|
||||
|
||||
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})
|
||||
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)):
|
||||
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):
|
||||
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_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)
|
||||
var target = random_vine_node_at(target_location)
|
||||
grow_vine_sequence(end, target, true, true)
|
||||
if i==0 and branches_count == 1:
|
||||
vine_end_data.append({"location": petal_location, "offset": petal_offset, "depth": 0})
|
||||
vine_end_data.append(petal)
|
||||
|
||||
func random_offset():
|
||||
return Vector2(randf_range(60, 240), randf_range(90, 270))
|
||||
|
|
|
|||
|
|
@ -1,8 +1,40 @@
|
|||
class_name VineNode extends Node2D
|
||||
|
||||
|
||||
@export var vine : Vine
|
||||
@export var location : Vector2
|
||||
@export var location : Vector2 :
|
||||
set(new_loc):
|
||||
location = Global.vec_mod(new_loc, Grid.num_collumns, true)
|
||||
@export var offset : Vector2
|
||||
@export var depth : int
|
||||
|
||||
func _ready() -> void:
|
||||
position = Grid.get_world_position(location, offset)
|
||||
func _get(property: StringName) -> Variant:
|
||||
if property == "position":
|
||||
update_position()
|
||||
return position
|
||||
if property == "global_position":
|
||||
update_position()
|
||||
return global_position
|
||||
return null
|
||||
|
||||
func _set(property: StringName, value: Variant) -> bool:
|
||||
if property == "global_position":
|
||||
location = Grid.get_location_from_world_pos(value)
|
||||
offset = Grid.get_offset_from_world_pos(value)
|
||||
update_position()
|
||||
return true
|
||||
if property == "position":
|
||||
update_position()
|
||||
return false
|
||||
return false
|
||||
|
||||
func update_position():
|
||||
global_position = Grid.get_world_position(location, offset)
|
||||
|
||||
func _enter_grid() -> void:
|
||||
update_position()
|
||||
|
||||
func _init(_vine = null, _location = Vector2.ZERO, _offset = Vector2.ZERO, _depth = 0):
|
||||
vine = _vine
|
||||
location = _location
|
||||
offset = _offset
|
||||
depth = _depth
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ extends Node2D
|
|||
var buildings : Array[Building] = []
|
||||
|
||||
var max_bud_height = 8
|
||||
var vines_per_node : Array = []
|
||||
var vines_per_node : Array
|
||||
|
||||
func _ready() -> void:
|
||||
reset()
|
||||
|
|
@ -75,7 +75,17 @@ func reset():
|
|||
for j in range(max_bud_height + 2):
|
||||
arr.append([])
|
||||
vines_per_node.append(arr)
|
||||
|
||||
|
||||
func get_vines_at(location) -> Array:
|
||||
location = Global.vec_mod(location, num_collumns, true)
|
||||
return vines_per_node[location.x][location.y]
|
||||
|
||||
func add_vine_to(vine, location) -> void:
|
||||
if location.y > max_bud_height + 1 or location.y < 0:
|
||||
return
|
||||
location = Global.vec_mod(location, num_collumns, true)
|
||||
vines_per_node[location.x][location.y].append(vine)
|
||||
|
||||
# for testing
|
||||
#func _ready() -> void:
|
||||
#
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue