diff --git a/Themes/UI Theme.tres b/Themes/UI Theme.tres new file mode 100644 index 0000000..5faba1b --- /dev/null +++ b/Themes/UI Theme.tres @@ -0,0 +1,15 @@ +[gd_resource type="Theme" load_steps=2 format=3 uid="uid://dm7ee4aqjr2dl"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_l4fss"] +bg_color = Color(9.14484e-07, 0.446448, 0.577112, 1) +corner_radius_top_left = 8 +corner_radius_top_right = 8 +corner_radius_bottom_right = 8 +corner_radius_bottom_left = 8 + +[resource] +MarginContainer/constants/margin_bottom = 16 +MarginContainer/constants/margin_left = 16 +MarginContainer/constants/margin_right = 16 +MarginContainer/constants/margin_top = 16 +PanelContainer/styles/panel = SubResource("StyleBoxFlat_l4fss") diff --git a/scenes/Systems.tscn b/scenes/Systems.tscn index e570f71..e3b8cfc 100644 --- a/scenes/Systems.tscn +++ b/scenes/Systems.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=5 format=3 uid="uid://iibqlagufwhm"] +[gd_scene load_steps=6 format=3 uid="uid://iibqlagufwhm"] [ext_resource type="Script" path="res://scripts/System/Systems.gd" id="1_uen2c"] [ext_resource type="Script" path="res://scripts/System/CutsceneSystem.gd" id="2_sf62c"] [ext_resource type="Script" path="res://scripts/System/ItemSystem.gd" id="3_nwp6i"] [ext_resource type="Script" path="res://scripts/System/QuestSystem.gd" id="4_d00wi"] +[ext_resource type="Script" path="res://scripts/System/VNSystem.gd" id="5_22p3i"] [node name="Systems" type="Node3D"] script = ExtResource("1_uen2c") @@ -16,3 +17,6 @@ script = ExtResource("3_nwp6i") [node name="Quest" type="Node3D" parent="."] script = ExtResource("4_d00wi") + +[node name="VN" type="Node3D" parent="."] +script = ExtResource("5_22p3i") diff --git a/scenes/TestScene.tscn b/scenes/TestScene.tscn index 27ca132..77aae94 100644 --- a/scenes/TestScene.tscn +++ b/scenes/TestScene.tscn @@ -1,10 +1,12 @@ -[gd_scene load_steps=9 format=3 uid="uid://bdrpqtbwvtivd"] +[gd_scene load_steps=11 format=3 uid="uid://bdrpqtbwvtivd"] [ext_resource type="PackedScene" uid="uid://yhtpoum3eek7" path="res://scenes/Entities/Rosa.tscn" id="1_3u2u0"] [ext_resource type="PackedScene" uid="uid://iibqlagufwhm" path="res://scenes/Systems.tscn" id="1_3x3uf"] [ext_resource type="PackedScene" uid="uid://dr4b2pmsknuhc" path="res://scenes/Entities/TestNPC.tscn" id="2_6f3lj"] [ext_resource type="PackedScene" uid="uid://7wjfo6u4dp3h" path="res://scenes/Maps/test.tscn" id="4_18e1y"] [ext_resource type="PackedScene" uid="uid://cy4r0tp2htivb" path="res://scenes/MapBounds.tscn" id="4_gv7tl"] +[ext_resource type="Theme" uid="uid://dm7ee4aqjr2dl" path="res://Themes/UI Theme.tres" id="6_d185f"] +[ext_resource type="PackedScene" uid="uid://bkx3l0kckf4a8" path="res://scenes/UI/VNTextbox.tscn" id="7_nofjj"] [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_1b6it"] sky_horizon_color = Color(0.59625, 0.6135, 0.6375, 1) @@ -41,3 +43,16 @@ omni_range = 281.646 [node name="MapBounds" parent="." instance=ExtResource("4_gv7tl")] transform = Transform3D(22.0363, 0, 0, 0, 7.5201, 0, 0, 0, 19.278, 1.48402, 2.89779, 1.65935) + +[node name="UI" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("6_d185f") + +[node name="VNTextbox" parent="UI" instance=ExtResource("7_nofjj")] +layout_mode = 1 +offset_top = -133.0 diff --git a/scenes/UI/VNTextbox.tscn b/scenes/UI/VNTextbox.tscn new file mode 100644 index 0000000..f1816f1 --- /dev/null +++ b/scenes/UI/VNTextbox.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=3 format=3 uid="uid://bkx3l0kckf4a8"] + +[ext_resource type="Theme" uid="uid://dm7ee4aqjr2dl" path="res://Themes/UI Theme.tres" id="1_wx4lp"] +[ext_resource type="Script" path="res://scripts/UI/VNTextbox.gd" id="2_uo1gm"] + +[node name="VNTextbox" type="PanelContainer"] +anchors_preset = 12 +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_top = -134.0 +grow_horizontal = 2 +grow_vertical = 0 +theme = ExtResource("1_wx4lp") +script = ExtResource("2_uo1gm") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme = ExtResource("1_wx4lp") + +[node name="Label" type="RichTextLabel" parent="MarginContainer"] +layout_mode = 2 +theme = ExtResource("1_wx4lp") +text = "test +test +test" diff --git a/scripts/Cutscene/Event/CutsceneChangeEvent.gd b/scripts/Cutscene/Event/CutsceneChangeEvent.gd index 547f989..794bda8 100644 --- a/scripts/Cutscene/Event/CutsceneChangeEvent.gd +++ b/scripts/Cutscene/Event/CutsceneChangeEvent.gd @@ -15,4 +15,4 @@ func end() -> void: self.cutsceneNext.setupCutscene(); self.cutsceneNext.start(); var systems = get_tree().current_scene.get_node("Systems") as Systems; - systems.CUTSCENE.setCurrentCutscene(self.cutsceneNext); \ No newline at end of file + systems.CUTSCENE.setCurrentCutscene(self.cutsceneNext); diff --git a/scripts/Entities/TestNPCController.gd b/scripts/Entities/TestNPCController.gd index e09b3cb..4b63177 100644 --- a/scripts/Entities/TestNPCController.gd +++ b/scripts/Entities/TestNPCController.gd @@ -3,11 +3,14 @@ const TestCutscene = preload("res://scripts/Cutscene/TestCutscene.gd") func interact(interactor) -> void: var systems = getSystems(); - systems.CUTSCENE.setCurrentCutscene(TestCutscene.new()) - #systems.ITEM.addItem(systems.ITEM.ITEM_POTION, 1); - #var itemSystem = (get_node("Systems") as Systems).ITEM; - #itemSystem.addItem(itemSystem.ITEM_POTION, 1); - #pass + # systems.VN.getTextbox().setText("1-2-3\n4-5-6\n\n7-8-9\n10-11-12\n13-14-15\n16-17-18\n19-20-21\n22-23-24\n25-26-27\n28-29-30\n31-32-33\n34-35-36\n37-38-39\n40-41-42\n43-44-45\n46-47-48\n49-50-51\n52-53-54\n55-56-57\n58-59-60\n61-62-63\n64-65-66\n67-68-69\n70-71-72\n73-74-75\n76-77-78\n79-80-81\n82-83-84\n85-86-87\n88-89-90\n91-92-93\n94-95-96\n97-98-99\n100-101-102\n103-104-105\n106-107-108\n109-110-111\n112-113-114\n115-116-117\n118-119-120\n121-122-123\n124-125-126\n127-128-129\n130-131-132\n133-134-135\n136-137-138\n139-140-141\n142-143-144\n145-146-147\n148-149-150\n151-152-153\n154-155-156\n157-158-159\n160-161-162\n163-164-165\n166-167-168\n169-170-171\n172-173-174\n175-176-177\n178-179-180\n181-182-183\n184-185-186\n187-188-189\n190-191-192\n193-194-195\n196-197-198\n199-200-201\n202-203-204\n205-206-207\n208-209-210\n211-212-213\n214-215-216\n217-218-219\n220-221-222\n223-224-225\n226-227-228\n229-230-231\n232-233-234\n235-236-237\n238-239-240\n241-242-243\n244-245-246\n247-248-249\n250-251-252\n253-254-255\n256-257-258"); + systems.VN.getTextbox().setText("Hello World\nHow are you?"); +# systems.VN.getTextbox().setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras ut convallis nisl. Nulla eleifend erat non odio convallis tempus. Quisque sagittis egestas lacus, eget varius diam ullamcorper vel. Donec lacinia luctus turpis ac sodales. Praesent in quam maximus justo pretium iaculis. Morbi tristique nisi est, imperdiet volutpat velit semper congue. Nam eleifend ornare lorem eu ornare. Donec ac venenatis mauris. Etiam a purus a velit cursus pellentesque sed at neque. Proin viverra turpis ut lorem congue vestibulum. Proin a sapien id odio tempus tincidunt sed at lacus. Curabitur nisi nulla, porta ac magna sit amet, ornare elementum nisi. Proin convallis eget nisi ac vehicula. Mauris at consequat dolor, 1 2 3 4 5 pellentesque est. Nullam dapibus aliquet nisl eu porta. Quisque sagittis sem nec nibh tristique fermentum. +# Mauris eu nunc condimentum est rhoncus suscipit elementum sit amet felis. Morbi ut hendrerit ipsum. Cras vel sollicitudin odio. Maecenas eget finibus orci. Etiam tempus nulla vitae tincidunt aliquet. Nulla consectetur, massa sed rutrum iaculis, leo nulla bibendum erat, commodo rutrum magna lorem sit amet turpis. Morbi vel sollicitudin arcu, sit amet tempus leo. Nunc molestie sed dui eu fringilla. Mauris egestas lectus ac nisi condimentum, sollicitudin rhoncus arcu pellentesque. Vestibulum quis suscipit odio. +# Aenean ac metus nisi. Quisque et posuere ex. Vivamus et laoreet nulla. Nam quis faucibus diam. Aenean blandit dui sed est vehicula, sit amet dignissim mauris ultricies. Vivamus semper nisi vel erat dignissim interdum eu vitae enim. Nunc dignissim ligula imperdiet finibus dapibus. Pellentesque non erat sollicitudin libero convallis convallis. Nulla commodo, dolor aliquet laoreet lacinia, turpis lectus aliquet sem, et porttitor ipsum elit quis quam. Aliquam erat volutpat. Aliquam sit amet quam vel enim scelerisque blandit. Sed congue aliquam sodales. +# Pellentesque nec mauris id felis dignissim ullamcorper. Fusce quis ex accumsan, dictum risus vel, blandit ligula. Vestibulum at dolor ut neque faucibus rhoncus ac rhoncus risus. Nulla id semper dolor. In vel aliquam lectus. Morbi et dignissim augue. Nunc commodo elit at ligula ullamcorper iaculis. Morbi accumsan accumsan lectus, a iaculis magna. Nam auctor ac eros at venenatis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis et tincidunt lacus. Aliquam vitae quam et ipsum luctus tincidunt tincidunt eget sem. Morbi vestibulum ante mauris. Vestibulum ac faucibus quam. Vestibulum interdum odio nulla, nec pellentesque mi imperdiet ac. +# Morbi dictum mattis porttitor. Integer eu nulla maximus, vehicula urna at, iaculis odio. Nam feugiat, dui vitae imperdiet mattis, felis dui elementum risus, sed dapibus sem turpis quis mi. Sed lacinia vehicula risus, sed scelerisque enim euismod sed. Sed aliquet efficitur sapien vitae cursus. Phasellus non elit metus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque vitae tellus erat. Curabitur vel elit sagittis, dignissim orci at, vulputate lacus. Nam ut magna velit. Fusce sit amet tristique lacus."); + # systems.QUEST.QUEST_EXAMPLE.start(); func updateMovement(delta) -> void: pass diff --git a/scripts/Quest/Quest.gd b/scripts/Quest/Quest.gd index 6a5442e..2c15128 100644 --- a/scripts/Quest/Quest.gd +++ b/scripts/Quest/Quest.gd @@ -24,6 +24,7 @@ func getState() -> QuestState: return questState; func start(): + print("Starting quest: " + questName); questState = QuestState.ACTIVE; currentObjective = 0; diff --git a/scripts/System/Systems.gd b/scripts/System/Systems.gd index bae8d47..a2eb970 100644 --- a/scripts/System/Systems.gd +++ b/scripts/System/Systems.gd @@ -2,16 +2,18 @@ class_name Systems extends Node const ItemSystem = preload("res://scripts/System/ItemSystem.gd"); const CutsceneSystem = preload("res://scripts/System/CutsceneSystem.gd"); const QuestSystem = preload("res://scripts/System/QuestSystem.gd"); +const VNSystem = preload("res://scripts/System/VNSystem.gd"); var ITEM:ItemSystem; var CUTSCENE:CutsceneSystem; var QUEST:QuestSystem; +var VN:VNSystem; func _ready(): ITEM = $Item; CUTSCENE = $Cutscene; QUEST = $Quest; - pass + VN = $VN; func _process(delta): pass diff --git a/scripts/System/VNSystem.gd b/scripts/System/VNSystem.gd new file mode 100644 index 0000000..47734bd --- /dev/null +++ b/scripts/System/VNSystem.gd @@ -0,0 +1,5 @@ +class_name VNSystem extends Node +const VNTextbox = preload("res://scripts/UI/VNTextbox.gd") + +func getTextbox() -> VNTextbox: + return get_tree().current_scene.get_node("UI/VNTextbox") as VNTextbox; diff --git a/scripts/UI/VNTextbox.gd b/scripts/UI/VNTextbox.gd new file mode 100644 index 0000000..e9925db --- /dev/null +++ b/scripts/UI/VNTextbox.gd @@ -0,0 +1,111 @@ +class_name VNTextbox extends PanelContainer + +const VN_REVEAL_TIME = 0.01 +const VISIBLE_LINES:int = 4 + +var label:RichTextLabel; +var text:String = "" +var parsedOutText = "" +var visibleCharacters:int = 0; +var revealTimer:float = 0; + +var lineStarts:Array[int] = []; +var newlineIndexes:Array[int] = []; +var wrappedText:String = ""; +var currentLine = 0; +var currentViewScrolled = true; +var isSpeedupDown = false; +var isMoreViews = false; + +func _ready() -> void: + label = $MarginContainer/Label + +func _process(delta: float) -> void: + if text == "": + return; + + if currentViewScrolled: + if Input.is_action_just_pressed("interact"): + if isMoreViews: + visibleCharacters = 0; + currentLine += VISIBLE_LINES; + currentViewScrolled = false; + recalculateWrapping(); + return + print("End of view"); + return; + + if visibleCharacters >= getCountOfCharactersToScrollInView(): + currentViewScrolled = true; + print("Scrolled view"); + if isMoreViews: + print("More views"); + return; + + if Input.is_action_just_pressed("interact"): + isSpeedupDown = true; + elif Input.is_action_just_released("interact"): + isSpeedupDown = false; + elif !Input.is_action_pressed("interact"): + isSpeedupDown = false; + + revealTimer += delta; + if isSpeedupDown: + revealTimer += delta; + + if revealTimer > VN_REVEAL_TIME: + revealTimer = 0; + visibleCharacters += 1; + label.visible_characters = visibleCharacters; + +func getCountOfCharactersToScrollInView() -> int: + if lineStarts.size() <= VISIBLE_LINES: + return wrappedText.length(); + if currentLine + VISIBLE_LINES >= lineStarts.size(): + return wrappedText.length() - lineStarts[currentLine]; + return lineStarts[min(lineStarts.size(), currentLine + VISIBLE_LINES)] - lineStarts[currentLine]; + +func recalculateWrapping(): + # Reset label to default. + label.text = text; + label.visible_characters = -1; + label.fit_content = true; + isMoreViews = false; + + # Determine where the wrapped newlines are + lineStarts = [ 0 ]; + var line = 0; + var wasNewLine = false; + for i in range(0, text.length()): + var tLine = label.get_character_line(i); + if tLine == line: + wasNewLine = false + if text[i] == "\n": + wasNewLine = true + continue; + if !wasNewLine: + newlineIndexes.append(i); + lineStarts.append(i); + line = tLine; + + # Create fake pre-wrapped text. + wrappedText = ""; + for i in range(lineStarts[currentLine], text.length()): + if newlineIndexes.find(i) != -1 and i != lineStarts[currentLine]: + wrappedText += "\n"; + wrappedText += text[i]; + + label.text = wrappedText; + label.fit_content = false; + label.visible_characters = 0; + + if lineStarts.size() > currentLine + VISIBLE_LINES: + isMoreViews = true; + +func setText(text:String) -> void: + self.text = text; + revealTimer = 0; + visibleCharacters = 0; + currentLine = 0; + currentViewScrolled = false; + recalculateWrapping();