From 86e059a2b8ededc9b9d51f7a279937dd7e929e7e Mon Sep 17 00:00:00 2001 From: Paolo Pustorino Date: Thu, 28 Dec 2023 16:15:04 +0100 Subject: [PATCH] refs #37: Rooms Aseprite importer preparatory code and PopochiuObjects creation refactoring (#64) * refs #37: Squashed Room Importer and Objects creation refactoring. refs #37: Preparation for refactoring of importer code. refs #37: The plugin is now ready for the implementation of the Room importing logic. refs #37: WIP refactoring the prop creation logic. It works but needs heavy polishing. refs #37: Open #67 about the heavy polishing, in the meantime this reduce the passing-over of UI elements. refs #37: Changed commit language. refs #37: Refactored the region creation following the new template. Added a base class to limit code-duplication. refs #37: Refactored the walkable areas too. refs #37: Refactored the hotspots creation too. refs #37: Project file updated to Godot 4.1 refs #37: Rooms creation have been refactored. refs #37: Characters creation have been refactored. refs #37: Inventory items creation have been refactored. refs #37: Dialog creation have been refactored. refs #37: some code dedup on type helpers. refs #37: code dedup in helpers should be over. Also addressed annoying Godot 4.1 bug. refs #37: all creation helpers have been renamed to factories. refs #37: factories init methods changed to real constructors. refs #37: renamed and added internal factories variables for better readability. refs #37: Fixed inconsistency in inventory items file naming. refs #37: Renamed local variables in factory classes. refs #37: Switch to a success state return strategy to bubble feedback up to the popup. refs #37: Fixed wrong ownership for room objects children bug. refs #37: Cleaned up useless and hard-to-maintain references to the obj types in comments. Addresses PR comments by @carenalga. refs #37: Renamed factories private members to reduce unnecessary verbosity. refs #37: Solved error message about invalid ownership when creating room objects. refs #37: WIP for rooms importer. This code is broken! refs #37: WIP for rooms importer. This code is broken! refs #37: WIP for rooms importer. This code is broken! refs #37: A lot of code rewriting to make the base feature work. It works :) refs #37: More work to get rid of strange execution errors. refs #37: moving stuff in a desperate attempt to make this working in a predictable way. refs #37: changed the importing flow strategy to circumvent a nasty error on linux with filesystem signals availability. refs #37: off-by-one error fixed in animation frames range. refs #37: fixed an error I probably inherited from another branch. TEST1: messing with importer. refs #37: worked around the console error when packing a scene with not-owned children (please see Godot GH-81982 for details). refs #37: visibility toggle in the importer interface is now working as intended. refs #37: all props now have an attached script, even the non-clickable ones; the importer is now able to update visibility and clickability status of already imported props. refs #37: InteractionPolygons for props and hotspots have been moved in the scene and an edit button has been exposed in the toolbar to edit them. Fix missing images when importing room from Aseprite (#110) Store polygon for interaction in @export var This will allow to keep the data of the polygon in the .tscn file of the room so the InteractionPolygon.polygon data of each prop is overwritten by the room both in runtime and while editing the room. NOTE: The polygon of the InteractionPolygon in each prop is not saved in the prop's scene file yet. Add comments and broke some long lines refs #37: InteractionPolygons icon is now more readable. Fixes for post-import error message (#126) * Fix Output error after importing room * Fix error message after closing room import popup The problem was caused because the popup was being added to the Room tree. Now it is added to Popochiu's main dock. * Temporary fix for bad row naming after import * Imported prop image is placed in the prop's folder Fix Aseprite importer section not showing in Inspector for room refs #37: Added a feature flag to Editor Settings, to disable Aseprite Importer for those who does not use Aseprite. refs #37: Fixed a warning related to EditorInterface being a singleton in 4.2. * refs #37: Removed leftovers after squashing and rebasing over 2.0 * Fix post-rebase issues about main_dock --------- Co-authored-by: carenalga --- .gitignore | 5 + .../importers/aseprite/animation_creator.gd | 6 + .../create_character/create_character.gd | 2 - .../popups/create_hotspot/create_hotspot.gd | 1 + .../create_inventory_item.gd | 1 - .../history/components/dialog_line.tscn | 11 ++ .../history/components/interaction_line.tscn | 11 ++ popochiu/rooms/house/room_house.tscn | 131 ++++++++++++++++++ .../sources/aseprite/room_exterior.aseprite | Bin 0 -> 9508 bytes 9 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 addons/popochiu/engine/objects/graphic_interface/history/components/dialog_line.tscn create mode 100644 addons/popochiu/engine/objects/graphic_interface/history/components/interaction_line.tscn create mode 100644 popochiu/rooms/house/room_house.tscn create mode 100644 popochiu/sources/aseprite/room_exterior.aseprite diff --git a/.gitignore b/.gitignore index 0c92be4c1..f0a358367 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,12 @@ # Addons other than Popochiu # (we use some for development) +<<<<<<< HEAD # addons/* # !addons/popochiu/ +======= +addons/* +!addons/popochiu/ +>>>>>>> 87c52d8 (refs #37: Rooms Aseprite importer preparatory code and PopochiuObjects creation refactoring (#64)) # Godot-specific ignores .import/ diff --git a/addons/popochiu/editor/importers/aseprite/animation_creator.gd b/addons/popochiu/editor/importers/aseprite/animation_creator.gd index ed223abd9..2e66bea75 100644 --- a/addons/popochiu/editor/importers/aseprite/animation_creator.gd +++ b/addons/popochiu/editor/importers/aseprite/animation_creator.gd @@ -30,6 +30,12 @@ func init(config, aseprite: RefCounted, editor_file_system: EditorFileSystem = n _file_system = editor_file_system _aseprite = aseprite +# Public interfaces, dedicated to specific popochiu objects +func create_character_animations(character: Node, player: AnimationPlayer, options: Dictionary): + # Chores + _target_node = character + _player = player + _options = options ## Public interfaces, dedicated to specific popochiu objects func create_character_animations(character: Node, player: AnimationPlayer, options: Dictionary): diff --git a/addons/popochiu/editor/popups/create_character/create_character.gd b/addons/popochiu/editor/popups/create_character/create_character.gd index 9645537ad..f6a64115f 100644 --- a/addons/popochiu/editor/popups/create_character/create_character.gd +++ b/addons/popochiu/editor/popups/create_character/create_character.gd @@ -16,7 +16,6 @@ const PopochiuDock := preload('res://addons/popochiu/editor/main_dock/popochiu_d var _new_character_name := '' var _factory: PopochiuCharacterFactory - #region Godot ###################################################################################### func _ready() -> void: super() @@ -61,7 +60,6 @@ func set_main_dock(node: Panel) -> void: if not _main_dock: return - #endregion #region Private #################################################################################### diff --git a/addons/popochiu/editor/popups/create_hotspot/create_hotspot.gd b/addons/popochiu/editor/popups/create_hotspot/create_hotspot.gd index 79bb94f3a..9c8c1cff9 100644 --- a/addons/popochiu/editor/popups/create_hotspot/create_hotspot.gd +++ b/addons/popochiu/editor/popups/create_hotspot/create_hotspot.gd @@ -1,3 +1,4 @@ +# Creates a new hotspot in the room. @tool extends 'res://addons/popochiu/editor/popups/creation_popup.gd' # Creates a new hotspot in the room. diff --git a/addons/popochiu/editor/popups/create_inventory_item/create_inventory_item.gd b/addons/popochiu/editor/popups/create_inventory_item/create_inventory_item.gd index fcf3636f1..6008ffc15 100644 --- a/addons/popochiu/editor/popups/create_inventory_item/create_inventory_item.gd +++ b/addons/popochiu/editor/popups/create_inventory_item/create_inventory_item.gd @@ -59,7 +59,6 @@ func set_main_dock(node: Panel) -> void: if not _main_dock: return - #endregion #region Private #################################################################################### diff --git a/addons/popochiu/engine/objects/graphic_interface/history/components/dialog_line.tscn b/addons/popochiu/engine/objects/graphic_interface/history/components/dialog_line.tscn new file mode 100644 index 000000000..1ecce2e97 --- /dev/null +++ b/addons/popochiu/engine/objects/graphic_interface/history/components/dialog_line.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=2 format=3 uid="uid://b6dm3xvvr7dvi"] + +[ext_resource type="FontFile" uid="uid://dixh1egf7k2fb" path="res://addons/popochiu/fonts/monkeyisland_1991.ttf" id="1_o6vvl"] + +[node name="DialogLine" type="Label"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +theme_override_fonts/font = ExtResource("1_o6vvl") +text = "Dave: hola" diff --git a/addons/popochiu/engine/objects/graphic_interface/history/components/interaction_line.tscn b/addons/popochiu/engine/objects/graphic_interface/history/components/interaction_line.tscn new file mode 100644 index 000000000..fd26607a3 --- /dev/null +++ b/addons/popochiu/engine/objects/graphic_interface/history/components/interaction_line.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=2 format=3 uid="uid://2mnjw3qsi8hc"] + +[ext_resource type="FontFile" uid="uid://dixh1egf7k2fb" path="res://addons/popochiu/fonts/monkeyisland_1991.ttf" id="1_i1qxr"] + +[node name="InteractionLine" type="Label"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +theme_override_fonts/font = ExtResource("1_i1qxr") +text = "Dave: hola" diff --git a/popochiu/rooms/house/room_house.tscn b/popochiu/rooms/house/room_house.tscn new file mode 100644 index 000000000..48edbc560 --- /dev/null +++ b/popochiu/rooms/house/room_house.tscn @@ -0,0 +1,131 @@ +[gd_scene load_steps=12 format=3 uid="uid://imgyvjiqcabs"] + +[ext_resource type="Script" path="res://popochiu/rooms/house/room_house.gd" id="1_2rfwu"] +[ext_resource type="PackedScene" uid="uid://jrp1r8uco7vy" path="res://popochiu/rooms/house/props/background/prop_background.tscn" id="2_amufg"] +[ext_resource type="Script" path="res://popochiu/rooms/house/props/background/prop_background.gd" id="3_fxlxc"] +[ext_resource type="PackedScene" uid="uid://dbkathyetrso7" path="res://popochiu/rooms/house/props/door/prop_door.tscn" id="4_qpaur"] +[ext_resource type="Script" path="res://popochiu/rooms/house/props/door/prop_door.gd" id="5_h0lr0"] +[ext_resource type="PackedScene" uid="uid://mqwbrgbk0llc" path="res://popochiu/rooms/house/props/drawer/prop_drawer.tscn" id="6_uvcj4"] +[ext_resource type="Script" path="res://popochiu/rooms/house/props/drawer/prop_drawer.gd" id="7_o4euj"] +[ext_resource type="PackedScene" uid="uid://diukdigj0f4io" path="res://popochiu/rooms/house/props/table/prop_table.tscn" id="8_hg5ln"] +[ext_resource type="Script" path="res://popochiu/rooms/house/props/table/prop_table.gd" id="9_ktt1q"] +[ext_resource type="PackedScene" uid="uid://1467eig2vwbo" path="res://popochiu/rooms/house/props/toy_car/prop_toy_car.tscn" id="10_nkfsd"] +[ext_resource type="Script" path="res://popochiu/rooms/house/props/toy_car/prop_toy_car.gd" id="11_earee"] + +[node name="RoomHouse" type="Node2D"] +script = ExtResource("1_2rfwu") +script_name = "House" +popochiu_placeholder = null +metadata/_popochiu_aseprite_config_ = { +"o_folder": "", +"o_name": "", +"only_visible_layers": false, +"op_exp": true, +"source": "res://popochiu/rooms/house/house.aseprite", +"tags": [{ +"direction": "forward", +"from": 0, +"import": true, +"loops": true, +"prop_clickable": true, +"prop_visible": true, +"tag_name": "background", +"to": 1.0 +}, { +"direction": "forward", +"from": 0, +"import": true, +"loops": true, +"prop_clickable": true, +"prop_visible": true, +"tag_name": "door", +"to": 2.0 +}, { +"direction": "forward", +"from": 0, +"import": true, +"loops": true, +"prop_clickable": true, +"prop_visible": true, +"tag_name": "drawer", +"to": 2.0 +}, { +"direction": "forward", +"from": 0, +"import": true, +"loops": true, +"prop_clickable": true, +"prop_visible": true, +"tag_name": "table", +"to": 1.0 +}, { +"direction": "forward", +"from": 0, +"import": true, +"loops": true, +"prop_clickable": true, +"prop_visible": true, +"tag_name": "toy_car", +"to": 1.0 +}], +"wipe_old_anims": true +} + +[node name="WalkableAreas" type="Node2D" parent="."] + +[node name="Props" type="Node2D" parent="."] + +[node name="Background" type="Area2D" parent="Props" instance=ExtResource("2_amufg")] +z_index = -1 +position = Vector2(160, 90) +script = ExtResource("3_fxlxc") +script_name = "Background" +description = "Background" +baseline = -90 +cursor = 1 +interaction_polygon = PackedVector2Array(-12, -12, 12, -12, 12, 12, -12, 12) +metadata/ANIM_NAME = "background" + +[node name="Door" type="Area2D" parent="Props" instance=ExtResource("4_qpaur")] +position = Vector2(160, 90) +script = ExtResource("5_h0lr0") +script_name = "Door" +description = "Door" +cursor = 1 +interaction_polygon = PackedVector2Array(-12, -12, 12, -12, 12, 12, -12, 12) +metadata/ANIM_NAME = "door" + +[node name="Drawer" type="Area2D" parent="Props" instance=ExtResource("6_uvcj4")] +position = Vector2(160, 90) +script = ExtResource("7_o4euj") +script_name = "Drawer" +description = "Drawer" +cursor = 1 +interaction_polygon = PackedVector2Array(-12, -12, 12, -12, 12, 12, -12, 12) +metadata/ANIM_NAME = "drawer" + +[node name="Table" type="Area2D" parent="Props" instance=ExtResource("8_hg5ln")] +position = Vector2(160, 90) +script = ExtResource("9_ktt1q") +script_name = "Table" +description = "Table" +cursor = 1 +interaction_polygon = PackedVector2Array(-12, -12, 12, -12, 12, 12, -12, 12) +metadata/ANIM_NAME = "table" + +[node name="ToyCar" type="Area2D" parent="Props" instance=ExtResource("10_nkfsd")] +position = Vector2(160, 90) +script = ExtResource("11_earee") +script_name = "ToyCar" +description = "Toy Car" +cursor = 1 +interaction_polygon = PackedVector2Array(-12, -12, 12, -12, 12, 12, -12, 12) +metadata/ANIM_NAME = "toy_car" + +[node name="Hotspots" type="Node2D" parent="."] + +[node name="Regions" type="Node2D" parent="."] + +[node name="Markers" type="Node2D" parent="."] + +[node name="Characters" type="Node2D" parent="."] diff --git a/popochiu/sources/aseprite/room_exterior.aseprite b/popochiu/sources/aseprite/room_exterior.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..8024404e40e6eb04ce981fe3bc0fbaf58130e280 GIT binary patch literal 9508 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 ga!}{z1)+fuI&G1&O^koe(*8dMfnCV|%a>#S1