feat: implemented photo inbox and notepad

This commit is contained in:
Sara Gerretsen 2025-10-30 21:33:22 +01:00
parent 850fe5865b
commit 2577d41e46
17 changed files with 285 additions and 74 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://p7uaxluyc0tk"
path="res://.godot/imported/Knife.jpg-a5a0b11f87ebf896f8f190d2055a6239.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/photo-images/Knife.jpg"
dest_files=["res://.godot/imported/Knife.jpg-a5a0b11f87ebf896f8f190d2055a6239.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,13 @@
[gd_resource type="ClueDB" load_steps=4 format=3 uid="uid://dlf8dxiter8b8"]
[ext_resource type="Texture2D" uid="uid://p7uaxluyc0tk" path="res://assets/photo-images/Knife.jpg" id="1_q5eka"]
[sub_resource type="ClueData" id="ClueData_kxjsf"]
id = 0
image = ExtResource("1_q5eka")
[sub_resource type="ClueData" id="ClueData_q5eka"]
id = 1
[resource]
clues = [SubResource("ClueData_kxjsf"), SubResource("ClueData_q5eka")]

View file

@ -0,0 +1,21 @@
[gd_scene load_steps=4 format=3 uid="uid://btcmnw6q6g0h0"]
[sub_resource type="QuadMesh" id="QuadMesh_87mh6"]
[sub_resource type="ImageTexture" id="ImageTexture_usqe2"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_usqe2"]
size = Vector2(166, 172)
[node name="PinnedPhoto" type="PinnedPhoto"]
input_pickable = true
[node name="MeshInstance2D" type="MeshInstance2D" parent="."]
position = Vector2(0, 73.49998)
scale = Vector2(162.00002, 168.99995)
mesh = SubResource("QuadMesh_87mh6")
texture = SubResource("ImageTexture_usqe2")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(0, 73)
shape = SubResource("RectangleShape2D_usqe2")

View file

@ -1,52 +1,20 @@
[gd_scene load_steps=8 format=3 uid="uid://dosb4sb7pvss4"]
[gd_scene load_steps=3 format=3 uid="uid://dosb4sb7pvss4"]
[sub_resource type="QuadMesh" id="QuadMesh_usqe2"]
[ext_resource type="PackedScene" uid="uid://o3ri154wpbrx" path="res://scenes/workspace.tscn" id="1_87mh6"]
[ext_resource type="PackedScene" uid="uid://owa17yo7q6wo" path="res://scenes/start_server_ui.tscn" id="1_btop4"]
[sub_resource type="Gradient" id="Gradient_usqe2"]
offsets = PackedFloat32Array(1)
colors = PackedColorArray(0.7490196, 0.7019608, 0.6431373, 1)
[node name="FlatscreenRoot" type="Node"]
[sub_resource type="GradientTexture1D" id="GradientTexture1D_87mh6"]
gradient = SubResource("Gradient_usqe2")
[sub_resource type="RectangleShape2D" id="RectangleShape2D_87mh6"]
size = Vector2(1288, 533)
[sub_resource type="QuadMesh" id="QuadMesh_87mh6"]
[sub_resource type="ImageTexture" id="ImageTexture_usqe2"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_usqe2"]
size = Vector2(166, 172)
[node name="FlatscreenRoot" type="Node2D"]
[node name="ServerNode" type="ServerNode" parent="."]
[node name="Camera2D" type="Camera2D" parent="."]
anchor_mode = 0
[node name="Pinboard" type="Pinboard" parent="."]
position = Vector2(312, 19)
[node name="FlatscreenRoot" parent="." instance=ExtResource("1_87mh6")]
[node name="MeshInstance2D" type="MeshInstance2D" parent="Pinboard"]
position = Vector2(794.49994, 417)
scale = Vector2(1535.0001, 818)
mesh = SubResource("QuadMesh_usqe2")
texture = SubResource("GradientTexture1D_87mh6")
[node name="CollisionShape2D" type="CollisionShape2D" parent="Pinboard"]
position = Vector2(798, 465.5)
shape = SubResource("RectangleShape2D_87mh6")
[node name="PinnedPhoto" type="PinnedPhoto" parent="."]
position = Vector2(479, 904)
input_pickable = true
[node name="MeshInstance2D" type="MeshInstance2D" parent="PinnedPhoto"]
position = Vector2(0, 73.49998)
scale = Vector2(162.00002, 168.99995)
mesh = SubResource("QuadMesh_87mh6")
texture = SubResource("ImageTexture_usqe2")
[node name="CollisionShape2D" type="CollisionShape2D" parent="PinnedPhoto"]
position = Vector2(0, 73)
shape = SubResource("RectangleShape2D_usqe2")
[node name="StartServerUI" parent="." instance=ExtResource("1_btop4")]
anchors_preset = 0
anchor_right = 0.0
anchor_bottom = 0.0
offset_right = 1920.0
offset_bottom = 1080.0

View file

@ -1,12 +1,11 @@
[gd_scene load_steps=2 format=3 uid="uid://owa17yo7q6wo"]
[sub_resource type="GDScript" id="GDScript_usqe2"]
resource_name = "StartServerUI"
script/source = "extends CenterContainer
[sub_resource type="GDScript" id="GDScript_oroue"]
script/source = "extends PanelContainer
@onready var label := $VBoxContainer/ConnectingText
@onready var open_server_btn := $VBoxContainer/OpenServerButton
@onready var close_server_btn := $VBoxContainer/CloseServerButton
@onready var label := %ConnectingText
@onready var open_server_btn := %OpenServerButton
@onready var close_server_btn := %CloseServerButton
func _ready():
ServerNode.get_singleton().connection_established.connect(self._on_server_node_connection_established)
@ -29,40 +28,47 @@ func _on_server_node_connection_established() -> void:
self.visible = false
"
[node name="StartServerUI" type="CenterContainer"]
[node name="StartServerUI" type="PanelContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = SubResource("GDScript_oroue")
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = SubResource("GDScript_usqe2")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
layout_mode = 2
[node name="OpenServerButton" type="Button" parent="VBoxContainer"]
[node name="OpenServerButton" type="Button" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Host Game Server"
[node name="CloseServerButton" type="Button" parent="VBoxContainer"]
[node name="CloseServerButton" type="Button" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "Cancel Connection"
[node name="ConnectingText" type="Label" parent="VBoxContainer"]
[node name="ConnectingText" type="Label" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "Waiting for client..."
horizontal_alignment = 1
[node name="PermissionsText" type="Label" parent="VBoxContainer"]
[node name="PermissionsText" type="Label" parent="CenterContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
text = "Requires permissions to open port 6667.
If you have a firewall on your system you
may need to open configure it"
horizontal_alignment = 1
[connection signal="pressed" from="VBoxContainer/OpenServerButton" to="." method="_on_open_button_pressed"]
[connection signal="pressed" from="VBoxContainer/CloseServerButton" to="." method="_on_close_button_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/OpenServerButton" to="." method="_on_open_button_pressed"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/CloseServerButton" to="." method="_on_close_button_pressed"]

View file

@ -0,0 +1,53 @@
[gd_scene load_steps=7 format=3 uid="uid://o3ri154wpbrx"]
[ext_resource type="PackedScene" uid="uid://btcmnw6q6g0h0" path="res://objects/pinned_photo.tscn" id="1_7cefc"]
[sub_resource type="QuadMesh" id="QuadMesh_usqe2"]
[sub_resource type="Gradient" id="Gradient_usqe2"]
offsets = PackedFloat32Array(1)
colors = PackedColorArray(0.7490196, 0.7019608, 0.6431373, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_87mh6"]
gradient = SubResource("Gradient_usqe2")
[sub_resource type="RectangleShape2D" id="RectangleShape2D_87mh6"]
size = Vector2(1074, 533)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_7cefc"]
size = Vector2(295, 346)
[node name="FlatscreenRoot" type="Node2D"]
[node name="Camera2D" type="Camera2D" parent="."]
anchor_mode = 0
[node name="Pinboard" type="Pinboard" parent="."]
position = Vector2(312, 19)
[node name="MeshInstance2D" type="MeshInstance2D" parent="Pinboard"]
position = Vector2(794.49994, 417)
scale = Vector2(1535.0001, 818)
mesh = SubResource("QuadMesh_usqe2")
texture = SubResource("GradientTexture1D_87mh6")
[node name="CollisionShape2D" type="CollisionShape2D" parent="Pinboard"]
position = Vector2(691, 465.5)
shape = SubResource("RectangleShape2D_87mh6")
[node name="CollisionShape2D2" type="CollisionShape2D" parent="Pinboard"]
position = Vector2(1392.5, 560)
shape = SubResource("RectangleShape2D_7cefc")
[node name="PinnedPhoto" parent="." instance=ExtResource("1_7cefc")]
position = Vector2(479, 904)
[node name="PhotoInbox" type="PhotoInbox" parent="."]
position = Vector2(1767, 890)
photo_scene = ExtResource("1_7cefc")
[node name="TextEdit" type="TextEdit" parent="."]
offset_left = 1604.0
offset_top = 181.0
offset_right = 1822.0
offset_bottom = 346.0

View file

@ -4,7 +4,7 @@
void ClueData::_bind_methods() {
BIND_HPROPERTY(Variant::INT, id, PROPERTY_HINT_ENUM, NetworkData::ClueID_hint());
BIND_HPROPERTY(Variant::OBJECT, image, PROPERTY_HINT_RESOURCE_TYPE, "Image");
BIND_HPROPERTY(Variant::OBJECT, image, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D");
}
void ClueData::set_revealed(bool value) {
@ -38,11 +38,10 @@ bool ClueData::get_revealed() const {
return this->revealed;
}
void ClueData::set_image(Ref<Image> image) {
void ClueData::set_image(Ref<Texture2D> image) {
this->image = image;
// TODO: Sync to server
}
Ref<Image> ClueData::get_image() const {
Ref<Texture2D> ClueData::get_image() const {
return this->image;
}

View file

@ -1,7 +1,7 @@
#pragma once
#include "core/io/image.h"
#include "core/io/resource.h"
#include "scene/resources/texture.h"
#include "you_done_it/ydi_networking.h"
class ClueData : public Resource {
@ -16,11 +16,11 @@ public:
NetworkData::ClueID get_id() const;
void reveal();
bool get_revealed() const;
void set_image(Ref<Image> image);
Ref<Image> get_image() const;
void set_image(Ref<Texture2D> image);
Ref<Texture2D> get_image() const;
private:
NetworkData::ClueID id{ NetworkData::CLUE_MAX };
bool revealed{ false };
Ref<Image> image{};
Ref<Texture2D> image{};
};

View file

@ -19,12 +19,6 @@ void ClueDB::ensure_data_valid() {
}
}
ClueDB::~ClueDB() {
if (singleton_instance == this) {
singleton_instance = nullptr;
}
}
Ref<ClueDB> &ClueDB::get_singleton() {
if (!singleton_instance.is_valid()) {
singleton_instance = Ref<ClueDB>(ResourceLoader::load("res://clue_db.tres"));
@ -32,6 +26,10 @@ Ref<ClueDB> &ClueDB::get_singleton() {
return singleton_instance;
}
bool ClueDB::has_singleton() {
return singleton_instance.is_valid();
}
void ClueDB::set_clues(Array data) {
for (Variant value : data) {
Ref<ClueData> clue{ Object::cast_to<ClueData>(value) };

View file

@ -12,8 +12,8 @@ class ClueDB : public Resource {
void ensure_data_valid();
public:
virtual ~ClueDB();
static Ref<ClueDB> &get_singleton();
static bool has_singleton();
void set_clues(Array data);
Array get_clues();
Ref<ClueData> get_clue(NetworkData::ClueID id);

View file

@ -1,4 +1,75 @@
#include "photo_inbox.h"
#include "core/input/input_event.h"
#include "core/object/class_db.h"
#include "core/os/keyboard.h"
#include "you_done_it/clue_db.h"
#include "you_done_it/macros.h"
#include "you_done_it/pinned_photo.h"
#include "you_done_it/server_node.h"
void PhotoInbox::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, photo_scene, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
}
void PhotoInbox::enter_tree() {
if (ServerNode * server{ ServerNode::get_singleton() }) {
server->connect(ServerNode::sig_clue_revealed, callable_mp(this, &self_type::on_clue_revealed));
} else {
// enable process unhandled input if no server is found, as this implies we should be running in test mode.
set_process_unhandled_input(true);
print_line("No ServerNode singleton found, Running PhotoInbox in testing mode");
}
}
void PhotoInbox::unhandled_input(Ref<InputEvent> const &event) {
Ref<InputEventKey> key{ event };
if (key.is_valid() && key->is_pressed()) {
switch (key->get_key_label()) {
default:
break;
case Key::KEY_1:
on_clue_revealed(NetworkData::CLUE_FIRST);
get_viewport()->set_input_as_handled();
break;
case Key::KEY_2:
on_clue_revealed(NetworkData::CLUE_SECOND);
get_viewport()->set_input_as_handled();
break;
}
}
}
void PhotoInbox::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_ENTER_TREE:
enter_tree();
return;
}
}
void PhotoInbox::on_clue_revealed(NetworkData::ClueID clue) {
Node *instantiated{ photo_scene->instantiate() };
if (!instantiated) {
return;
}
if (PinnedPhoto * photo{ cast_to<PinnedPhoto>(instantiated) }) {
photo->set_global_position(get_global_position());
photo->set_visible(false); // make invisible until setup is complete to avoid delay
get_parent()->add_child(instantiated);
photo->set_clue(clue);
photo->set_visible(true);
}
}
void PhotoInbox::set_photo_scene(Ref<PackedScene> scene) {
this->photo_scene = ClassDB::is_parent_class(scene->get_state()->get_node_type(0), "Node2D") ? scene : Ref<PackedScene>();
}
Ref<PackedScene> PhotoInbox::get_photo_scene() const {
return this->photo_scene;
}

View file

@ -1,8 +1,23 @@
#pragma once
#include "scene/2d/node_2d.h"
#include "scene/resources/packed_scene.h"
#include "you_done_it/ydi_networking.h"
class PhotoInbox : public Node2D {
GDCLASS(PhotoInbox, Node2D);
static void _bind_methods();
void enter_tree();
void on_clue_revealed(NetworkData::ClueID id);
private:
virtual void unhandled_input(Ref<InputEvent> const &event) override;
void _notification(int what);
public:
void set_photo_scene(Ref<PackedScene> scene);
Ref<PackedScene> get_photo_scene() const;
private:
Ref<PackedScene> photo_scene{};
};

View file

@ -1,6 +1,7 @@
#include "pinboard.h"
#include "core/config/engine.h"
#include "pinned_photo.h"
#include "scene/2d/mesh_instance_2d.h"
void Pinboard::_bind_methods() {
}

View file

@ -2,6 +2,8 @@
#include "core/config/engine.h"
#include "core/input/input_event.h"
#include "macros.h"
#include "scene/2d/mesh_instance_2d.h"
#include "you_done_it/clue_db.h"
void PinnedPhoto::_bind_methods() {
BIND_PROPERTY(Variant::BOOL, can_drop);
@ -10,6 +12,13 @@ void PinnedPhoto::_bind_methods() {
void PinnedPhoto::enter_tree() {
connect("input_event", callable_mp(this, &self_type::on_input_event));
connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered_tree));
}
void PinnedPhoto::on_child_entered_tree(Node *node) {
if (MeshInstance2D * meshinst{ cast_to<MeshInstance2D>(node) }) {
this->photo_mesh = meshinst;
}
}
void PinnedPhoto::process(double delta) {
@ -27,6 +36,9 @@ void PinnedPhoto::on_input_event(Viewport *viewport, Ref<InputEvent> event, int
}
void PinnedPhoto::unhandled_input(Ref<InputEvent> const &event) {
if (!this->is_held) {
return;
}
Ref<InputEventMouseButton> button{ event };
if (button.is_valid() && this->can_drop && button->is_released()) {
this->is_held = false;
@ -63,6 +75,12 @@ bool PinnedPhoto::get_can_drop() const {
void PinnedPhoto::set_clue(NetworkData::ClueID id) {
this->clue = id;
if (photo_mesh) {
Ref<Texture2D> texture{ ClueDB::get_singleton()->get_clue(id)->get_image() };
if (texture.is_valid()) {
photo_mesh->set_texture(texture);
}
}
}
NetworkData::ClueID PinnedPhoto::get_clue() const {

View file

@ -1,6 +1,7 @@
#pragma once
#include "core/input/input_event.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/physics/animatable_body_2d.h"
#include "scene/main/viewport.h"
#include "ydi_networking.h"
@ -9,6 +10,7 @@ class PinnedPhoto : public AnimatableBody2D {
GDCLASS(PinnedPhoto, AnimatableBody2D);
static void _bind_methods();
void enter_tree();
void on_child_entered_tree(Node *node);
void process(double delta);
void on_input_event(Viewport *viewport, Ref<InputEvent> event, int shape);
@ -23,6 +25,7 @@ public:
NetworkData::ClueID get_clue() const;
private:
MeshInstance2D *photo_mesh{ nullptr };
NetworkData::ClueID clue{ NetworkData::CLUE_MAX };
bool can_drop{ false };
bool is_held{ false };

View file

@ -5,6 +5,7 @@
#include "you_done_it/clue_data.h"
#include "you_done_it/clue_finder.h"
#include "you_done_it/clue_marker.h"
#include "you_done_it/photo_inbox.h"
#include "you_done_it/pinboard.h"
#include "you_done_it/pinned_photo.h"
#include "you_done_it/server_node.h"
@ -25,10 +26,14 @@ void initialize_you_done_it_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<ClueDB>();
ClassDB::register_class<Pinboard>();
ClassDB::register_class<PinnedPhoto>();
ClassDB::register_class<PhotoInbox>();
}
void uninitialize_you_done_it_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
if (ClueDB::has_singleton()) {
ClueDB::get_singleton().unref();
}
}