This commit is contained in:
2025-11-26 18:57:37 -06:00
parent 1e83200bba
commit d532a9ab21
25 changed files with 525 additions and 534 deletions

View File

@@ -5,23 +5,23 @@ signal interactable(playerEntity:Player)
signal notInteractable(playerEntity:Player)
func _enter_tree() -> void:
area_entered.connect(onAreaEntered)
area_exited.connect(onAreaExited)
area_entered.connect(onAreaEntered)
area_exited.connect(onAreaExited)
func _exit_tree() -> void:
area_entered.disconnect(onAreaEntered)
area_exited.disconnect(onAreaExited)
area_entered.disconnect(onAreaEntered)
area_exited.disconnect(onAreaExited)
func onAreaEntered(area:Area3D) -> void:
if !area.get_parent() or !(area.get_parent() is Player):
return
var player:Player = area.get_parent() as Player
interactable.emit(player)
if !area.get_parent() or !(area.get_parent() is Player):
return
var player:Player = area.get_parent() as Player
interactable.emit(player)
func onAreaExited(area:Area3D) -> void:
if !area.get_parent() or !(area.get_parent() is Player):
return
if !area.get_parent() or !(area.get_parent() is Player):
return
var player:Player = area.get_parent() as Player
notInteractable.emit(player)
var player:Player = area.get_parent() as Player
notInteractable.emit(player)

View File

@@ -7,44 +7,44 @@ var interactableArea:InteractableArea
var shapeChild:CollisionShape3D
func _enter_tree() -> void:
interactableArea = $InteractableArea
interactableArea = $InteractableArea
if !mapResource:
push_error("MapChangeInteract must have a mapResource set.")
return
if !mapResource:
push_error("MapChangeInteract must have a mapResource set.")
return
# Needs to be exactly one child.
if get_child_count() != 2:
push_error("MapChangeInteract must have exactly one child InteractableArea node.")
return
# Needs to be exactly one child.
if get_child_count() != 2:
push_error("MapChangeInteract must have exactly one child InteractableArea node.")
return
var child = get_child(1)
if not (child is CollisionShape3D):
push_error("MapChangeInteract's child must be an CollisionShape3D node.")
var child = get_child(1)
if not (child is CollisionShape3D):
push_error("MapChangeInteract's child must be an CollisionShape3D node.")
shapeChild = child
remove_child(shapeChild)
interactableArea.add_child(shapeChild)
shapeChild = child
remove_child(shapeChild)
interactableArea.add_child(shapeChild)
interactableArea.interactEvent.connect(onInteract)
interactableArea.interactable.connect(onInteractable)
interactableArea.notInteractable.connect(onNotInteractable)
interactableArea.interactEvent.connect(onInteract)
interactableArea.interactable.connect(onInteractable)
interactableArea.notInteractable.connect(onNotInteractable)
func _exit_tree() -> void:
interactableArea.interactEvent.disconnect(onInteract)
interactableArea.interactable.disconnect(onInteractable)
interactableArea.notInteractable.disconnect(onNotInteractable)
interactableArea.interactEvent.disconnect(onInteract)
interactableArea.interactable.disconnect(onInteractable)
interactableArea.notInteractable.disconnect(onNotInteractable)
interactableArea.remove_child(shapeChild)
add_child(shapeChild)
interactableArea.remove_child(shapeChild)
add_child(shapeChild)
func onInteract(_ent:Player) -> void:
OVERWORLD.mapChange(mapResource, destinationPointNodeName)
OVERWORLD.mapChange(mapResource, destinationPointNodeName)
func onInteractable(_ent:Player) -> void:
print("Able to leave map")
pass
print("Able to leave map")
pass
func onNotInteractable(_ent:Player) -> void:
print("Not able to leave map")
pass
print("Not able to leave map")
pass

View File

@@ -3,10 +3,10 @@ class_name CutsceneItem extends Node
var cutscene:Cutscene = null
func start() -> void:
# This method should be overridden by subclasses
pass
# This method should be overridden by subclasses
pass
func done() -> void:
if !cutscene:
return
cutscene.nextItem()
if !cutscene:
return
cutscene.nextItem()

View File

@@ -4,24 +4,24 @@ class_name EntityMovement extends Node
const FRICTION = 0.01
enum FacingDirection {
SOUTH = 0,
EAST = 1,
NORTH = 2,
WEST = 3
SOUTH = 0,
EAST = 1,
NORTH = 2,
WEST = 3
};
const FacingDirWalkAnimations = {
FacingDirection.SOUTH: "walk_south",
FacingDirection.EAST: "walk_east",
FacingDirection.NORTH: "walk_north",
FacingDirection.WEST: "walk_west"
FacingDirection.SOUTH: "walk_south",
FacingDirection.EAST: "walk_east",
FacingDirection.NORTH: "walk_north",
FacingDirection.WEST: "walk_west"
};
const FacingDirAngle = {
FacingDirection.SOUTH: 0.0,
FacingDirection.EAST: PI / 2,
FacingDirection.NORTH: PI,
FacingDirection.WEST: -PI / 2
FacingDirection.SOUTH: 0.0,
FacingDirection.EAST: PI / 2,
FacingDirection.NORTH: PI,
FacingDirection.WEST: -PI / 2
};
var _inputDir:Vector2 = Vector2.ZERO
@@ -34,115 +34,115 @@ var _running:bool = false
@export var walkSpeed:float = 48.0
@export var runSpeed:float = 64.0
@export var facingDir:FacingDirection = FacingDirection.SOUTH:
set(value):
_facingDir = value
_updateSprite()
get:
return _facingDir
set(value):
_facingDir = value
_updateSprite()
get:
return _facingDir
#
# Private Methods
#
func _updateSprite() -> void:
if !sprite || sprite.animation == FacingDirWalkAnimations[facingDir]:
return
sprite.animation = FacingDirWalkAnimations[facingDir]
if !sprite || sprite.animation == FacingDirWalkAnimations[facingDir]:
return
sprite.animation = FacingDirWalkAnimations[facingDir]
func _applyFacingDir() -> void:
if !sprite || _inputDir.length() <= 0.01:
return
if !sprite || _inputDir.length() <= 0.01:
return
if _inputDir.y > 0:
if facingDir != FacingDirection.NORTH && _inputDir.x != 0:
if _inputDir.x > 0 && facingDir == FacingDirection.EAST:
facingDir = FacingDirection.EAST
elif _inputDir.x < 0 && facingDir == FacingDirection.WEST:
facingDir = FacingDirection.WEST
else:
facingDir = FacingDirection.NORTH
else:
facingDir = FacingDirection.NORTH
elif _inputDir.y < 0:
if facingDir != FacingDirection.SOUTH && _inputDir.x != 0:
if _inputDir.x > 0 && facingDir == FacingDirection.EAST:
facingDir = FacingDirection.EAST
elif _inputDir.x < 0 && facingDir == FacingDirection.WEST:
facingDir = FacingDirection.WEST
else:
facingDir = FacingDirection.SOUTH
else:
facingDir = FacingDirection.SOUTH
elif _inputDir.x > 0:
facingDir = FacingDirection.EAST
else:
facingDir = FacingDirection.WEST
if _inputDir.y > 0:
if facingDir != FacingDirection.NORTH && _inputDir.x != 0:
if _inputDir.x > 0 && facingDir == FacingDirection.EAST:
facingDir = FacingDirection.EAST
elif _inputDir.x < 0 && facingDir == FacingDirection.WEST:
facingDir = FacingDirection.WEST
else:
facingDir = FacingDirection.NORTH
else:
facingDir = FacingDirection.NORTH
elif _inputDir.y < 0:
if facingDir != FacingDirection.SOUTH && _inputDir.x != 0:
if _inputDir.x > 0 && facingDir == FacingDirection.EAST:
facingDir = FacingDirection.EAST
elif _inputDir.x < 0 && facingDir == FacingDirection.WEST:
facingDir = FacingDirection.WEST
else:
facingDir = FacingDirection.SOUTH
else:
facingDir = FacingDirection.SOUTH
elif _inputDir.x > 0:
facingDir = FacingDirection.EAST
else:
facingDir = FacingDirection.WEST
func _applyGravity() -> void:
if !body.is_on_floor():
body.velocity += PHYSICS.GRAVITY * get_process_delta_time()
if !body.is_on_floor():
body.velocity += PHYSICS.GRAVITY * get_process_delta_time()
func _applyMovement() -> void:
if !canMove():
return
if !canMove():
return
var cameraCurrent = get_viewport().get_camera_3d()
if !cameraCurrent:
return
var cameraCurrent = get_viewport().get_camera_3d()
if !cameraCurrent:
return
# Use camera orientation for movement direction
var camBasis = cameraCurrent.global_transform.basis
# Use camera orientation for movement direction
var camBasis = cameraCurrent.global_transform.basis
# Forward and right vectors, ignore vertical component
var forward = -camBasis.z
forward.y = 0
forward = forward.normalized()
var right = camBasis.x
right.y = 0
right = right.normalized()
# Forward and right vectors, ignore vertical component
var forward = -camBasis.z
forward.y = 0
forward = forward.normalized()
var right = camBasis.x
right.y = 0
right = right.normalized()
var directionAdjusted = (
forward * _inputDir.y + right * _inputDir.x
).normalized()
if directionAdjusted.length() <= 0.01:
return
var directionAdjusted = (
forward * _inputDir.y + right * _inputDir.x
).normalized()
if directionAdjusted.length() <= 0.01:
return
if rotate:
var targetRot = atan2(directionAdjusted.x, directionAdjusted.z)
rotate.rotation.y = targetRot
if rotate:
var targetRot = atan2(directionAdjusted.x, directionAdjusted.z)
rotate.rotation.y = targetRot
var speed = walkSpeed
if _running:
speed = runSpeed
body.velocity.x = directionAdjusted.x * speed
body.velocity.z = directionAdjusted.z * speed
var speed = walkSpeed
if _running:
speed = runSpeed
body.velocity.x = directionAdjusted.x * speed
body.velocity.z = directionAdjusted.z * speed
func _applyFriction(delta:float) -> void:
body.velocity.x *= delta * FRICTION
body.velocity.z *= delta * FRICTION
body.velocity.x *= delta * FRICTION
body.velocity.z *= delta * FRICTION
#
# Protected Methods
#
func canMove() -> bool:
return true
return true
#
# Callbacks
#
func _enter_tree() -> void:
_updateSprite()
_updateSprite()
func _physics_process(delta:float) -> void:
if Engine.is_editor_hint():
return
if Engine.is_editor_hint():
return
if !body:
return
if !body:
return
_applyGravity()
_applyFriction(delta)
_applyMovement()
_applyFacingDir()
body.move_and_slide()
_applyGravity()
_applyFriction(delta)
_applyMovement()
_applyFacingDir()
body.move_and_slide()

View File

@@ -4,35 +4,35 @@ class_name NPC extends CharacterBody3D
@export var _movement:NPCMovement
@export var facingDirection:EntityMovement.FacingDirection:
set(value):
if _movement:
_movement.facingDir = value
get:
if _movement:
return _movement.facingDir
return EntityMovement.FacingDirection.SOUTH
set(value):
if _movement:
_movement.facingDir = value
get:
if _movement:
return _movement.facingDir
return EntityMovement.FacingDirection.SOUTH
@export var walkSpeed:float = 48.0:
set(value):
if _movement:
_movement.walkSpeed = value
get:
if _movement:
return _movement.walkSpeed
return 48.0
set(value):
if _movement:
_movement.walkSpeed = value
get:
if _movement:
return _movement.walkSpeed
return 48.0
@export var runSpeed:float = 64.0:
set(value):
if _movement:
_movement.runSpeed = value
get:
if _movement:
return _movement.runSpeed
return 64.0
set(value):
if _movement:
_movement.runSpeed = value
get:
if _movement:
return _movement.runSpeed
return 64.0
func onInteract(player:Player) -> void:
UI.TEXTBOX.setText("Hello, I'm an NPC!\nThis is the second line here, I am purposefully adding a tonne of words so that it is forced to go across multiple lines and you can see how the word wrapping works, not only using Godot's built in word wrapping but with my advanced visibile characters smart wrapping. Now I am doing a multiline thing\nLine 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10");
pass
UI.TEXTBOX.setText("Hello, I'm an NPC!\nThis is the second line here, I am purposefully adding a tonne of words so that it is forced to go across multiple lines and you can see how the word wrapping works, not only using Godot's built in word wrapping but with my advanced visibile characters smart wrapping. Now I am doing a multiline thing\nLine 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10");
pass
func _enter_tree() -> void:
pass
pass

View File

@@ -1,5 +1,5 @@
class_name NPCTest extends Node
func onInteract(playerEntity: Player) -> void:
print("Player has interacted with the NPC.")
UI.TEXTBOX.setText("You have interacted with the NPC.")
print("Player has interacted with the NPC.")
UI.TEXTBOX.setText("You have interacted with the NPC.")

View File

@@ -4,28 +4,28 @@ class_name Player extends CharacterBody3D
@export var _movement:PlayerMovement
@export var facingDirection:EntityMovement.FacingDirection:
set(value):
if _movement:
_movement.facingDir = value
get:
if _movement:
return _movement.facingDir
return EntityMovement.FacingDirection.SOUTH
set(value):
if _movement:
_movement.facingDir = value
get:
if _movement:
return _movement.facingDir
return EntityMovement.FacingDirection.SOUTH
@export var walkSpeed:float = 48.0:
set(value):
if _movement:
_movement.walkSpeed = value
get:
if _movement:
return _movement.walkSpeed
return 48.0
set(value):
if _movement:
_movement.walkSpeed = value
get:
if _movement:
return _movement.walkSpeed
return 48.0
@export var runSpeed:float = 64.0:
set(value):
if _movement:
_movement.runSpeed = value
get:
if _movement:
return _movement.runSpeed
return 64.0
set(value):
if _movement:
_movement.runSpeed = value
get:
if _movement:
return _movement.runSpeed
return 64.0

View File

@@ -9,25 +9,25 @@ const CAMERA_PIXEL_SCALE = 1.0
@export var offset:Vector3 = Vector3(0, 0, 12)
func _process(delta: float) -> void:
if !camera || !target:
return
if !camera || !target:
return
# I tried a few things but this is most consistent for both backbuffer and
# framebuffer viewports.
var viewportHeight = get_viewport().get_visible_rect().size.y;
var unitScale = CAMERA_PIXEL_SCALE * CAMERA_PIXELS_PER_UNIT;
# I tried a few things but this is most consistent for both backbuffer and
# framebuffer viewports.
var viewportHeight = get_viewport().get_visible_rect().size.y;
var unitScale = CAMERA_PIXEL_SCALE * CAMERA_PIXELS_PER_UNIT;
var z:float = (
tan((deg_to_rad(180) - deg_to_rad(camera.fov)) / 2.0) *
(viewportHeight / 2.0)
) / unitScale;
var look = target.global_position;
var position = offset + look;
var z:float = (
tan((deg_to_rad(180) - deg_to_rad(camera.fov)) / 2.0) *
(viewportHeight / 2.0)
) / unitScale;
var look = target.global_position;
var position = offset + look;
camera.look_at_from_position(
Vector3(position.x, position.y + z, position.z),
look
);
camera.look_at_from_position(
Vector3(position.x, position.y + z, position.z),
look
);
pass
pass

View File

@@ -4,10 +4,10 @@ class_name PlayerInput extends Node
@export var movement:PlayerMovement
func _process(delta: float) -> void:
if Input.is_action_just_pressed("pause"):
PAUSE.menuPause()
if Input.is_action_just_pressed("pause"):
PAUSE.menuPause()
if Input.is_action_just_pressed("interact"):
interaction.interact()
if Input.is_action_just_pressed("interact"):
interaction.interact()
movement._inputDir = Input.get_vector("move_left", "move_right", "move_back", "move_forward").normalized()
movement._inputDir = Input.get_vector("move_left", "move_right", "move_back", "move_forward").normalized()

View File

@@ -4,24 +4,24 @@ class_name PlayerInteraction extends Node
@export var player:CharacterBody3D
func canInteract() -> bool:
if PAUSE.isMovementPaused():
return false
return true
if PAUSE.isMovementPaused():
return false
return true
func interact() -> void:
if !canInteract():
return
if !canInteract():
return
var overlapping = interactableArea.get_overlapping_areas()
var interactable: InteractableArea = null
var overlapping = interactableArea.get_overlapping_areas()
var interactable: InteractableArea = null
for node in overlapping:
if !(node is InteractableArea):
continue
interactable = node
break
for node in overlapping:
if !(node is InteractableArea):
continue
interactable = node
break
if !interactable:
return
if !interactable:
return
interactable.interactEvent.emit(player)
interactable.interactEvent.emit(player)

View File

@@ -2,6 +2,6 @@
class_name PlayerMovement extends "res://entity/EntityMovement.gd"
func canMove() -> bool:
if PAUSE.isMovementPaused():
return false
return true
if PAUSE.isMovementPaused():
return false
return true

View File

@@ -3,32 +3,32 @@ class_name OverworldScene extends Node
@export var map:Node3D = null
func _enter_tree() -> void:
OVERWORLD.mapChanged.connect(onMapChanged)
OVERWORLD.mapChanged.connect(onMapChanged)
func _ready() -> void:
pass
pass
func _exit_tree() -> void:
OVERWORLD.mapChanged.disconnect(onMapChanged)
OVERWORLD.mapChanged.disconnect(onMapChanged)
func onMapChanged(newMap:PackedScene, playerDestinationNodeName:String) -> void:
print("New map time.", newMap)
for childScene in map.get_children():
map.remove_child(childScene)
print("New map time.", newMap)
for childScene in map.get_children():
map.remove_child(childScene)
if !newMap:
return
var newMapInstance = newMap.instantiate()
map.add_child(newMapInstance)
if !newMap:
return
var newMapInstance = newMap.instantiate()
map.add_child(newMapInstance)
# Find Player.
if playerDestinationNodeName:
var player = newMapInstance.get_node("Player")
var destNode = newMapInstance.get_node(playerDestinationNodeName)
if player && player is Player && destNode:
player.global_position = destNode.global_position
player.global_rotation.y = destNode.global_rotation.y
elif playerDestinationNodeName:
push_error("Player, or destination node not found in new map.")
pass
# Find Player.
if playerDestinationNodeName:
var player = newMapInstance.get_node("Player")
var destNode = newMapInstance.get_node(playerDestinationNodeName)
if player && player is Player && destNode:
player.global_position = destNode.global_position
player.global_rotation.y = destNode.global_rotation.y
elif playerDestinationNodeName:
push_error("Player, or destination node not found in new map.")
pass

View File

@@ -4,31 +4,31 @@ class_name RootScene extends Node3D
@export var initial:Node3D = null
func _enter_tree() -> void:
SCENE.sceneChanged.connect(onSceneChange)
SCENE.setScene(SceneSingleton.SceneType.INITIAL)
SCENE.sceneChanged.connect(onSceneChange)
SCENE.setScene(SceneSingleton.SceneType.INITIAL)
func _exit_tree() -> void:
push_error("RootScene should not be removed from the scene tree. This is a bug.")
push_error("RootScene should not be removed from the scene tree. This is a bug.")
func onSceneChange(newScene:SceneSingleton.SceneType) -> void:
print("overworld", overworld)
remove_child(overworld)
remove_child(initial)
print("overworld", overworld)
remove_child(overworld)
remove_child(initial)
overworld.visible = false
initial.visible = false
overworld.visible = false
initial.visible = false
match newScene:
SceneSingleton.SceneType.INITIAL:
add_child(initial)
initial.visible = true
match newScene:
SceneSingleton.SceneType.INITIAL:
add_child(initial)
initial.visible = true
SceneSingleton.SceneType.OVERWORLD:
add_child(overworld)
overworld.visible = true
SceneSingleton.SceneType.OVERWORLD:
add_child(overworld)
overworld.visible = true
SceneSingleton.SceneType.UNSET:
pass
SceneSingleton.SceneType.UNSET:
pass
_:
pass
_:
pass

View File

@@ -24,7 +24,6 @@ UI="*res://singleton/UI.tscn"
QUEST="*res://singleton/Quest.tscn"
OVERWORLD="*res://singleton/Overworld.gd"
SCENE="*res://singleton/Scene.gd"
MadTalkGlobals="*res://addons/madtalk/runtime/MadTalkGlobals.tscn"
ControllerIcons="*res://addons/controller_icons/ControllerIcons.gd"
[debug]
@@ -47,7 +46,7 @@ project/assembly_name="Dawn Godot"
[editor_plugins]
enabled=PackedStringArray("res://addons/controller_icons/plugin.cfg", "res://addons/madtalk/plugin.cfg")
enabled=PackedStringArray("res://addons/controller_icons/plugin.cfg")
[filesystem]

View File

@@ -9,77 +9,77 @@ var playerDestinationNodeName:String
var newMapLoaded:bool = false
func isMapChanging() -> bool:
return newMapPath != ""
return newMapPath != ""
func _enter_tree() -> void:
pass
pass
func _exit_tree() -> void:
TRANSITION.fadeOutEnd.disconnect(onFadeOutEnd)
TRANSITION.fadeInEnd.disconnect(onFadeInEnd)
TRANSITION.fadeOutEnd.disconnect(onFadeOutEnd)
TRANSITION.fadeInEnd.disconnect(onFadeInEnd)
func _process(_delta:float) -> void:
if(!isMapChanging()):
return
if(!isMapChanging()):
return
var status = ResourceLoader.load_threaded_get_status(newMapPath)
if status == ResourceLoader.THREAD_LOAD_FAILED:
push_error("Failed to load map: " + newMapPath)
newMapPath = ""
elif status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE:
push_error("Failed to load map: " + newMapPath)
newMapPath = ""
var status = ResourceLoader.load_threaded_get_status(newMapPath)
if status == ResourceLoader.THREAD_LOAD_FAILED:
push_error("Failed to load map: " + newMapPath)
newMapPath = ""
elif status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE:
push_error("Failed to load map: " + newMapPath)
newMapPath = ""
elif status == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
print("Map loading in progress for: " + newMapPath)
elif status == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
print("Map loading in progress for: " + newMapPath)
elif status == ResourceLoader.THREAD_LOAD_LOADED:
newMapLoaded = true
newMapReady()
elif status == ResourceLoader.THREAD_LOAD_LOADED:
newMapLoaded = true
newMapReady()
func mapChange(map:String, playerDestinationNodeName:String) -> void:
# Begin Loading new map
newMapPath = map
playerDestinationNodeName = playerDestinationNodeName
ResourceLoader.load_threaded_request(newMapPath)
# Begin Loading new map
newMapPath = map
playerDestinationNodeName = playerDestinationNodeName
ResourceLoader.load_threaded_request(newMapPath)
# Begin fadeout
hasFadedOut = false
TRANSITION.fade(TransitionSingleton.FadeType.FADE_OUT)
TRANSITION.fadeOutEnd.connect(onFadeOutEnd)
# Begin fadeout
hasFadedOut = false
TRANSITION.fade(TransitionSingleton.FadeType.FADE_OUT)
TRANSITION.fadeOutEnd.connect(onFadeOutEnd)
func onFadeOutEnd() -> void:
# Fade out has occurred, are we still waiting for the map to load?
TRANSITION.fadeOutEnd.disconnect(onFadeOutEnd)
hasFadedOut = true
# Fade out has occurred, are we still waiting for the map to load?
TRANSITION.fadeOutEnd.disconnect(onFadeOutEnd)
hasFadedOut = true
# Make sure we aren't still waiting for the map to load.
if !newMapLoaded:
return
newMapReady()
# Make sure we aren't still waiting for the map to load.
if !newMapLoaded:
return
newMapReady()
func newMapReady():
if !hasFadedOut:
return
if !hasFadedOut:
return
# Instantiate the new map
var mapResource = ResourceLoader.load_threaded_get(newMapPath)
if mapResource == null:
push_error("Failed to load map resource: " + newMapPath)
return
# Stop tracking new map name
newMapPath = ""
# Instantiate the new map
var mapResource = ResourceLoader.load_threaded_get(newMapPath)
if mapResource == null:
push_error("Failed to load map resource: " + newMapPath)
return
# Stop tracking new map name
newMapPath = ""
# Emit event
mapChanged.emit(mapResource, playerDestinationNodeName)
# Emit event
mapChanged.emit(mapResource, playerDestinationNodeName)
# Begin Fade In
TRANSITION.fade(TransitionSingleton.FadeType.FADE_IN)
TRANSITION.fadeInEnd.connect(onFadeInEnd)
# Begin Fade In
TRANSITION.fade(TransitionSingleton.FadeType.FADE_IN)
TRANSITION.fadeInEnd.connect(onFadeInEnd)
func onFadeInEnd() -> void:
TRANSITION.fadeInEnd.disconnect(onFadeInEnd)
TRANSITION.fadeInEnd.disconnect(onFadeInEnd)

View File

@@ -3,28 +3,28 @@ class_name PauseSingleton extends Node
var cutscenePaused:bool = false
func cutscenePause() -> void:
cutscenePaused = true
cutscenePaused = true
func cutsceneResume() -> void:
cutscenePaused = false
cutscenePaused = false
func isMovementPaused() -> bool:
if cutscenePaused:
return true
if cutscenePaused:
return true
if !UI.TEXTBOX.isClosed:
return true
if !UI.TEXTBOX.isClosed:
return true
if UI.PAUSE.isOpen():
return true
if UI.PAUSE.isOpen():
return true
if OVERWORLD.isMapChanging():
return true
return false
if OVERWORLD.isMapChanging():
return true
return false
func menuPause() -> void:
if UI.PAUSE.isOpen():
UI.PAUSE.close()
else:
UI.PAUSE.open()
if UI.PAUSE.isOpen():
UI.PAUSE.close()
else:
UI.PAUSE.open()

View File

@@ -1,34 +1,34 @@
class_name ClosableMenu extends Control
@export var isOpen: bool:
set(newValue):
isOpen = newValue
visible = newValue
if newValue:
opened.emit()
else:
closed.emit()
get():
return isOpen
set(newValue):
isOpen = newValue
visible = newValue
if newValue:
opened.emit()
else:
closed.emit()
get():
return isOpen
signal closed
signal opened
func _enter_tree() -> void:
visible = isOpen
visible = isOpen
func _exit_tree() -> void:
visible = false
visible = false
func _ready() -> void:
visible = isOpen
print("ClosableMenu is ready, isOpen: ", isOpen)
visible = isOpen
print("ClosableMenu is ready, isOpen: ", isOpen)
func close() -> void:
isOpen = false
isOpen = false
func open() -> void:
isOpen = true
isOpen = true
func toggle() -> void:
isOpen = !isOpen
isOpen = !isOpen

View File

@@ -12,62 +12,62 @@ var currentViewScrolled = true;
var isSpeedupDown = false;
var isClosed:bool = false:
get():
return !self.visible;
set(value):
self.visible = !value;
get():
return !self.visible;
set(value):
self.visible = !value;
signal textboxClosing
func _ready() -> void:
label = $MarginContainer/Label
isClosed = true
label = $MarginContainer/Label
isClosed = true
func _process(delta: float) -> void:
if label.getFinalText() == "":
isClosed = true;
return;
if label.visible_characters >= label.getCharactersDisplayedCount():
if (label.maxLines + label.startLine) < label.getTotalLineCount():
# Not on last page.
if Input.is_action_just_pressed("interact"):
label.startLine += label.maxLines;
label.visible_characters = 0;
currentViewScrolled = false;
return
if label.getFinalText() == "":
isClosed = true;
return;
if label.visible_characters >= label.getCharactersDisplayedCount():
if (label.maxLines + label.startLine) < label.getTotalLineCount():
# Not on last page.
if Input.is_action_just_pressed("interact"):
label.startLine += label.maxLines;
label.visible_characters = 0;
currentViewScrolled = false;
return
currentViewScrolled = true;
else:
# On last page
if Input.is_action_just_released("interact"):
textboxClosing.emit();
isClosed = true;
currentViewScrolled = true
return;
currentViewScrolled = true;
else:
# On last page
if Input.is_action_just_released("interact"):
textboxClosing.emit();
isClosed = true;
currentViewScrolled = true
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;
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;
revealTimer += delta;
if isSpeedupDown:
revealTimer += delta;
if revealTimer > VN_REVEAL_TIME:
revealTimer = 0;
label.visible_characters += 1;
if revealTimer > VN_REVEAL_TIME:
revealTimer = 0;
label.visible_characters += 1;
func setText(text:String) -> void:
isClosed = false;
revealTimer = 0;
currentViewScrolled = false;
label.visible_characters = 0;
label.startLine = 0;
label.text = ""
await get_tree().process_frame# Absolutely needed to make the text wrap
label.text = text;
label.visible_characters = 0;
isClosed = false;
revealTimer = 0;
currentViewScrolled = false;
label.visible_characters = 0;
label.startLine = 0;
label.text = ""
await get_tree().process_frame# Absolutely needed to make the text wrap
label.text = text;
label.visible_characters = 0;

View File

@@ -57,15 +57,7 @@ Line 10"
_finalText = "Hello, I'm an NPC!
This is the second line here, I am purposefully adding a tonne of words so that it is forced to go across multiple lines and you can see how the word wrapping works, not only using Godot's built in word wrapping but with my advanced visibile characters smart wrapping. Now I am doing a multiline thing
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10"
Line 2"
_newLineIndexes = Array[int]([0])
_lines = PackedStringArray("Hello, I\'m an NPC!", "This is the second line here, I am purposefully adding a tonne of words so that it is forced to go across multiple lines and you can see how the word wrapping works, not only using Godot\'s built in word wrapping but with my advanced visibile characters smart wrapping. Now I am doing a multiline thing", "Line 1", "Line 2", "Line 3", "Line 4", "Line 5", "Line 6", "Line 7", "Line 8", "Line 9", "Line 10")
maxLines = 4

View File

@@ -9,133 +9,133 @@ class_name AdvancedRichText extends RichTextLabel
# Hides the original RichTextLabel text property
func _set(property: StringName, value) -> bool:
if property == "text":
userText = value
_recalcText()
return true
elif property == "richtextlabel_text":
text = value
return true
return false
if property == "text":
userText = value
_recalcText()
return true
elif property == "richtextlabel_text":
text = value
return true
return false
func _get(property: StringName):
if property == "text":
return userText
elif property == "richtextlabel_text":
return text
return null
if property == "text":
return userText
elif property == "richtextlabel_text":
return text
return null
@export var translate:bool = true:
set(value):
translate = value
_recalcText()
get():
return translate
set(value):
translate = value
_recalcText()
get():
return translate
@export var smartWrap:bool = true:
set(value):
smartWrap = value
_recalcText()
get():
return smartWrap
set(value):
smartWrap = value
_recalcText()
get():
return smartWrap
@export var maxLines:int = -1:
set(value):
maxLines = value
_recalcText()
get():
return maxLines
set(value):
maxLines = value
_recalcText()
get():
return maxLines
@export var startLine:int = 0:
set(value):
startLine = value
_recalcText()
get():
return startLine
set(value):
startLine = value
_recalcText()
get():
return startLine
# Returns count of characters that can be displayed, assuming visible_chars = -1
func getCharactersDisplayedCount() -> int:
# Count characters
var count = 0
var lineCount = min(startLine + maxLines, _lines.size()) - startLine
for i in range(startLine, startLine + lineCount):
count += _lines[i].length()
if lineCount > 1:
count += lineCount - 1 # Add newlines
return count
# Count characters
var count = 0
var lineCount = min(startLine + maxLines, _lines.size()) - startLine
for i in range(startLine, startLine + lineCount):
count += _lines[i].length()
if lineCount > 1:
count += lineCount - 1 # Add newlines
return count
func getFinalText() -> String:
return _finalText
return _finalText
func getTotalLineCount() -> int:
return _lines.size()
return _lines.size()
func _enter_tree() -> void:
self.threaded = false;
self.threaded = false;
func _recalcText() -> void:
_lines.clear()
_lines.clear()
if userText.is_empty():
self.richtextlabel_text = ""
return
if userText.is_empty():
self.richtextlabel_text = ""
return
# Translate if needed
var textTranslated = userText
if self.translate:
textTranslated = tr(textTranslated)
# Translate if needed
var textTranslated = userText
if self.translate:
textTranslated = tr(textTranslated)
# Replace input bb tags.
var regex = RegEx.new()
regex.compile(r"\[input action=(.*?)\](.*?)\[/input\]")
var inputIconText = textTranslated
for match in regex.search_all(textTranslated):
var action = match.get_string(1).to_lower()
var height:int = get_theme_font_size("normal_font_size")
var img_tag = "[img height=%d valign=center,center]res://ui/input/%s.tres[/img]" % [ height, action ]
inputIconText = inputIconText.replace(match.get_string(0), img_tag)
# Replace input bb tags.
var regex = RegEx.new()
regex.compile(r"\[input action=(.*?)\](.*?)\[/input\]")
var inputIconText = textTranslated
for match in regex.search_all(textTranslated):
var action = match.get_string(1).to_lower()
var height:int = get_theme_font_size("normal_font_size")
var img_tag = "[img height=%d valign=center,center]res://ui/input/%s.tres[/img]" % [ height, action ]
inputIconText = inputIconText.replace(match.get_string(0), img_tag)
# Perform smart wrapping
var wrappedText = inputIconText
if smartWrap:
var unwrappedText = wrappedText.strip_edges()
# Perform smart wrapping
var wrappedText = inputIconText
if smartWrap:
var unwrappedText = wrappedText.strip_edges()
self.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART;
self.richtextlabel_text = unwrappedText
self.visible_characters = -1;
self.fit_content = false;
_newLineIndexes = [];
self.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART;
self.richtextlabel_text = unwrappedText
self.visible_characters = -1;
self.fit_content = false;
_newLineIndexes = [];
# Determine where the wrapped newlines are
var line = 0;
var wasNewLine = false;
for i in range(0, self.richtextlabel_text.length()):
var tLine = self.get_character_line(i);
if tLine == line:
wasNewLine = false
if self.richtextlabel_text[i] == "\n":
wasNewLine = true
continue;
if !wasNewLine:
_newLineIndexes.append(i);
line = tLine;
# Determine where the wrapped newlines are
var line = 0;
var wasNewLine = false;
for i in range(0, self.richtextlabel_text.length()):
var tLine = self.get_character_line(i);
if tLine == line:
wasNewLine = false
if self.richtextlabel_text[i] == "\n":
wasNewLine = true
continue;
if !wasNewLine:
_newLineIndexes.append(i);
line = tLine;
# Create fake pre-wrapped text.
wrappedText = "";
for i in range(0, self.richtextlabel_text.length()):
if _newLineIndexes.find(i) != -1 and i != 0:
wrappedText += "\n";
wrappedText += self.richtextlabel_text[i];
# Create fake pre-wrapped text.
wrappedText = "";
for i in range(0, self.richtextlabel_text.length()):
if _newLineIndexes.find(i) != -1 and i != 0:
wrappedText += "\n";
wrappedText += self.richtextlabel_text[i];
# Handle max and start line(s)
var maxText = wrappedText
if maxLines > 0:
_lines = maxText.split("\n", true);
var selectedLines = [];
for i in range(startLine, min(startLine + maxLines, _lines.size())):
selectedLines.append(_lines[i]);
maxText = "\n".join(selectedLines);
_finalText = maxText
self.richtextlabel_text = maxText
print("Updated text")
# Handle max and start line(s)
var maxText = wrappedText
if maxLines > 0:
_lines = maxText.split("\n", true);
var selectedLines = [];
for i in range(startLine, min(startLine + maxLines, _lines.size())):
selectedLines.append(_lines[i]);
maxText = "\n".join(selectedLines);
_finalText = maxText
self.richtextlabel_text = maxText
print("Updated text")

View File

@@ -6,13 +6,13 @@ class_name MainMenu extends Control
@export_file("*.tscn") var newGameScene:String
func _ready() -> void:
btnNewGame.pressed.connect(onNewGamePressed)
btnSettings.pressed.connect(onSettingsPressed)
btnNewGame.pressed.connect(onNewGamePressed)
btnSettings.pressed.connect(onSettingsPressed)
func onNewGamePressed() -> void:
SCENE.setScene(SceneSingleton.SceneType.OVERWORLD)
OVERWORLD.mapChange(newGameScene, "PlayerSpawnPoint")
SCENE.setScene(SceneSingleton.SceneType.OVERWORLD)
OVERWORLD.mapChange(newGameScene, "PlayerSpawnPoint")
func onSettingsPressed() -> void:
print("Settings button pressed")
settingsMenu.isOpen = true
print("Settings button pressed")
settingsMenu.isOpen = true

View File

@@ -1,18 +1,18 @@
class_name PauseMain extends VBoxContainer
func _ready() -> void:
visible = false
$HBoxContainer/ItemList.item_selected.connect(onItemSelected)
visible = false
$HBoxContainer/ItemList.item_selected.connect(onItemSelected)
func open():
visible = true
$HBoxContainer/ItemList.clear()
visible = true
$HBoxContainer/ItemList.clear()
func close():
visible = false
visible = false
func isOpen() -> bool:
return visible
return visible
func onItemSelected(index:int) -> void:
print("Selected item index: ", index)
print("Selected item index: ", index)

View File

@@ -4,16 +4,16 @@ class_name PauseMenu extends Control
@export var SETTINGS:PauseSettings
func _ready() -> void:
close()
close()
func isOpen() -> bool:
return visible
return visible
func open() -> void:
visible = true
MAIN.open()
visible = true
MAIN.open()
func close() -> void:
visible = false
MAIN.close()
SETTINGS.close()
visible = false
MAIN.close()
SETTINGS.close()

View File

@@ -1,10 +1,10 @@
class_name PauseSettings extends Control
func open() -> void:
visible = true
visible = true
func close() -> void:
visible = false
visible = false
func isOpen() -> bool:
return visible
return visible

View File

@@ -4,12 +4,12 @@ class_name SettingsMenu extends Control
@export var tabControls:Array[Control]
func _ready() -> void:
tabs.tab_changed.connect(onTabChanged)
onTabChanged(tabs.current_tab)
tabs.tab_changed.connect(onTabChanged)
onTabChanged(tabs.current_tab)
func onTabChanged(tabIndex:int) -> void:
for control in tabControls:
control.visible = false
if tabIndex >= 0 and tabIndex < tabControls.size():
tabControls[tabIndex].visible = true
for control in tabControls:
control.visible = false
if tabIndex >= 0 and tabIndex < tabControls.size():
tabControls[tabIndex].visible = true