Transition
This commit is contained in:
		@@ -20,6 +20,7 @@ config/icon="res://icon.svg"
 | 
			
		||||
PHYSICS="*res://scripts/singletons/GamePhysics.gd"
 | 
			
		||||
UI="*res://scenes/singletons/UI.tscn"
 | 
			
		||||
PAUSE="*res://scripts/singletons/Pause.gd"
 | 
			
		||||
TRANSITION="*res://scenes/singletons/Transition.tscn"
 | 
			
		||||
 | 
			
		||||
[debug]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,10 +38,11 @@ point_count = 2
 | 
			
		||||
[node name="Player" parent="." instance=ExtResource("2_rlkm5")]
 | 
			
		||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.06402, 1.54702, -2.35884)
 | 
			
		||||
 | 
			
		||||
[node name="NPC" parent="." node_paths=PackedStringArray("cutscene") instance=ExtResource("4_nb1wl")]
 | 
			
		||||
[node name="NPC" parent="." node_paths=PackedStringArray("interactCamera") instance=ExtResource("4_nb1wl")]
 | 
			
		||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4.20455, 1.94676, -3.51349)
 | 
			
		||||
interactType = 2
 | 
			
		||||
cutscene = NodePath("../Cutscenes/TestCutscene")
 | 
			
		||||
interactType = 1
 | 
			
		||||
interactTexts = Array[String](["test"])
 | 
			
		||||
interactCamera = NodePath("../TestChatCamera")
 | 
			
		||||
 | 
			
		||||
[node name="Camera3D" type="Camera3D" parent="." node_paths=PackedStringArray("targetFollow", "pathFollow", "pathMap")]
 | 
			
		||||
transform = Transform3D(0.996991, 0.0418507, -0.0652558, 0, 0.841762, 0.539849, 0.0775229, -0.538225, 0.839228, 1.25757, 8.21861, 8.01254)
 | 
			
		||||
@@ -52,6 +53,10 @@ pathFollow = NodePath("../PathCamera/PathFollow3D")
 | 
			
		||||
pathMap = NodePath("../PathWorld")
 | 
			
		||||
metadata/_custom_type_script = "uid://csb0i132lcu0w"
 | 
			
		||||
 | 
			
		||||
[node name="TestChatCamera" type="Camera3D" parent="."]
 | 
			
		||||
transform = Transform3D(0.854722, 0.231437, -0.464637, 0, 0.895106, 0.445854, 0.519087, -0.381081, 0.765066, -6.8472, 4.22457, 0.61366)
 | 
			
		||||
fov = 47.0
 | 
			
		||||
 | 
			
		||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
 | 
			
		||||
environment = SubResource("Environment_m5dm6")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,6 @@ size = Vector3(0.705444, 0.680542, 1.17688)
 | 
			
		||||
 | 
			
		||||
[node name="Player" type="CharacterBody3D"]
 | 
			
		||||
script = ExtResource("1_24gqh")
 | 
			
		||||
metadata/_custom_type_script = "uid://c0by5m1upv57h"
 | 
			
		||||
 | 
			
		||||
[node name="Scripts" type="Node" parent="."]
 | 
			
		||||
 | 
			
		||||
@@ -26,9 +25,10 @@ metadata/_custom_type_script = "uid://c0by5m1upv57h"
 | 
			
		||||
script = ExtResource("2_o7et6")
 | 
			
		||||
player = NodePath("../..")
 | 
			
		||||
 | 
			
		||||
[node name="PlayerInteraction" type="Node" parent="Scripts" node_paths=PackedStringArray("interactableArea")]
 | 
			
		||||
[node name="PlayerInteraction" type="Node" parent="Scripts" node_paths=PackedStringArray("interactableArea", "player")]
 | 
			
		||||
script = ExtResource("3_24gqh")
 | 
			
		||||
interactableArea = NodePath("../../InteractableArea")
 | 
			
		||||
player = NodePath("../..")
 | 
			
		||||
 | 
			
		||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
 | 
			
		||||
shape = SubResource("CapsuleShape3D_2m2ha")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								scenes/singletons/Transition.tscn
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scenes/singletons/Transition.tscn
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
[gd_scene load_steps=2 format=3 uid="uid://i4ukelrrsujw"]
 | 
			
		||||
 | 
			
		||||
[ext_resource type="Script" uid="uid://iu3m73wtjlho" path="res://scripts/singletons/Transition.gd" id="1_isjic"]
 | 
			
		||||
 | 
			
		||||
[node name="Transition" type="Control"]
 | 
			
		||||
layout_mode = 3
 | 
			
		||||
anchors_preset = 15
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
grow_horizontal = 2
 | 
			
		||||
grow_vertical = 2
 | 
			
		||||
script = ExtResource("1_isjic")
 | 
			
		||||
 | 
			
		||||
[node name="Overlay" type="ColorRect" parent="."]
 | 
			
		||||
layout_mode = 1
 | 
			
		||||
anchors_preset = 15
 | 
			
		||||
anchor_right = 1.0
 | 
			
		||||
anchor_bottom = 1.0
 | 
			
		||||
grow_horizontal = 2
 | 
			
		||||
grow_vertical = 2
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
class_name InteractableArea extends Area3D
 | 
			
		||||
 | 
			
		||||
signal interactEvent
 | 
			
		||||
signal interactEvent(playerEntity:Player)
 | 
			
		||||
@@ -8,46 +8,146 @@ enum InteractType {
 | 
			
		||||
 | 
			
		||||
# Movement speed in units per second
 | 
			
		||||
@export var gravity: float = 24.8
 | 
			
		||||
 | 
			
		||||
@export var interactType:InteractType = InteractType.NONE
 | 
			
		||||
@export_multiline var interactTexts:Array[String] = []
 | 
			
		||||
@export var npcLookAtPlayer:bool = true
 | 
			
		||||
@export var playerLookAtNPC:bool = true
 | 
			
		||||
@export var interactCamera:Camera3D = null
 | 
			
		||||
@export var cutscene:Cutscene = null
 | 
			
		||||
 | 
			
		||||
var nextTextIndex:int = 0
 | 
			
		||||
var previousCamera:Camera3D = null
 | 
			
		||||
var playerEnt:Player
 | 
			
		||||
var conversationEnding:bool = false
 | 
			
		||||
 | 
			
		||||
func lookAtPlayer() -> void:
 | 
			
		||||
	if !playerEnt:
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	# Get player position and NPC position
 | 
			
		||||
	var playerPos = playerEnt.global_transform.origin
 | 
			
		||||
	var npcPos = global_transform.origin
 | 
			
		||||
 | 
			
		||||
	# Rotate the NPC to look at the player
 | 
			
		||||
	if npcLookAtPlayer:
 | 
			
		||||
		var npcDirection = (playerPos - npcPos).normalized()
 | 
			
		||||
		var npcRotation = Vector3(0, atan2(npcDirection.x, npcDirection.z), 0)
 | 
			
		||||
		global_transform.basis = Basis.from_euler(npcRotation)
 | 
			
		||||
 | 
			
		||||
	# Rotate the player to look at the NPC
 | 
			
		||||
	if playerLookAtNPC:
 | 
			
		||||
		var playerDirection = (npcPos - playerPos).normalized()
 | 
			
		||||
		var playerRotation = Vector3(0, atan2(playerDirection.x, playerDirection.z), 0)
 | 
			
		||||
		playerEnt.global_transform.basis = Basis.from_euler(playerRotation)
 | 
			
		||||
 | 
			
		||||
func showTexts():
 | 
			
		||||
	TRANSITION.fadeOutStart.disconnect(showTexts)
 | 
			
		||||
 | 
			
		||||
	# Any texts?
 | 
			
		||||
	if interactTexts.size() == 0:
 | 
			
		||||
		endTexts()
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	# First text.
 | 
			
		||||
	UI.TEXTBOX.setText(interactTexts[nextTextIndex])
 | 
			
		||||
	UI.TEXTBOX.textboxClosing.connect(onTextboxClosing)
 | 
			
		||||
 | 
			
		||||
func endTexts():
 | 
			
		||||
	UI.TEXTBOX.textboxClosing.disconnect(onTextboxClosing)
 | 
			
		||||
	conversationEnding = true
 | 
			
		||||
 | 
			
		||||
	# Do we fade out the camera?
 | 
			
		||||
	if interactCamera:
 | 
			
		||||
		TRANSITION.fade(TRANSITION.FadeType.FADE_OUT)
 | 
			
		||||
		TRANSITION.fadeOutEnd.connect(onFadeOutEnd)
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	# Reset Camera?
 | 
			
		||||
	if previousCamera:
 | 
			
		||||
		previousCamera.current = true
 | 
			
		||||
		previousCamera = null
 | 
			
		||||
 | 
			
		||||
func _enter_tree() -> void:
 | 
			
		||||
	$InteractableArea.interactEvent.connect(_on_interact)
 | 
			
		||||
	$InteractableArea.interactEvent.connect(onInteract)
 | 
			
		||||
 | 
			
		||||
func _exit_tree() -> void:
 | 
			
		||||
	$InteractableArea.interactEvent.disconnect(_on_interact)
 | 
			
		||||
	$InteractableArea.interactEvent.disconnect(onInteract)
 | 
			
		||||
	UI.TEXTBOX.textboxClosing.disconnect(onTextboxClosing)
 | 
			
		||||
	TRANSITION.fadeOutEnd.disconnect(onFadeOutEnd)
 | 
			
		||||
	TRANSITION.fadeInEnd.disconnect(onFadeInEnd)
 | 
			
		||||
 | 
			
		||||
func _physics_process(delta):
 | 
			
		||||
	# Apply gravity if not on floor
 | 
			
		||||
	if !is_on_floor():
 | 
			
		||||
		velocity += PHYSICS.GRAVITY * delta
 | 
			
		||||
 | 
			
		||||
	move_and_slide()
 | 
			
		||||
 | 
			
		||||
func _on_interact() -> void:
 | 
			
		||||
func onInteract(playerEntity:Player) -> void:
 | 
			
		||||
	# Reset state
 | 
			
		||||
	previousCamera = null
 | 
			
		||||
	nextTextIndex = 0
 | 
			
		||||
	playerEnt = playerEntity
 | 
			
		||||
	conversationEnding = false
 | 
			
		||||
 | 
			
		||||
	match interactType:
 | 
			
		||||
		InteractType.TEXTBOX:
 | 
			
		||||
			if interactTexts.size() == 0:
 | 
			
		||||
			PAUSE.cutscenePause()
 | 
			
		||||
 | 
			
		||||
			# If a camera is set, switch to it, otherwise chat immediately.
 | 
			
		||||
			if !interactCamera:
 | 
			
		||||
				showTexts()
 | 
			
		||||
				return
 | 
			
		||||
			UI.TEXTBOX.setText(interactTexts[nextTextIndex])
 | 
			
		||||
			UI.TEXTBOX.textboxClosing.connect(onTextboxClosing)
 | 
			
		||||
			return
 | 
			
		||||
			
 | 
			
		||||
			# Fade out.
 | 
			
		||||
			TRANSITION.fade(TRANSITION.FadeType.FADE_OUT)
 | 
			
		||||
			TRANSITION.fadeOutEnd.connect(onFadeOutEnd)
 | 
			
		||||
 | 
			
		||||
		InteractType.CUTSCENE:
 | 
			
		||||
			if cutscene:
 | 
			
		||||
				cutscene.start()
 | 
			
		||||
			return
 | 
			
		||||
			if !cutscene:
 | 
			
		||||
				return
 | 
			
		||||
			cutscene.start()
 | 
			
		||||
		
 | 
			
		||||
		_:
 | 
			
		||||
			return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func onTextboxClosing() -> void:
 | 
			
		||||
	nextTextIndex += 1
 | 
			
		||||
 | 
			
		||||
	# More text?
 | 
			
		||||
	if nextTextIndex < interactTexts.size():
 | 
			
		||||
		UI.TEXTBOX.setText(interactTexts[nextTextIndex])
 | 
			
		||||
	else:
 | 
			
		||||
		UI.TEXTBOX.textboxClosing.disconnect(onTextboxClosing)
 | 
			
		||||
		endTexts()
 | 
			
		||||
 | 
			
		||||
func onFadeOutEnd() -> void:
 | 
			
		||||
	# Begin fade back in.
 | 
			
		||||
	TRANSITION.fadeOutEnd.disconnect(onFadeOutEnd)
 | 
			
		||||
	TRANSITION.fade(TRANSITION.FadeType.FADE_IN)
 | 
			
		||||
	TRANSITION.fadeInEnd.connect(onFadeInEnd)
 | 
			
		||||
 | 
			
		||||
	# Is the conversation ending?
 | 
			
		||||
	if conversationEnding:
 | 
			
		||||
		# Reset camera.
 | 
			
		||||
		if previousCamera:
 | 
			
		||||
			previousCamera.current = true
 | 
			
		||||
			previousCamera = null
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	# No! We are starting the conversation, make the ents look at each other
 | 
			
		||||
	lookAtPlayer()
 | 
			
		||||
 | 
			
		||||
	# Change camera
 | 
			
		||||
	previousCamera = get_viewport().get_camera_3d()
 | 
			
		||||
	interactCamera.current = true
 | 
			
		||||
 | 
			
		||||
func onFadeInEnd() -> void:
 | 
			
		||||
	TRANSITION.fadeInEnd.disconnect(onFadeInEnd)
 | 
			
		||||
 | 
			
		||||
	# Did the conversation end?
 | 
			
		||||
	if conversationEnding:
 | 
			
		||||
		PAUSE.cutsceneResume()
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	# Show texts after fade in.
 | 
			
		||||
	showTexts()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										0
									
								
								scripts/entities/Player.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								scripts/entities/Player.gd
									
									
									
									
									
										Normal file
									
								
							@@ -1,6 +1,7 @@
 | 
			
		||||
class_name PlayerInteraction extends Node
 | 
			
		||||
 | 
			
		||||
@export var interactableArea:Area3D
 | 
			
		||||
@export var player:CharacterBody3D
 | 
			
		||||
 | 
			
		||||
func canInteract() -> bool:
 | 
			
		||||
	if PAUSE.isMovementPaused():
 | 
			
		||||
@@ -26,4 +27,4 @@ func _process(delta: float) -> void:
 | 
			
		||||
	if !interactable:
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	interactable.interactEvent.emit()
 | 
			
		||||
	interactable.interactEvent.emit(player)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,6 @@ const SPEED = 8.0
 | 
			
		||||
 | 
			
		||||
@export var player:CharacterBody3D
 | 
			
		||||
 | 
			
		||||
func _ready() -> void:
 | 
			
		||||
	player = get_parent().get_parent()
 | 
			
		||||
	
 | 
			
		||||
func canMove() -> bool:
 | 
			
		||||
	if PAUSE.isMovementPaused():
 | 
			
		||||
		return false
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,16 @@
 | 
			
		||||
class_name PauseSingleton extends Node
 | 
			
		||||
 | 
			
		||||
var cutscenePaused:bool = false
 | 
			
		||||
 | 
			
		||||
func cutscenePause() -> void:
 | 
			
		||||
	cutscenePaused = true
 | 
			
		||||
 | 
			
		||||
func cutsceneResume() -> void:
 | 
			
		||||
	cutscenePaused = false
 | 
			
		||||
 | 
			
		||||
func isMovementPaused() -> bool:
 | 
			
		||||
	if cutscenePaused:
 | 
			
		||||
		return true
 | 
			
		||||
	if !UI.TEXTBOX.isClosed:
 | 
			
		||||
		return true
 | 
			
		||||
	return false
 | 
			
		||||
							
								
								
									
										79
									
								
								scripts/singletons/Transition.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								scripts/singletons/Transition.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
class_name TransitionSingleton extends Control
 | 
			
		||||
 | 
			
		||||
enum FadeType {
 | 
			
		||||
	NONE,
 | 
			
		||||
	FADE_IN,
 | 
			
		||||
	FADE_OUT
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
signal fadeOutStart
 | 
			
		||||
signal fadeOutEnd
 | 
			
		||||
signal fadeInStart
 | 
			
		||||
signal fadeInEnd
 | 
			
		||||
signal fadeUpdate(t:float)
 | 
			
		||||
 | 
			
		||||
var fadeType:FadeType = FadeType.NONE
 | 
			
		||||
var fadeDuration:float = 0.4
 | 
			
		||||
var fadeTime:float = 0.0
 | 
			
		||||
 | 
			
		||||
func _enter_tree() -> void:
 | 
			
		||||
	$Overlay.visible = false
 | 
			
		||||
 | 
			
		||||
func _process(delta: float) -> void:
 | 
			
		||||
	if fadeType == FadeType.NONE:
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	fadeTime += delta
 | 
			
		||||
	var t:float = fadeTime / fadeDuration
 | 
			
		||||
 | 
			
		||||
	# Get destination alpha type.
 | 
			
		||||
	var destAlpha:float = 0.0
 | 
			
		||||
	var srcAlpha:float
 | 
			
		||||
	if fadeType == FadeType.FADE_IN:
 | 
			
		||||
		srcAlpha = 1.0
 | 
			
		||||
		destAlpha = 0.0
 | 
			
		||||
	elif fadeType == FadeType.FADE_OUT:
 | 
			
		||||
		srcAlpha = 0.0
 | 
			
		||||
		destAlpha = 1.0
 | 
			
		||||
 | 
			
		||||
	# End?
 | 
			
		||||
	if t >= 1.0:
 | 
			
		||||
		fadeUpdate.emit(1.0)
 | 
			
		||||
		var cFade = fadeType
 | 
			
		||||
		print("Transition: Fade complete")
 | 
			
		||||
		fadeType = FadeType.NONE
 | 
			
		||||
 | 
			
		||||
		if cFade == FadeType.FADE_OUT:
 | 
			
		||||
			$Overlay.visible = true
 | 
			
		||||
			fadeOutEnd.emit()
 | 
			
		||||
		elif cFade == FadeType.FADE_IN:
 | 
			
		||||
			$Overlay.visible = false
 | 
			
		||||
			fadeInEnd.emit()
 | 
			
		||||
		
 | 
			
		||||
		$Overlay.color.a = destAlpha
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	# TODO: Use curves
 | 
			
		||||
	$Overlay.color.a = srcAlpha + (destAlpha - srcAlpha) * t
 | 
			
		||||
	fadeUpdate.emit(t)
 | 
			
		||||
	pass
 | 
			
		||||
 | 
			
		||||
func fade(
 | 
			
		||||
	fade:FadeType = FadeType.FADE_IN,
 | 
			
		||||
	duration:float = 0.4,
 | 
			
		||||
	color:Color = Color(0, 0, 0, 1),
 | 
			
		||||
):
 | 
			
		||||
	$Overlay.visible = false
 | 
			
		||||
	$Overlay.color = color
 | 
			
		||||
	fadeDuration = duration
 | 
			
		||||
	fadeTime = 0
 | 
			
		||||
	fadeType = fade
 | 
			
		||||
 | 
			
		||||
	if fade == FadeType.FADE_IN:
 | 
			
		||||
		fadeInStart.emit()
 | 
			
		||||
		$Overlay.color.a = 0
 | 
			
		||||
	elif fade == FadeType.FADE_OUT:
 | 
			
		||||
		fadeOutStart.emit()
 | 
			
		||||
		$Overlay.color.a = 1
 | 
			
		||||
 | 
			
		||||
	$Overlay.visible = true
 | 
			
		||||
							
								
								
									
										1
									
								
								scripts/singletons/Transition.gd.uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								scripts/singletons/Transition.gd.uid
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
uid://iu3m73wtjlho
 | 
			
		||||
		Reference in New Issue
	
	Block a user