Skip to content
54 changes: 54 additions & 0 deletions scenes/game_elements/props/tree/components/tree_parter.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[gd_scene format=3 uid="uid://conut7biwewd5"]

[ext_resource type="AudioStream" uid="uid://1gnb8sf687eo" path="res://assets/first_party/sounds/mushroom/Hu.ogg" id="2_40l5v"]
[ext_resource type="Script" uid="uid://c78objoydjdo0" path="res://scenes/game_logic/tree_parter.gd" id="4_2ul7r"]

[sub_resource type="RectangleShape2D" id="RectangleShape2D_hggpd"]
resource_local_to_scene = true
size = Vector2(200, 400)

[sub_resource type="RectangleShape2D" id="RectangleShape2D_urkup"]
resource_local_to_scene = true
size = Vector2(4, 400)

[sub_resource type="RectangleShape2D" id="RectangleShape2D_pp1gq"]
size = Vector2(200, 4)

[node name="TreeParter" type="Node2D" unique_id=1011308445]
script = ExtResource("4_2ul7r")

[node name="WalkableTrees" type="Area2D" parent="." unique_id=1698908802]
collision_mask = 17

[node name="CollisionShape2D" type="CollisionShape2D" parent="WalkableTrees" unique_id=763540384]
shape = SubResource("RectangleShape2D_hggpd")

[node name="Borders" type="StaticBody2D" parent="." unique_id=1630802636]
modulate = Color(1, 0.30980393, 1, 1)
position = Vector2(-110, 52)
collision_layer = 16
collision_mask = 0

[node name="LeftBorder" type="CollisionShape2D" parent="Borders" unique_id=1196037431]
position = Vector2(7, -52)
shape = SubResource("RectangleShape2D_urkup")
one_way_collision = true
one_way_collision_margin = 10.0
one_way_collision_direction = Vector2(-1, 0)

[node name="RightBorder" type="CollisionShape2D" parent="Borders" unique_id=993898564]
position = Vector2(213, -52)
shape = SubResource("RectangleShape2D_urkup")
one_way_collision = true
one_way_collision_margin = 10.0
one_way_collision_direction = Vector2(1, 0)

[node name="TopBorder" type="CollisionShape2D" parent="Borders" unique_id=355443638]
position = Vector2(110, -255)
shape = SubResource("RectangleShape2D_pp1gq")

[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="." unique_id=1779282063]
stream = ExtResource("2_40l5v")

[connection signal="body_entered" from="WalkableTrees" to="." method="_on_body_entered"]
[connection signal="body_exited" from="WalkableTrees" to="." method="_on_body_exited"]
1,135 changes: 1,135 additions & 0 deletions scenes/game_elements/props/tree/components/tree_parter_test.tscn

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are y-sort issues in this test scene!

Image

Large diffs are not rendered by default.

67 changes: 67 additions & 0 deletions scenes/game_logic/tree_parter.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
@tool
extends Node2D
# TODO: Change to item you want to walk past (in inspector)
# TODO: we also would need tree to have a class_name or some other way to generalize this
const TREE_SCENE = preload("res://scenes/game_elements/props/tree/components/tree.gd")
Comment on lines +5 to +7

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why constrain this to a single class? What this script does for opening the access is:

  • Set the tree in PROCESS_MODE_DISABLED
  • Change the tree modulate to make it semi-transparent.

And since modulate is a property of CanvasItem, this could work with any CanvasItem.

Also the "WalkableTrees" Area2D is used for 2 things:

  • For detecting the player and opening the access.
  • For setup of the items to disable and modulate.

I think that this coupling is a bit constraining, and is a bit tricky to setup the items at run-time, using the body_entered signal. If you leave the Area2D just for detecting the player, you could do the setup of items just by exporting an Array of CanvasItems. Something like:

## Items you want to walk past
@export var items: Array[CanvasItem]

Although it will be hard to setup, and has to be done each time AreaFiller "Refill" is pressed. For that a @export_tool_button could be added. Or alternatively, export the parent node and traverse all immediate children, matching CanvasItems.

## Parent of items you want to walk past. Each CanvasItem immediate children 
@export var parent_of_items: Node2D

const SECRET_PATH_MODULATION = Color(.6, .6, .6, 0.3)

@export_range(10, 1000, 10) var width: float = 200.0:
set = _set_width_values

@export_range(10, 1000, 10) var height: float = 400.0:
set = _set_height_values
Comment on lines +10 to +14

@manuq manuq Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is limiting, because the Area2D and its collision shape are inside the tree_parter scene. So:

  • It constrains to a rectangle shape.
  • And the rectangle shape can't be modified in the 2D viewport, only by these width, height sliders in the Inspector.

Instead, you can remove the Area2D from tree_parter and add an @export for it. You could check how other "behavior" scripts do it.

Oh, but I see now that this also has to adjust the borders according to the width and height! Looks a bit overengineered (I'll explain in a few).


var trees: Array[Node2D] # objects that should be modulated and not collide
var colliders: Array[Node2D] # objects that should not collide

@onready var walkable_trees: Area2D = $WalkableTrees
@onready var l_border: CollisionShape2D = $Borders/LeftBorder
@onready var r_border: CollisionShape2D = $Borders/RightBorder
@onready var t_border: CollisionShape2D = $Borders/TopBorder
# TODO: Give audio stream a leaf rustle sound
@onready var audio_stream_player_2d: AudioStreamPlayer2D = $AudioStreamPlayer2D


func _set_width_values(val: float) -> void:
if walkable_trees:
for shape in walkable_trees.get_children():
shape.shape.size.x = val
l_border.position.x -= (val - width) / 2
r_border.position.x += (val - width) / 2
t_border.shape.size.x += (val - width)
width = val


func _set_height_values(val: float) -> void:
if walkable_trees:
for shape in walkable_trees.get_children():
shape.shape.size.y = val
l_border.shape.size.y += (val - height) / 2
r_border.shape.size.y += (val - height) / 2
t_border.position.y -= (val - height) / 2
height = val


func _on_body_entered(body: Node2D) -> void:
if body is Player:
for tree in trees:
tree.process_mode = Node.PROCESS_MODE_DISABLED
tree.get_parent().modulate = SECRET_PATH_MODULATION
audio_stream_player_2d.play()
for collider in colliders:
collider.process_mode = Node.PROCESS_MODE_DISABLED
Comment on lines +49 to +54

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that setting process_mode = Node.PROCESS_MODE_DISABLED on the tree will also set it on all its child nodes like the collider (if they are setup with Node.PROCESS_MODE_INHERIT). So I wonder if you need the extra colliders array at all.

elif body.get_parent().get_script() == TREE_SCENE:
trees.append(body)
else:
colliders.append(body)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relies on doing the setup of trees and colliders at run-time when the scene is started and body_entered is called with them.



func _on_body_exited(body: Node2D) -> void:
if body is Player:
for tree in trees:
tree.process_mode = Node.PROCESS_MODE_INHERIT
tree.get_parent().modulate = Color.WHITE
for collider in colliders:
collider.process_mode = Node.PROCESS_MODE_INHERIT
1 change: 1 addition & 0 deletions scenes/game_logic/tree_parter.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://c78objoydjdo0
12 changes: 12 additions & 0 deletions scenes/quests/lore_quests/dev_island/dev_island.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: The Threadbare Authors
# SPDX-License-Identifier: MPL-2.0
extends Node2D


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
var player := get_tree().get_first_node_in_group("player")
# TODO: What abilities are available in "hub"?
if player:
GameState.player.set_ability(Enums.PlayerAbilities.ABILITY_A, true)
GameState.player.set_ability(Enums.PlayerAbilities.ABILITY_B, true)
1 change: 1 addition & 0 deletions scenes/quests/lore_quests/dev_island/dev_island.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://buvlru43o3tl5
60 changes: 60 additions & 0 deletions scenes/quests/lore_quests/dev_island/dev_island.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
[gd_scene format=4 uid="uid://degtbs5nqp0l7"]

[ext_resource type="Script" uid="uid://buvlru43o3tl5" path="res://scenes/quests/lore_quests/dev_island/dev_island.gd" id="1_3ic4x"]
[ext_resource type="TileSet" uid="uid://b8qnr0owsbhhn" path="res://tiles/exterior_floors.tres" id="1_t4lug"]
[ext_resource type="PackedScene" uid="uid://iu2q66clupc6" path="res://scenes/game_elements/characters/player/player.tscn" id="2_cf7qj"]
[ext_resource type="SpriteFrames" uid="uid://dtoylirwywk0j" path="res://scenes/game_elements/characters/components/sprite_frames/storyweaver_blue.tres" id="3_1ahrq"]
[ext_resource type="PackedScene" uid="uid://0ull24fvmhwk" path="res://scenes/game_elements/props/teleporter/teleporter.tscn" id="4_1ahrq"]
[ext_resource type="PackedScene" uid="uid://covsdqqsd6rsy" path="res://scenes/game_elements/props/sign/sign.tscn" id="5_8bnge"]

[sub_resource type="RectangleShape2D" id="RectangleShape2D_cdbf2"]
size = Vector2(101, 114)

[sub_resource type="RectangleShape2D" id="RectangleShape2D_5l5sl"]
size = Vector2(110, 99)

[node name="DevIsland" type="Node2D" unique_id=90110061]
script = ExtResource("1_3ic4x")

[node name="TileMap" type="Node2D" parent="." unique_id=965204047]

[node name="Ground" type="TileMapLayer" parent="TileMap" unique_id=1010684124]
tile_map_data = PackedByteArray("AAAAAAAAAQABAAEAAAAAAAEAAQABAAEAAAAAAAIAAQABAAEAAAAAAAMAAQABAAEAAAAAAAQAAQABAAEAAAAAAAUAAQAGAAMAAAAAAAYAAQABAAEAAAAAAAcAAQABAAEAAAAAAAgAAQABAAEAAAAAAAkAAQABAAEAAAABAAAAAQABAAEAAAABAAEAAQABAAEAAAABAAIAAQABAAEAAAABAAMAAQABAAEAAAABAAQAAQABAAEAAAABAAUAAQAGAAMAAAABAAYAAQABAAEAAAABAAcAAQABAAEAAAABAAgAAQABAAEAAAABAAkAAQABAAEAAAACAAAAAQABAAEAAAACAAEAAQABAAEAAAACAAIAAQABAAEAAAACAAMAAQABAAEAAAACAAQAAQABAAEAAAACAAUAAQAGAAMAAAACAAYAAQABAAEAAAACAAcAAQABAAEAAAACAAgAAQABAAEAAAACAAkAAQABAAEAAAADAAAAAQABAAEAAAADAAEAAQABAAEAAAADAAIAAQABAAEAAAADAAMAAQABAAEAAAADAAQAAQABAAEAAAADAAUAAQAGAAMAAAADAAYAAQABAAEAAAADAAcAAQABAAEAAAADAAgAAQABAAEAAAADAAkAAQABAAEAAAAEAAAAAQABAAEAAAAEAAEAAQABAAEAAAAEAAIAAQABAAEAAAAEAAMAAQABAAEAAAAEAAQAAQABAAEAAAAEAAUAAQAGAAMAAAAEAAYAAQABAAEAAAAEAAcAAQABAAEAAAAEAAgAAQABAAEAAAAEAAkAAQABAAEAAAAFAAAAAQABAAEAAAAFAAEAAQABAAEAAAAFAAIAAQABAAEAAAAFAAMAAQABAAEAAAAFAAQAAQABAAEAAAAFAAUAAQAGAAMAAAAFAAYAAQABAAEAAAAFAAcAAQABAAEAAAAFAAgAAQABAAEAAAAFAAkAAQABAAEAAAAGAAAAAQABAAEAAAAGAAEAAQABAAEAAAAGAAIAAQABAAEAAAAGAAMAAQABAAEAAAAGAAQAAQABAAEAAAAGAAUAAQAGAAMAAAAGAAYAAQABAAEAAAAGAAcAAQABAAEAAAAGAAgAAQABAAEAAAAGAAkAAQABAAEAAAAHAAAAAQABAAEAAAAHAAEAAQABAAEAAAAHAAIAAQABAAEAAAAHAAMAAQABAAEAAAAHAAQAAQABAAEAAAAHAAUAAQAGAAMAAAAHAAYAAQABAAEAAAAHAAcAAQABAAEAAAAHAAgAAQABAAEAAAAHAAkAAQABAAEAAAAIAAAAAQABAAEAAAAIAAEAAQABAAEAAAAIAAIAAQABAAEAAAAIAAMAAQABAAEAAAAIAAQAAQABAAEAAAAIAAUAAQAGAAMAAAAIAAYAAQABAAEAAAAIAAcAAQABAAEAAAAIAAgAAQABAAEAAAAIAAkAAQABAAEAAAAJAAAAAQABAAEAAAAJAAEAAQABAAEAAAAJAAIAAQABAAEAAAAJAAMAAQABAAEAAAAJAAQAAQABAAEAAAAJAAUAAQAGAAMAAAAJAAYAAQABAAEAAAAJAAcAAQABAAEAAAAJAAgAAQABAAEAAAAJAAkAAQABAAEAAAAKAAAAAQABAAEAAAAKAAEAAQABAAEAAAAKAAIAAQABAAEAAAAKAAMAAQABAAEAAAAKAAQAAQABAAEAAAAKAAUAAQAGAAMAAAAKAAYAAQABAAEAAAAKAAcAAQABAAEAAAAKAAgAAQABAAEAAAAKAAkAAQABAAEAAAALAAAAAQAIAAEAAAALAAEAAQAIAAEAAAALAAIAAQAIAAEAAAALAAMAAQAIAAEAAAALAAQAAQAIAAEAAAALAAUAAQAGAAEAAAALAAYAAQAIAAEAAAALAAcAAQAIAAEAAAALAAgAAQAIAAEAAAALAAkAAQAIAAEAAAAMAAAAAQABAAEAAAAMAAEAAQABAAEAAAAMAAIAAQABAAEAAAAMAAMAAQABAAEAAAAMAAQAAQABAAEAAAAMAAUAAQAGAAMAAAAMAAYAAQABAAEAAAAMAAcAAQABAAEAAAAMAAgAAQABAAEAAAAMAAkAAQABAAEAAAANAAAAAQABAAEAAAANAAEAAQABAAEAAAANAAIAAQABAAEAAAANAAMAAQABAAEAAAANAAQAAQABAAEAAAANAAUAAQAGAAMAAAANAAYAAQABAAEAAAANAAcAAQABAAEAAAANAAgAAQABAAEAAAANAAkAAQABAAEAAAAOAAAAAQABAAEAAAAOAAEAAQABAAEAAAAOAAIAAQABAAEAAAAOAAMAAQABAAEAAAAOAAQAAQABAAEAAAAOAAUAAQAGAAMAAAAOAAYAAQABAAEAAAAOAAcAAQABAAEAAAAOAAgAAQABAAEAAAAOAAkAAQABAAEAAAAPAAAAAQABAAEAAAAPAAEAAQABAAEAAAAPAAIAAQABAAEAAAAPAAMAAQABAAEAAAAPAAQAAQABAAEAAAAPAAUAAQAGAAMAAAAPAAYAAQABAAEAAAAPAAcAAQABAAEAAAAPAAgAAQABAAEAAAAPAAkAAQABAAEAAAAQAAAAAQABAAEAAAAQAAEAAQABAAEAAAAQAAIAAQABAAEAAAAQAAMAAQABAAEAAAAQAAQAAQABAAEAAAAQAAUAAQAGAAMAAAAQAAYAAQABAAEAAAAQAAcAAQABAAEAAAAQAAgAAQABAAEAAAAQAAkAAQABAAEAAAARAAAAAQABAAEAAAARAAEAAQABAAEAAAARAAIAAQABAAEAAAARAAMAAQABAAEAAAARAAQAAQABAAEAAAARAAUAAQAGAAMAAAARAAYAAQABAAEAAAARAAcAAQABAAEAAAARAAgAAQABAAEAAAARAAkAAQABAAEAAAASAAAAAQABAAEAAAASAAEAAQABAAEAAAASAAIAAQABAAEAAAASAAMAAQABAAEAAAASAAQAAQABAAEAAAASAAUAAQAGAAMAAAASAAYAAQABAAEAAAASAAcAAQABAAEAAAASAAgAAQABAAEAAAASAAkAAQABAAEAAAATAAAAAQABAAEAAAATAAEAAQABAAEAAAATAAIAAQABAAEAAAATAAMAAQABAAEAAAATAAQAAQABAAEAAAATAAUAAQAGAAMAAAATAAYAAQABAAEAAAATAAcAAQABAAEAAAATAAgAAQABAAEAAAATAAkAAQABAAEAAAAUAAAAAQABAAEAAAAUAAEAAQABAAEAAAAUAAIAAQABAAEAAAAUAAMAAQABAAEAAAAUAAQAAQABAAEAAAAUAAUAAQAGAAMAAAAUAAYAAQABAAEAAAAUAAcAAQABAAEAAAAUAAgAAQABAAEAAAAUAAkAAQABAAEAAAAVAAAAAQABAAEAAAAVAAEAAQABAAEAAAAVAAIAAQABAAEAAAAVAAMAAQABAAEAAAAVAAQAAQABAAEAAAAVAAUAAQAGAAMAAAAVAAYAAQABAAEAAAAVAAcAAQABAAEAAAAVAAgAAQABAAEAAAAVAAkAAQABAAEAAAAWAAAAAQABAAEAAAAWAAEAAQABAAEAAAAWAAIAAQABAAEAAAAWAAMAAQABAAEAAAAWAAQAAQABAAEAAAAWAAUAAQAGAAMAAAAWAAYAAQABAAEAAAAWAAcAAQABAAEAAAAWAAgAAQABAAEAAAAWAAkAAQABAAEAAAD//wAAAQAAAAEAAAD//wEAAQAAAAEAAAD//wIAAQAAAAEAAAD//wMAAQAAAAEAAAD//wQAAQAAAAEAAAD//wUAAQAGAAMAAAD//wYAAQAAAAEAAAD//wcAAQAAAAEAAAD//wgAAQAAAAEAAAD//wkAAQAAAAEAAAAAAAoAAQABAAIAAAABAAoAAQABAAIAAAACAAoAAQABAAIAAAADAAoAAQABAAIAAAAEAAoAAQABAAIAAAAFAAoAAQABAAIAAAAGAAoAAQABAAIAAAAHAAoAAQABAAIAAAAIAAoAAQABAAIAAAAJAAoAAQABAAIAAAAKAAoAAQABAAIAAAALAAoAAQAIAAEAAAAMAAoAAQABAAIAAAANAAoAAQABAAIAAAAOAAoAAQABAAIAAAAPAAoAAQABAAIAAAAQAAoAAQABAAIAAAARAAoAAQABAAIAAAASAAoAAQABAAIAAAATAAoAAQABAAIAAAAUAAoAAQABAAIAAAAVAAoAAQABAAIAAAAWAAoAAQABAAIAAAAXAAAAAQACAAEAAAAXAAEAAQACAAEAAAAXAAIAAQACAAEAAAAXAAMAAQACAAEAAAAXAAQAAQACAAEAAAAXAAUAAQAGAAMAAAAXAAYAAQACAAEAAAAXAAcAAQACAAEAAAAXAAgAAQACAAEAAAAXAAkAAQACAAEAAAAAAP//AQABAAAAAAABAP//AQABAAAAAAACAP//AQABAAAAAAADAP//AQABAAAAAAAEAP//AQABAAAAAAAFAP//AQABAAAAAAAGAP//AQABAAAAAAAHAP//AQABAAAAAAAIAP//AQABAAAAAAAJAP//AQABAAAAAAAKAP//AQABAAAAAAALAP//AQAIAAEAAAAMAP//AQABAAAAAAANAP//AQABAAAAAAAOAP//AQABAAAAAAAPAP//AQABAAAAAAAQAP//AQABAAAAAAARAP//AQABAAAAAAASAP//AQABAAAAAAATAP//AQABAAAAAAAUAP//AQABAAAAAAAVAP//AQABAAAAAAAWAP//AQABAAAAAAAXAP//AQACAAAAAAAXAAoAAQACAAIAAAD//woAAQAAAAIAAAD/////AQAAAAAAAAA=")
tile_set = ExtResource("1_t4lug")

[node name="Player" parent="." unique_id=296354958 instance=ExtResource("2_cf7qj")]
position = Vector2(774, 660)
player_name = "StoryWeaver"
sprite_frames = ExtResource("3_1ahrq")

[node name="Camera2D2" type="Camera2D" parent="Player" unique_id=1308126884]
limit_left = 0
limit_top = -320
limit_right = 2772
limit_bottom = 680
editor_draw_limits = true

[node name="Teleporter" parent="." unique_id=1779636661 instance=ExtResource("4_1ahrq")]
position = Vector2(1468, 347)
next_scene = "uid://blnnwmrypq0a6"

[node name="CollisionShape2D" type="CollisionShape2D" parent="Teleporter" unique_id=1623949637]
position = Vector2(28, 2)
shape = SubResource("RectangleShape2D_cdbf2")

[node name="Sign" parent="." unique_id=1579530966 instance=ExtResource("5_8bnge")]
position = Vector2(1443, 439)
direction = 1
text = "Learn how repelling works!"

[node name="Sign2" parent="." unique_id=606620495 instance=ExtResource("5_8bnge")]
position = Vector2(798, -12)
text = "Learn about custom hookable objects"

[node name="Teleporter2" parent="." unique_id=460831825 instance=ExtResource("4_1ahrq")]
position = Vector2(716, -48)
next_scene = "uid://s7y5x5caaah3"

[node name="CollisionShape2D" type="CollisionShape2D" parent="Teleporter2" unique_id=1369709219]
position = Vector2(14, 16)
shape = SubResource("RectangleShape2D_5l5sl")
12 changes: 12 additions & 0 deletions scenes/quests/lore_quests/dev_island/quest.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="LoreQuest" format=3 uid="uid://c4wb1jwjb8sg0"]

[ext_resource type="Resource" uid="uid://66840dnuhupo" path="res://scenes/quests/lore_quests/quest_000/quest_000_retelling.dialogue" id="1_kgvkk"]
[ext_resource type="Script" uid="uid://b23ralr2qbarg" path="res://scenes/menus/storybook/components/lore_quest.gd" id="2_mcpyp"]

[resource]
script = ExtResource("2_mcpyp")
title = "Dev Island"
description = "WIP Dev Island"
first_scene = "uid://degtbs5nqp0l7"
retelling = ExtResource("1_kgvkk")
metadata/_custom_type_script = "uid://dts1hwdy3phin"