mirror of
https://github.com/RPG-Research/bcirpg.git
synced 2024-04-16 14:23:01 +00:00
Made a toolset folder, and added the Dialogic plugin.
This commit is contained in:
@ -0,0 +1,7 @@
|
||||
Copyright © 2021 Alessandro Senese (ceceppa)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,318 @@
|
||||
class_name DialogicAnimaPropertiesHelper
|
||||
#
|
||||
# Different node types have different property names
|
||||
#
|
||||
# Example:
|
||||
# Control: position is "rect_position"
|
||||
# Node2D : position is "offset"
|
||||
#
|
||||
# So, this utility class helps the animations to figure out which
|
||||
# property to animate :)
|
||||
#
|
||||
enum PIVOT {
|
||||
CENTER,
|
||||
CENTER_BOTTOM,
|
||||
TOP_CENTER,
|
||||
TOP_LEFT,
|
||||
LEFT_BOTTOM,
|
||||
RIGHT_BOTTOM
|
||||
}
|
||||
|
||||
static func get_position(node: Node) -> Vector2:
|
||||
if node is Control:
|
||||
return node.rect_position
|
||||
if node is Node2D:
|
||||
return node.global_position
|
||||
|
||||
return node.global_transform.origin
|
||||
|
||||
static func get_size(node: Node) -> Vector2:
|
||||
if node is Control:
|
||||
return node.get_size()
|
||||
elif node is AnimatedSprite:
|
||||
var frames = (node as AnimatedSprite).frames
|
||||
var animation = (node as AnimatedSprite).animation
|
||||
# scale can be negative
|
||||
var scale = Vector2(abs(node.scale.x), abs(node.scale.y))
|
||||
return frames.get_frame(animation, 0).get_size() * scale
|
||||
elif node is Node2D and "texture" in node:
|
||||
# scale can be negative
|
||||
var scale = Vector2(abs(node.scale.x), abs(node.scale.y))
|
||||
return node.texture.get_size() * scale
|
||||
|
||||
return Vector2.ZERO
|
||||
|
||||
static func get_scale(node: Node) -> Vector2:
|
||||
if node is Control:
|
||||
return node.rect_scale
|
||||
return node.scale
|
||||
|
||||
static func get_rotation(node: Node):
|
||||
if node is Control:
|
||||
return node.rect_rotation
|
||||
elif node is Node2D:
|
||||
return node.rotation_degrees
|
||||
|
||||
return node.rotation
|
||||
|
||||
static func set_2D_pivot(node: Node, pivot: int) -> void:
|
||||
var size: Vector2 = get_size(node)
|
||||
|
||||
match pivot:
|
||||
PIVOT.TOP_CENTER:
|
||||
if node is Control:
|
||||
node.set_pivot_offset(Vector2(size.x / 2, 0))
|
||||
else:
|
||||
var position = node.global_position
|
||||
|
||||
node.offset = Vector2(0, size.y / 2)
|
||||
node.global_position = position - node.offset
|
||||
PIVOT.TOP_LEFT:
|
||||
if node is Control:
|
||||
node.set_pivot_offset(Vector2(0, 0))
|
||||
else:
|
||||
var position = node.global_position
|
||||
|
||||
node.offset = Vector2(size.x / 2, 0)
|
||||
node.global_position = position - node.offset
|
||||
PIVOT.CENTER:
|
||||
if node is Control:
|
||||
node.set_pivot_offset(size / 2)
|
||||
PIVOT.CENTER_BOTTOM:
|
||||
if node is Control:
|
||||
node.set_pivot_offset(Vector2(size.x / 2, size.y / 2))
|
||||
else:
|
||||
var position = node.global_position
|
||||
|
||||
node.offset = Vector2(0, -size.y / 2)
|
||||
node.global_position = position - node.offset
|
||||
PIVOT.LEFT_BOTTOM:
|
||||
if node is Control:
|
||||
node.set_pivot_offset(Vector2(0, size.y))
|
||||
else:
|
||||
var position = node.global_position
|
||||
|
||||
node.offset = Vector2(size.x / 2, size.y)
|
||||
node.global_position = position - node.offset
|
||||
PIVOT.RIGHT_BOTTOM:
|
||||
if node is Control:
|
||||
node.set_pivot_offset(Vector2(size.x, size.y / 2))
|
||||
else:
|
||||
var position = node.global_position
|
||||
|
||||
node.offset = Vector2(-size.x / 2, size.y / 2)
|
||||
node.global_position = position - node.offset
|
||||
_:
|
||||
printerr('Pivot point not handled yet')
|
||||
|
||||
static func get_property_initial_value(node: Node, property: String):
|
||||
property = property.to_lower()
|
||||
|
||||
match property:
|
||||
"x", "position:x":
|
||||
var position = get_position(node)
|
||||
|
||||
return position.x
|
||||
"y", "position:y":
|
||||
var position = get_position(node)
|
||||
|
||||
return position.y
|
||||
"z", "position:z":
|
||||
var position = get_position(node)
|
||||
|
||||
return position.z
|
||||
"position":
|
||||
return get_position(node)
|
||||
"rotation":
|
||||
return get_rotation(node)
|
||||
"rotation:x":
|
||||
return get_rotation(node).x
|
||||
"rotation:y":
|
||||
return get_rotation(node).y
|
||||
"rotation:z":
|
||||
return get_rotation(node).z
|
||||
"opacity":
|
||||
return node.modulate.a
|
||||
"skew:x":
|
||||
return node.get_global_transform().y.x
|
||||
"skew:y":
|
||||
return node.get_global_transform().x.y
|
||||
|
||||
var p = property.split(':')
|
||||
|
||||
var property_name: String = p[0]
|
||||
var rect_property_name: String = 'rect_' + property_name
|
||||
var node_property_name: String
|
||||
|
||||
var key = p[1] if p.size() > 1 else null
|
||||
|
||||
if node.get(property_name):
|
||||
node_property_name = property_name
|
||||
|
||||
if node.get(rect_property_name):
|
||||
node_property_name = rect_property_name
|
||||
|
||||
if p[0] == 'shader_param':
|
||||
var material: ShaderMaterial
|
||||
if node is MeshInstance:
|
||||
material = node.get_surface_material(0)
|
||||
else:
|
||||
material = node.material
|
||||
|
||||
return material.get_shader_param(p[1])
|
||||
|
||||
if node_property_name:
|
||||
if key:
|
||||
return node[node_property_name][key]
|
||||
|
||||
return node[node_property_name]
|
||||
|
||||
if property.find('__') == 0:
|
||||
return 0
|
||||
|
||||
return property_name
|
||||
|
||||
static func map_property_to_godot_property(node: Node, property: String) -> Dictionary:
|
||||
property = property.to_lower()
|
||||
|
||||
match property:
|
||||
"x", "position:x":
|
||||
if node is Control:
|
||||
return {
|
||||
property_name = "rect_position",
|
||||
key = "x",
|
||||
}
|
||||
|
||||
return {
|
||||
property_name = "global_transform",
|
||||
key = "origin",
|
||||
subkey = "x"
|
||||
}
|
||||
"y", "position:y":
|
||||
if node is Control:
|
||||
return {
|
||||
property_name = "rect_position",
|
||||
key = "y",
|
||||
}
|
||||
|
||||
return {
|
||||
property_name = "global_transform",
|
||||
key = "origin",
|
||||
subkey = "y"
|
||||
}
|
||||
"z", "position:z":
|
||||
if node is Control:
|
||||
printerr('position:z is not supported by Control nodes')
|
||||
|
||||
return {
|
||||
property_name = "global_transform",
|
||||
key = "origin",
|
||||
subkey = "z"
|
||||
}
|
||||
"position":
|
||||
if node is Control:
|
||||
return {
|
||||
property_name = "rect_position"
|
||||
}
|
||||
|
||||
return {
|
||||
property_name = "global_transform",
|
||||
key = "origin"
|
||||
}
|
||||
"opacity":
|
||||
return {
|
||||
property_name = "modulate",
|
||||
key = "a"
|
||||
}
|
||||
"rotation":
|
||||
var property_name = "rotation"
|
||||
|
||||
if node is Control:
|
||||
property_name = "rect_rotation"
|
||||
elif node is Node2D:
|
||||
property_name = "rotation_degrees"
|
||||
|
||||
return {
|
||||
property_name = property_name
|
||||
}
|
||||
"rotation:x":
|
||||
return {
|
||||
property_name = "rotation",
|
||||
key = "x"
|
||||
}
|
||||
"rotation:y":
|
||||
return {
|
||||
property_name = "rotation",
|
||||
key = "y"
|
||||
}
|
||||
"rotation:z":
|
||||
return {
|
||||
property_name = "rotation",
|
||||
key = "z"
|
||||
}
|
||||
"skew:x":
|
||||
return {
|
||||
property_name = "transform",
|
||||
key = "y",
|
||||
subkey = "x"
|
||||
}
|
||||
"skew:y":
|
||||
return {
|
||||
property_name = "transform",
|
||||
key = "x",
|
||||
subkey = "y"
|
||||
}
|
||||
|
||||
var p = property.split(':')
|
||||
|
||||
var property_name: String = p[0]
|
||||
var rect_property_name: String = 'rect_' + property_name
|
||||
var node_property_name: String
|
||||
|
||||
var key = p[1] if p.size() > 1 else null
|
||||
var subkey = p[2] if p.size() > 2 else null
|
||||
|
||||
if node.get(property_name):
|
||||
node_property_name = property_name
|
||||
|
||||
if node.get(rect_property_name):
|
||||
node_property_name = rect_property_name
|
||||
|
||||
if p[0] == 'shader_param':
|
||||
var material: ShaderMaterial
|
||||
if node is MeshInstance:
|
||||
material = node.get_surface_material(0)
|
||||
else:
|
||||
material = node.material
|
||||
|
||||
return {
|
||||
callback = funcref(material, 'set_shader_param'),
|
||||
param = p[1]
|
||||
}
|
||||
|
||||
if node_property_name:
|
||||
if key:
|
||||
return {
|
||||
property_name = node_property_name,
|
||||
key = key
|
||||
}
|
||||
|
||||
if subkey:
|
||||
return {
|
||||
property_name = node_property_name,
|
||||
key = key,
|
||||
subkey = subkey
|
||||
}
|
||||
|
||||
return {
|
||||
property_name = node_property_name
|
||||
}
|
||||
|
||||
if property.find('__') == 0:
|
||||
return {
|
||||
property_name = property
|
||||
}
|
||||
|
||||
return {
|
||||
property_name = property
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
extends Node
|
||||
class_name DialogicAnimaResources
|
||||
|
||||
const BASE_PATH := 'res://addons/dialogic/Nodes/Anima/animations/'
|
||||
|
||||
static func get_animation_script(animation_name: String):
|
||||
# for custom_animation in _custom_animations:
|
||||
# if custom_animation.name == animation_name:
|
||||
# return custom_animation.script
|
||||
|
||||
var resource_file = get_animation_script_with_path(animation_name)
|
||||
if resource_file:
|
||||
return load(resource_file).new()
|
||||
|
||||
printerr('No animation found with name: ', animation_name)
|
||||
|
||||
return null
|
||||
|
||||
|
||||
static func get_animation_script_with_path(animation_name: String) -> String:
|
||||
if not animation_name.ends_with('.gd'):
|
||||
animation_name += '.gd'
|
||||
|
||||
animation_name = from_camel_to_snack_case(animation_name)
|
||||
|
||||
for file_name in get_available_animations():
|
||||
if file_name is String and file_name.ends_with(animation_name):
|
||||
return file_name
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
static func get_available_animations() -> Array:
|
||||
var list = _get_animations_list()
|
||||
var filtered := []
|
||||
|
||||
for file in list:
|
||||
if file.find('.gd.') < 0:
|
||||
filtered.push_back(file.replace('.gdc', '.gd'))
|
||||
|
||||
return filtered #+ _custom_animations
|
||||
|
||||
|
||||
static func _get_animations_list() -> Array:
|
||||
var files = _get_scripts_in_dir(BASE_PATH)
|
||||
var filtered := []
|
||||
|
||||
files.sort()
|
||||
return files
|
||||
|
||||
static func _get_scripts_in_dir(path: String, files: Array = []) -> Array:
|
||||
var dir = Directory.new()
|
||||
if dir.open(path) != OK:
|
||||
return files
|
||||
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
|
||||
while file_name != "":
|
||||
if file_name != "." and file_name != "..":
|
||||
if dir.current_is_dir():
|
||||
_get_scripts_in_dir(path + file_name + '/', files)
|
||||
else:
|
||||
files.push_back(path + file_name)
|
||||
|
||||
file_name = dir.get_next()
|
||||
|
||||
return files
|
||||
|
||||
static func from_camel_to_snack_case(string:String) -> String:
|
||||
var result = PoolStringArray()
|
||||
var is_first_char = true
|
||||
|
||||
for character in string:
|
||||
if character == character.to_lower() or is_first_char:
|
||||
result.append(character.to_lower())
|
||||
else:
|
||||
result.append('_' + character.to_lower())
|
||||
|
||||
is_first_char = false
|
||||
|
||||
return result.join('').replace(' ', '_')
|
||||
|
@ -0,0 +1,571 @@
|
||||
extends Tween
|
||||
|
||||
var loop = 1
|
||||
|
||||
signal finished_animation
|
||||
|
||||
var _animation_data = []
|
||||
|
||||
enum PLAY_MODE {
|
||||
NORMAL,
|
||||
BACKWARDS
|
||||
}
|
||||
|
||||
# Needed to use interpolate_property
|
||||
var _fake_property: Dictionary = {}
|
||||
var _callbacks := {}
|
||||
|
||||
func _ready():
|
||||
connect("tween_started", self, '_on_tween_started')
|
||||
connect("tween_step", self, '_on_tween_step_with_easing')
|
||||
connect("tween_step", self, '_on_tween_step_with_easing_callback')
|
||||
connect("tween_step", self, '_on_tween_step_with_easing_funcref')
|
||||
connect("tween_step", self, '_on_tween_step_without_easing')
|
||||
connect("tween_completed", self, '_on_tween_completed')
|
||||
|
||||
|
||||
func play(node, animation_name, duration):
|
||||
var script = DialogicAnimaResources.get_animation_script(animation_name.strip_edges())
|
||||
|
||||
if not script:
|
||||
printerr('animation not found: %s' % animation_name)
|
||||
|
||||
return duration
|
||||
|
||||
var real_duration = script.generate_animation(self, {'node':node, 'duration':duration, 'wait_time':0})
|
||||
|
||||
if real_duration is float:
|
||||
duration = real_duration
|
||||
|
||||
var index := 0
|
||||
|
||||
for animation_data in _animation_data:
|
||||
var easing_points
|
||||
|
||||
if animation_data.has('easing'):
|
||||
if animation_data.easing is FuncRef:
|
||||
easing_points = animation_data.easing
|
||||
else:
|
||||
easing_points = get_easing_points(animation_data.easing)
|
||||
|
||||
if animation_data.has('easing_points'):
|
||||
easing_points = animation_data.easing_points
|
||||
|
||||
animation_data._easing_points = easing_points
|
||||
|
||||
animation_data._animation_callback = funcref(self, '_calculate_from_and_to')
|
||||
|
||||
if easing_points is Array:
|
||||
animation_data._use_step_callback = '_on_tween_step_with_easing'
|
||||
elif easing_points is String:
|
||||
animation_data._use_step_callback = '_on_tween_step_with_easing_callback'
|
||||
elif easing_points is FuncRef:
|
||||
animation_data._use_step_callback = '_on_tween_step_with_easing_funcref'
|
||||
else:
|
||||
animation_data._use_step_callback = '_on_tween_step_without_easing'
|
||||
|
||||
index += 1
|
||||
|
||||
var started := start()
|
||||
|
||||
if not started:
|
||||
printerr('something went wrong while trying to start the tween')
|
||||
|
||||
if is_connected("tween_all_completed", self, 'finished_once'): disconnect("tween_all_completed", self, 'finished_once')
|
||||
connect('tween_all_completed', self, 'finished_once', [node, animation_name, duration])
|
||||
|
||||
func finished_once(node, animation, duration):
|
||||
loop -= 1
|
||||
if loop > 0:
|
||||
play(node, animation, duration)
|
||||
else:
|
||||
emit_signal('finished_animation')
|
||||
|
||||
# Given an array of frames generates the animation data using relative end value
|
||||
#
|
||||
# frames = [{
|
||||
# percentage = the percentage of the animation
|
||||
# to = the relative end value
|
||||
# easing_points = the easing points for the bezier curver (optional)
|
||||
# }]
|
||||
#
|
||||
func add_relative_frames(data: Dictionary, property: String, frames: Array) -> float:
|
||||
return _add_frames(data, property, frames, true)
|
||||
|
||||
#
|
||||
# Given an array of frames generates the animation data using absolute end value
|
||||
#
|
||||
# frames = [{
|
||||
# percentage = the percentage of the animation
|
||||
# to = the relative end value
|
||||
# easing_points = the easing points for the bezier curver (optional)
|
||||
# }]
|
||||
#
|
||||
func add_frames(data: Dictionary, property: String, frames: Array) -> float:
|
||||
return _add_frames(data, property, frames)
|
||||
|
||||
|
||||
func _add_frames(data: Dictionary, property: String, frames: Array, relative: bool = false) -> float:
|
||||
var duration: float = data.duration if data.has('duration') else 0.0
|
||||
var _wait_time: float = data._wait_time if data.has('_wait_time') else 0.0
|
||||
var last_duration := 0.0
|
||||
|
||||
var keys_to_ignore = ['duration', '_wait_time']
|
||||
for frame in frames:
|
||||
var percentage = frame.percentage if frame.has('percentage') else 100.0
|
||||
percentage /= 100.0
|
||||
|
||||
var frame_duration = max(0.000001, duration * percentage)
|
||||
var diff = frame_duration - last_duration
|
||||
var is_first_frame = true
|
||||
var is_last_frame = percentage == 1
|
||||
|
||||
var animation_data = {
|
||||
property = property,
|
||||
relative = relative,
|
||||
duration = diff,
|
||||
_wait_time = _wait_time
|
||||
}
|
||||
|
||||
# We need to restore the animation just before the node is animated
|
||||
# but we also need to consider that a node can have multiple
|
||||
# properties animated, so we need to restore it only before the first
|
||||
# animation starts
|
||||
for animation in _animation_data:
|
||||
if animation.node == data.node:
|
||||
is_first_frame = false
|
||||
|
||||
if animation.has('_is_last_frame'):
|
||||
is_last_frame = false
|
||||
|
||||
if is_first_frame:
|
||||
animation_data._is_first_frame = true
|
||||
|
||||
if is_last_frame:
|
||||
animation_data._is_last_frame = true
|
||||
|
||||
for key in frame:
|
||||
if key != 'percentage':
|
||||
animation_data[key] = frame[key]
|
||||
|
||||
for key in data:
|
||||
if key == 'callback' and percentage < 1:
|
||||
animation_data.erase(key)
|
||||
elif keys_to_ignore.find(key) < 0:
|
||||
animation_data[key] = data[key]
|
||||
|
||||
add_animation_data(animation_data)
|
||||
|
||||
last_duration = frame_duration
|
||||
_wait_time += diff
|
||||
|
||||
return _wait_time
|
||||
|
||||
|
||||
func add_animation_data(animation_data: Dictionary, play_mode: int = PLAY_MODE.NORMAL) -> void:
|
||||
_animation_data.push_back(animation_data)
|
||||
|
||||
var index = str(_animation_data.size())
|
||||
var duration = animation_data.duration if animation_data.has('duration') else 1
|
||||
var property_key = 'p' + index
|
||||
|
||||
_fake_property[property_key] = 0.0
|
||||
|
||||
if animation_data.has('on_completed') and animation_data.has('_is_last_frame'):
|
||||
_callbacks[property_key] = animation_data.on_completed
|
||||
|
||||
var from := 0.0 if play_mode == PLAY_MODE.NORMAL else 1.0
|
||||
var to := 1.0 - from
|
||||
|
||||
interpolate_property(
|
||||
self,
|
||||
'_fake_property:' + property_key,
|
||||
from,
|
||||
to,
|
||||
duration,
|
||||
Tween.TRANS_LINEAR,
|
||||
Tween.EASE_IN_OUT,
|
||||
animation_data._wait_time
|
||||
)
|
||||
|
||||
|
||||
func _on_tween_step_with_easing(object: Object, key: NodePath, _time: float, elapsed: float):
|
||||
var index := _get_animation_data_index(key)
|
||||
|
||||
if _animation_data[index]._use_step_callback != '_on_tween_step_with_easing':
|
||||
return
|
||||
|
||||
var easing_points = _animation_data[index]._easing_points
|
||||
var p1 = easing_points[0]
|
||||
var p2 = easing_points[1]
|
||||
var p3 = easing_points[2]
|
||||
var p4 = easing_points[3]
|
||||
|
||||
var easing_elapsed = _cubic_bezier(Vector2.ZERO, Vector2(p1, p2), Vector2(p3, p4), Vector2(1, 1), elapsed)
|
||||
|
||||
_animation_data[index]._animation_callback.call_func(index, easing_elapsed)
|
||||
|
||||
func _on_tween_step_with_easing_callback(object: Object, key: NodePath, _time: float, elapsed: float):
|
||||
var index := _get_animation_data_index(key)
|
||||
|
||||
if _animation_data[index]._use_step_callback != '_on_tween_step_with_easing_callback':
|
||||
return
|
||||
|
||||
var easing_points_function = _animation_data[index]._easing_points
|
||||
var easing_callback = funcref(self, easing_points_function)
|
||||
var easing_elapsed = easing_callback.call_func(elapsed)
|
||||
|
||||
_animation_data[index]._animation_callback.call_func(index, easing_elapsed)
|
||||
|
||||
func _on_tween_step_with_easing_funcref(object: Object, key: NodePath, _time: float, elapsed: float):
|
||||
var index := _get_animation_data_index(key)
|
||||
|
||||
if _animation_data[index]._use_step_callback != '_on_tween_step_with_easing_funcref':
|
||||
return
|
||||
|
||||
var easing_callback = _animation_data[index]._easing_points
|
||||
var easing_elapsed = easing_callback.call_func(elapsed)
|
||||
|
||||
_animation_data[index]._animation_callback.call_func(index, easing_elapsed)
|
||||
|
||||
func _on_tween_step_without_easing(object: Object, key: NodePath, _time: float, elapsed: float):
|
||||
var index := _get_animation_data_index(key)
|
||||
|
||||
if _animation_data[index]._use_step_callback != '_on_tween_step_without_easing':
|
||||
return
|
||||
|
||||
_animation_data[index]._animation_callback.call_func(index, elapsed)
|
||||
|
||||
func _get_animation_data_index(key: NodePath) -> int:
|
||||
var s = str(key)
|
||||
|
||||
return int(s.replace('_fake_property:p', '')) - 1
|
||||
|
||||
func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float) -> float:
|
||||
var q0 = p0.linear_interpolate(p1, t)
|
||||
var q1 = p1.linear_interpolate(p2, t)
|
||||
var q2 = p2.linear_interpolate(p3, t)
|
||||
|
||||
var r0 = q0.linear_interpolate(q1, t)
|
||||
var r1 = q1.linear_interpolate(q2, t)
|
||||
|
||||
var s = r0.linear_interpolate(r1, t)
|
||||
|
||||
return s.y
|
||||
|
||||
func _calculate_from_and_to(index: int, value: float) -> void:
|
||||
var animation_data = _animation_data[index]
|
||||
var node = animation_data.node
|
||||
|
||||
var do_calculate = true
|
||||
|
||||
if animation_data.has('_recalculate_from_to') and not animation_data._recalculate_from_to and animation_data.has('_property_data'):
|
||||
do_calculate = false
|
||||
|
||||
if do_calculate:
|
||||
_do_calculate_from_to(node, animation_data)
|
||||
|
||||
if animation_data._property_data.has('subkey'):
|
||||
animation_data._animation_callback = funcref(self, '_on_animation_with_subkey')
|
||||
elif animation_data._property_data.has('key'):
|
||||
animation_data._animation_callback = funcref(self, '_on_animation_with_key')
|
||||
else:
|
||||
animation_data._animation_callback = funcref(self, '_on_animation_without_key')
|
||||
|
||||
_animation_data[index]._animation_callback.call_func(index, value)
|
||||
|
||||
func _do_calculate_from_to(node: Node, animation_data: Dictionary) -> void:
|
||||
var from
|
||||
var to
|
||||
var relative = animation_data.relative if animation_data.has('relative') else false
|
||||
var node_from = DialogicAnimaPropertiesHelper.get_property_initial_value(node, animation_data.property)
|
||||
|
||||
if animation_data.has('from'):
|
||||
from = _maybe_convert_from_deg_to_rad(node, animation_data, animation_data.from)
|
||||
from = _maybe_calculate_relative_value(relative, from, node_from)
|
||||
else:
|
||||
from = node_from
|
||||
animation_data.__from = from
|
||||
|
||||
if animation_data.has('to'):
|
||||
to = _maybe_convert_from_deg_to_rad(node, animation_data, animation_data.to)
|
||||
to = _maybe_calculate_relative_value(relative, to, from)
|
||||
else:
|
||||
to = from
|
||||
animation_data.__to = to
|
||||
|
||||
if animation_data.has('pivot'):
|
||||
if node is Spatial:
|
||||
printerr('3D Pivot not supported yet')
|
||||
else:
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(animation_data.node, animation_data.pivot)
|
||||
|
||||
animation_data._property_data = DialogicAnimaPropertiesHelper.map_property_to_godot_property(node, animation_data.property)
|
||||
|
||||
animation_data._property_data.diff = to - from
|
||||
animation_data._property_data.from = from
|
||||
|
||||
func _maybe_calculate_relative_value(relative, value, current_node_value):
|
||||
if not relative:
|
||||
return value
|
||||
|
||||
return value + current_node_value
|
||||
|
||||
func _maybe_convert_from_deg_to_rad(node: Node, animation_data: Dictionary, value):
|
||||
if not node is Spatial or animation_data.property.find('rotation') < 0:
|
||||
return value
|
||||
|
||||
if value is Vector3:
|
||||
return Vector3(deg2rad(value.x), deg2rad(value.y), deg2rad(value.z))
|
||||
|
||||
return deg2rad(value)
|
||||
|
||||
func _on_animation_with_key(index: int, elapsed: float) -> void:
|
||||
var animation_data = _animation_data[index]
|
||||
var property_data = _animation_data[index]._property_data
|
||||
var node = animation_data.node
|
||||
var value = property_data.from + (property_data.diff * elapsed)
|
||||
|
||||
node[property_data.property_name][property_data.key] = value
|
||||
|
||||
func _on_animation_with_subkey(index: int, elapsed: float) -> void:
|
||||
var animation_data = _animation_data[index]
|
||||
var property_data = _animation_data[index]._property_data
|
||||
var node = animation_data.node
|
||||
var value = property_data.from + (property_data.diff * elapsed)
|
||||
|
||||
node[property_data.property_name][property_data.key][property_data.subkey] = value
|
||||
|
||||
func _on_animation_without_key(index: int, elapsed: float) -> void:
|
||||
var animation_data = _animation_data[index]
|
||||
var property_data = _animation_data[index]._property_data
|
||||
var node = animation_data.node
|
||||
var value = property_data.from + (property_data.diff * elapsed)
|
||||
|
||||
if property_data.has('callback'):
|
||||
property_data.callback.call_func(property_data.param, value)
|
||||
|
||||
return
|
||||
|
||||
node[property_data.property_name] = value
|
||||
|
||||
#
|
||||
# We don't want the user to specify the from/to value as color
|
||||
# we animate opacity.
|
||||
# So this function converts the "from = #" -> Color(.., .., .., #)
|
||||
# same for the to value
|
||||
#
|
||||
func _maybe_adjust_modulate_value(animation_data: Dictionary, value):
|
||||
var property = animation_data.property
|
||||
var node = animation_data.node
|
||||
|
||||
if not property == 'opacity':
|
||||
return value
|
||||
|
||||
if value is int or value is float:
|
||||
var color = node.modulate
|
||||
|
||||
color.a = value
|
||||
|
||||
return color
|
||||
|
||||
return value
|
||||
|
||||
func _on_tween_completed(_ignore, property_name: String) -> void:
|
||||
var property_key = property_name.replace(':_fake_property:', '')
|
||||
|
||||
if _callbacks.has(property_key):
|
||||
var callback = _callbacks[property_key]
|
||||
|
||||
if not callback is Array or callback.size() == 1:
|
||||
callback[0].call_func()
|
||||
else:
|
||||
callback[0].call_funcv(callback[1])
|
||||
|
||||
func _on_tween_started(_ignore, key) -> void:
|
||||
var index := _get_animation_data_index(key)
|
||||
#var hide_strategy = _visibility_strategy
|
||||
var animation_data = _animation_data[index]
|
||||
|
||||
# if animation_data.has('hide_strategy'):
|
||||
# hide_strategy = animation_data.hide_strategy
|
||||
|
||||
var node = animation_data.node
|
||||
var should_restore_visibility := false
|
||||
var should_restore_modulate := false
|
||||
|
||||
# if hide_strategy == Anima.VISIBILITY.HIDDEN_ONLY:
|
||||
# should_restore_visibility = true
|
||||
# elif hide_strategy == Anima.VISIBILITY.HIDDEN_AND_TRANSPARENT:
|
||||
# should_restore_modulate = true
|
||||
# should_restore_visibility = true
|
||||
# elif hide_strategy == Anima.VISIBILITY.TRANSPARENT_ONLY:
|
||||
# should_restore_modulate = true
|
||||
|
||||
if should_restore_modulate:
|
||||
var old_modulate = node.get_meta('_old_modulate')
|
||||
|
||||
if old_modulate:
|
||||
node.modulate = old_modulate
|
||||
|
||||
if should_restore_visibility:
|
||||
node.show()
|
||||
|
||||
var should_trigger_on_started: bool = animation_data.has('_is_first_frame') and animation_data._is_first_frame and animation_data.has('on_started')
|
||||
if should_trigger_on_started:
|
||||
var fn: FuncRef
|
||||
var args: Array = []
|
||||
if animation_data.on_started is Array:
|
||||
fn = animation_data.on_started[0]
|
||||
args = animation_data.on_started.slice(1, -1)
|
||||
else:
|
||||
fn = animation_data.on_started
|
||||
|
||||
fn.call_funcv(args)
|
||||
|
||||
|
||||
####################################################################################################
|
||||
####################################################################################################
|
||||
## FROM ANIMA EASING
|
||||
####################################################################################################
|
||||
####################################################################################################
|
||||
|
||||
enum EASING {
|
||||
LINEAR,
|
||||
EASE,
|
||||
EASE_IN_OUT,
|
||||
EASE_IN,
|
||||
EASE_OUT,
|
||||
EASE_IN_SINE,
|
||||
EASE_OUT_SINE,
|
||||
EASE_IN_OUT_SINE,
|
||||
EASE_IN_QUAD,
|
||||
EASE_OUT_QUAD,
|
||||
EASE_IN_OUT_QUAD,
|
||||
EASE_IN_CUBIC,
|
||||
EASE_OUT_CUBIC,
|
||||
EASE_IN_OUT_CUBIC,
|
||||
EASE_IN_QUART,
|
||||
EASE_OUT_QUART,
|
||||
EASE_IN_OUT_QUART,
|
||||
EASE_IN_QUINT,
|
||||
EASE_OUT_QUINT,
|
||||
EASE_IN_OUT_QUINT,
|
||||
EASE_IN_EXPO,
|
||||
EASE_OUT_EXPO,
|
||||
EASE_IN_OUT_EXPO,
|
||||
EASE_IN_CIRC,
|
||||
EASE_OUT_CIRC,
|
||||
EASE_IN_OUT_CIRC,
|
||||
EASE_IN_BACK,
|
||||
EASE_OUT_BACK,
|
||||
EASE_IN_OUT_BACK,
|
||||
EASE_IN_ELASTIC,
|
||||
EASE_OUT_ELASTIC,
|
||||
EASE_IN_OUT_ELASTIC,
|
||||
EASE_IN_BOUNCE,
|
||||
EASE_OUT_BOUNCE,
|
||||
EASE_IN_OUT_BOUNCE,
|
||||
}
|
||||
|
||||
const _easing_mapping = {
|
||||
EASING.LINEAR: null,
|
||||
EASING.EASE: [0.25, 0.1, 0.25, 1],
|
||||
EASING.EASE_IN_OUT: [0.42, 0, 0.58, 1],
|
||||
EASING.EASE_IN: [0.42, 0, 1, 1],
|
||||
EASING.EASE_OUT: [0, 0, 0.58, 1],
|
||||
EASING.EASE_IN_SINE: [0, 0, 1, .5],
|
||||
EASING.EASE_OUT_SINE: [0.61, 1, 0.88, 1],
|
||||
EASING.EASE_IN_OUT_SINE: [0.37, 0, 0.63, 1],
|
||||
EASING.EASE_IN_QUAD: [0.11, 0, 0.5, 0],
|
||||
EASING.EASE_OUT_QUAD: [0.5, 1.0, 0.89, 1],
|
||||
EASING.EASE_IN_OUT_QUAD: [0.45, 0, 0.55, 1],
|
||||
EASING.EASE_IN_CUBIC: [0.32, 0, 0.67, 0],
|
||||
EASING.EASE_OUT_CUBIC: [0.33, 1, 0.68, 1],
|
||||
EASING.EASE_IN_OUT_CUBIC: [0.65, 0, 0.35, 1],
|
||||
EASING.EASE_IN_QUART: [0.5, 0, 0.75, 0],
|
||||
EASING.EASE_OUT_QUART: [0.25, 1, 0.5, 1],
|
||||
EASING.EASE_IN_OUT_QUART: [0.76, 0, 0.24, 1],
|
||||
EASING.EASE_IN_QUINT: [0.64, 0, 0.78, 0],
|
||||
EASING.EASE_OUT_QUINT: [0.22, 1, 0.36, 1],
|
||||
EASING.EASE_IN_OUT_QUINT: [0.83, 0, 0.17, 1],
|
||||
EASING.EASE_IN_EXPO: [0.7, 0, 0.84, 0],
|
||||
EASING.EASE_OUT_EXPO: [0.16, 1, 0.3, 1],
|
||||
EASING.EASE_IN_OUT_EXPO: [0.87, 0, 0.13, 1],
|
||||
EASING.EASE_IN_CIRC: [0.55, 0, 0.1, 0.45],
|
||||
EASING.EASE_OUT_CIRC: [0, 0.55, 0.45, 1],
|
||||
EASING.EASE_IN_OUT_CIRC: [0.85, 0, 0.15, 1],
|
||||
EASING.EASE_IN_BACK: [0.36, 0, 0.66, -0.56],
|
||||
EASING.EASE_OUT_BACK: [0.36, 1.56, 0.64, 1],
|
||||
EASING.EASE_IN_OUT_BACK: [0.68, -0.6, 0.32, 1.6],
|
||||
EASING.EASE_IN_ELASTIC: 'ease_in_elastic',
|
||||
EASING.EASE_OUT_ELASTIC: 'ease_out_elastic',
|
||||
EASING.EASE_IN_OUT_ELASTIC: 'ease_in_out_elastic',
|
||||
EASING.EASE_IN_BOUNCE: 'ease_in_bounce',
|
||||
EASING.EASE_OUT_BOUNCE: 'ease_out_bounce',
|
||||
EASING.EASE_IN_OUT_BOUNCE: 'ease_in_out_bounce'
|
||||
}
|
||||
|
||||
const _ELASTIC_C4: float = (2.0 * PI) / 3.0
|
||||
const _ELASTIC_C5: float = (2.0 * PI) / 4.5
|
||||
|
||||
static func get_easing_points(easing_name):
|
||||
if _easing_mapping.has(easing_name):
|
||||
return _easing_mapping[easing_name]
|
||||
|
||||
printerr('Easing not found: ' + str(easing_name))
|
||||
|
||||
return _easing_mapping[EASING.LINEAR]
|
||||
|
||||
static func ease_in_elastic(elapsed: float) -> float:
|
||||
if elapsed == 0:
|
||||
return 0.0
|
||||
elif elapsed == 1:
|
||||
return 1.0
|
||||
|
||||
return -pow(2, 10 * elapsed - 10) * sin((elapsed * 10 - 10.75) * _ELASTIC_C4)
|
||||
|
||||
static func ease_out_elastic(elapsed: float) -> float:
|
||||
if elapsed == 0:
|
||||
return 0.0
|
||||
elif elapsed == 1:
|
||||
return 1.0
|
||||
|
||||
return pow(2, -10 * elapsed) * sin((elapsed * 10 - 0.75) * _ELASTIC_C4) + 1
|
||||
|
||||
static func ease_in_out_elastic(elapsed: float) -> float:
|
||||
if elapsed == 0:
|
||||
return 0.0
|
||||
elif elapsed == 1:
|
||||
return 1.0
|
||||
elif elapsed < 0.5:
|
||||
return -(pow(2, 20 * elapsed - 10) * sin((20 * elapsed - 11.125) * _ELASTIC_C5)) / 2
|
||||
|
||||
return (pow(2, -20 * elapsed + 10) * sin((20 * elapsed - 11.125) * _ELASTIC_C5)) / 2 + 1
|
||||
|
||||
const n1 = 7.5625;
|
||||
const d1 = 2.75;
|
||||
|
||||
static func ease_in_bounce(elapsed: float) -> float:
|
||||
return 1 - ease_out_bounce(1.0 - elapsed)
|
||||
|
||||
static func ease_out_bounce(elapsed: float) -> float:
|
||||
if elapsed < 1 / d1:
|
||||
return n1 * elapsed * elapsed;
|
||||
elif elapsed < 2 / d1:
|
||||
elapsed -= 1.5 / d1
|
||||
|
||||
return n1 * elapsed * elapsed + 0.75;
|
||||
elif elapsed < 2.5 / d1:
|
||||
elapsed -= 2.25 / d1
|
||||
|
||||
return n1 * elapsed * elapsed + 0.9375;
|
||||
|
||||
elapsed -= 2.625 / d1
|
||||
return n1 * elapsed * elapsed + 0.984375;
|
||||
|
||||
static func ease_in_out_bounce(elapsed: float) -> float:
|
||||
if elapsed < 0.5:
|
||||
return (1 - ease_out_bounce(1 - 2 * elapsed)) / 2
|
||||
|
||||
return (1 + ease_out_bounce(2 * elapsed - 1)) / 2
|
@ -0,0 +1,29 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
#var delay: float = data._wait_time
|
||||
var bounce_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 40, to = -30, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
|
||||
{ percentage = 43, to = 0, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
|
||||
{ percentage = 53, to = +30 },
|
||||
{ percentage = 70, to = -15, easing_points = [0.755, 0.05, 0.855, 0.06] },
|
||||
{ percentage = 80, to = +15 },
|
||||
{ percentage = 90, to = -4 },
|
||||
{ percentage = 100, to = +4 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, to = 1 * scale.y },
|
||||
{ percentage = 20, to = 1 * scale.y },
|
||||
{ percentage = 40, to = 1.1 * scale.y, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
|
||||
{ percentage = 43, to = 1.1 * scale.y, easing_points = [0.7555, 0.5, 0.8555, 0.06] },
|
||||
{ percentage = 53, to = 1 * scale.y },
|
||||
{ percentage = 70, to = 1.05 * scale.y, easing_points = [0.755, 0.05, 0.855, 0.06] },
|
||||
{ percentage = 80, to = 0.95 * scale.y },
|
||||
{ percentage = 90, to = 1.02 * scale.y },
|
||||
{ percentage = 100, to = 1 * scale.y },
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "Y", bounce_frames)
|
||||
anima_tween.add_frames(data, "scale:y", scale_frames)
|
@ -0,0 +1,10 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 25, to = 0 },
|
||||
{ percentage = 50, to = 1 },
|
||||
{ percentage = 75, to = 0 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
anima_tween.add_frames(data, "opacity", frames)
|
@ -0,0 +1,27 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var start = DialogicAnimaPropertiesHelper.get_position(data.node)
|
||||
|
||||
var shake_frames = [
|
||||
{ percentage = 0, from = 0 },
|
||||
{ percentage = 6.5, to = -6 },
|
||||
{ percentage = 18.5, to = +5 },
|
||||
{ percentage = 31.5, to = -3 },
|
||||
{ percentage = 43.5, to = +2 },
|
||||
{ percentage = 50, to = 0 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
var rotate_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 6.5, to = -9 },
|
||||
{ percentage = 18.5, to = +7 },
|
||||
{ percentage = 31.5, to = -5 },
|
||||
{ percentage = 43.5, to = +3 },
|
||||
{ percentage = 50, to = 0 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", shake_frames)
|
||||
anima_tween.add_frames(data, "rotation", rotate_frames)
|
@ -0,0 +1,14 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 14, to = scale * Vector2(1.3, 1.3) },
|
||||
{ percentage = 28, to = scale * Vector2(1, 1) },
|
||||
{ percentage = 42, to = scale * Vector2(1.3, 1.3) },
|
||||
{ percentage = 70, to = scale * Vector2(1, 1) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_frames(data, "scale", frames)
|
@ -0,0 +1,32 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var start_x = data.node.get_global_transform().y.x
|
||||
var start_y = data.node.get_global_transform().x.y
|
||||
|
||||
var skew_x := []
|
||||
var skew_y := []
|
||||
|
||||
var values = [
|
||||
{ percentage = 0, add = 0 },
|
||||
{ percentage = 11.1, add = 0 },
|
||||
{ percentage = 22.2, add = - 0.3 },
|
||||
{ percentage = 33.3, add = + 0.265 },
|
||||
{ percentage = 44.4, add = - 0.1325 },
|
||||
{ percentage = 55.5, add = + 0.06625 },
|
||||
{ percentage = 66.6, add = - 0.033125 },
|
||||
{ percentage = 77.7, add = + 0.0165625 },
|
||||
{ percentage = 88.8, add = - 0.00828125},
|
||||
{ percentage = 100, add = 0 },
|
||||
]
|
||||
|
||||
for value in values:
|
||||
skew_x.push_back({ percentage = value.percentage, to = start_x + value.add })
|
||||
skew_y.push_back({ percentage = value.percentage, to = start_y + value.add })
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
# Skew works only with Node2D
|
||||
if not data.node is Node2D:
|
||||
return
|
||||
|
||||
anima_tween.add_frames(data, "skew:x", skew_x)
|
||||
anima_tween.add_frames(data, "skew:y", skew_y)
|
@ -0,0 +1,12 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 50, to = scale * Vector2(1.05, 1.05), easing = anima_tween.EASING.EASE_IN_OUT_SINE },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_frames(data, "scale", frames)
|
@ -0,0 +1,15 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 30, to = scale * Vector2(1.25, 0.75) },
|
||||
{ percentage = 40, to = scale * Vector2(0.75, 1.25) },
|
||||
{ percentage = 50, to = scale * Vector2(1.15, 0.85) },
|
||||
{ percentage = 65, to = scale * Vector2(0.95, 1.05) },
|
||||
{ percentage = 75, to = scale * Vector2(1.05, 0.95) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_frames(data, "scale", frames)
|
@ -0,0 +1,16 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 10, to = -10 },
|
||||
{ percentage = 20, to = +20 },
|
||||
{ percentage = 30, to = -20 },
|
||||
{ percentage = 40, to = +20 },
|
||||
{ percentage = 50, to = -20 },
|
||||
{ percentage = 60, to = +20 },
|
||||
{ percentage = 70, to = -20 },
|
||||
{ percentage = 80, to = +20 },
|
||||
{ percentage = 90, to = -20 },
|
||||
{ percentage = 100, to = +10 },
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", frames)
|
@ -0,0 +1,16 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 10, to = -10 },
|
||||
{ percentage = 20, to = +20 },
|
||||
{ percentage = 30, to = -20 },
|
||||
{ percentage = 40, to = +20 },
|
||||
{ percentage = 50, to = -20 },
|
||||
{ percentage = 60, to = +20 },
|
||||
{ percentage = 70, to = -20 },
|
||||
{ percentage = 80, to = +20 },
|
||||
{ percentage = 90, to = -20 },
|
||||
{ percentage = 100, to = +10 },
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", frames)
|
@ -0,0 +1,12 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var frames = [
|
||||
{ percentage = 0, from = 0 },
|
||||
{ percentage = 20, to = 15 },
|
||||
{ percentage = 40, to = -10 },
|
||||
{ percentage = 60, to = 5 },
|
||||
{ percentage = 80, to = -5 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.TOP_CENTER)
|
||||
anima_tween.add_frames(data, "rotation", frames)
|
@ -0,0 +1,22 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var rotate_frames = [
|
||||
{ percentage = 0, from = 0 },
|
||||
]
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = DialogicAnimaPropertiesHelper.get_scale(data.node) * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
for index in range(2, 9):
|
||||
var s = -1 if index % 2 == 0 else 1
|
||||
var percent = index * 10.0
|
||||
|
||||
rotate_frames.push_back({ percentage = percent, to = 3 * s })
|
||||
scale_frames.push_back({ percentage = percent, to = Vector2(1.1, 1.1) })
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
rotate_frames.push_back({percentage = 100, to = 0})
|
||||
scale_frames.push_back({percentage = 100, to = Vector2(1, 1)})
|
||||
|
||||
anima_tween.add_frames(data, "rotation", rotate_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
@ -0,0 +1,28 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var node = data.node
|
||||
var start_position = DialogicAnimaPropertiesHelper.get_position(node)
|
||||
var size = DialogicAnimaPropertiesHelper.get_size(node)
|
||||
|
||||
var x_frames = [
|
||||
{ percentage = 0, from = start_position.x },
|
||||
{ percentage = 15, to = start_position.x + size.x * -0.25 },
|
||||
{ percentage = 30, to = start_position.x + size.x * 0.2 },
|
||||
{ percentage = 45, to = start_position.x + size.x * -0.15 },
|
||||
{ percentage = 60, to = start_position.x + size.x * 0.1 },
|
||||
{ percentage = 75, to = start_position.x + size.x * -0.05 },
|
||||
{ percentage = 100, to = start_position.x },
|
||||
]
|
||||
|
||||
var rotation_frames = [
|
||||
{ percentage = 0, from = 0 },
|
||||
{ percentage = 15, to = -5 },
|
||||
{ percentage = 30, to = 3 },
|
||||
{ percentage = 45, to = -3 },
|
||||
{ percentage = 60, to = 2 },
|
||||
{ percentage = 75, to = -1 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.TOP_CENTER)
|
||||
anima_tween.add_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "rotation", rotation_frames)
|
@ -0,0 +1,5 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 0, to = 1, easing_points = [0.42, 0, 0.58, 1]},
|
||||
]
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,14 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 0, to = 1, easing_points = [0.42, 0, 0.58, 1] },
|
||||
]
|
||||
|
||||
var size = DialogicAnimaPropertiesHelper.get_size(data.node)
|
||||
|
||||
var position_frames = [
|
||||
{ percentage = 0, from = size.y/16, easing_points = [0.42, 0, 0.58, 1] },
|
||||
{ percentage = 100, to = -size.y/16, easing_points = [0.42, 0, 0.58, 1] },
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", position_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,14 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 0, to = 1 },
|
||||
]
|
||||
|
||||
var size = DialogicAnimaPropertiesHelper.get_size(data.node)
|
||||
|
||||
var position_frames = [
|
||||
{ percentage = 0, from = 2000 },
|
||||
{ percentage = 100, to = -2000 },
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", position_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,6 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 1, to = 0, easing_points = [0.42, 0, 0.58, 1]},
|
||||
]
|
||||
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,13 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 1, to = 0, easing_points = [0.42, 0, 0.58, 1] },
|
||||
]
|
||||
|
||||
var size = DialogicAnimaPropertiesHelper.get_size(data.node)
|
||||
|
||||
var position_frames = [
|
||||
{ from = 0, to = size.y/16, easing_points = [0.42, 0, 0.58, 1]},
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", position_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,12 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 1, to = 0 },
|
||||
]
|
||||
|
||||
var position_frames = [
|
||||
{ percentage = 0, from = 0},
|
||||
{ percentage = 100, to = 2000 },
|
||||
]
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", position_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var y_frames = [
|
||||
{ percentage = 0, to = -1200 },
|
||||
{ percentage = 80, to = +1200 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0.7 },
|
||||
{ percentage = 80, to = 0.7 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", y_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = -2000 },
|
||||
{ percentage = 80, to = +2000 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0.7 },
|
||||
{ percentage = 80, to = 0.7 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = 2000 },
|
||||
{ percentage = 80, to = -2000 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0.7 },
|
||||
{ percentage = 80, to = 0.7 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var y_frames = [
|
||||
{ percentage = 0, to = 1200 },
|
||||
{ percentage = 80, to = -1200 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0.7 },
|
||||
{ percentage = 80, to = 0.7 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", y_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var y_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 100, to = -700 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 0.7 },
|
||||
{ percentage = 100, to = 0.7 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", y_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 100, to = -2000 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 0.7 },
|
||||
{ percentage = 100, to = 0.7 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 100, to = 2000 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 0.7 },
|
||||
{ percentage = 100, to = 0.7 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var y_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 100, to = 700 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 20, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(0.7, 0.7) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 0.7 },
|
||||
{ percentage = 100, to = 0.7 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "y", y_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,22 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(1, 1) },
|
||||
{ percentage = 20, to = scale * Vector2(0.9, 0.9) },
|
||||
{ percentage = 50, to = scale * Vector2(1.1, 1.1) },
|
||||
{ percentage = 55, to = scale * Vector2(1.1, 1.1) },
|
||||
{ percentage = 100, to = scale * Vector2(0.3, 0.3) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 1 },
|
||||
{ percentage = 50, to = 1 },
|
||||
{ percentage = 55, to = 1 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,21 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(0.3, 0.3), easing_points = [0.215, 0.61, 0.355, 1] },
|
||||
{ percentage = 20, to = scale * Vector2(1, 1), easing_points = [0.215, 0.61, 0.355, 1] },
|
||||
{ percentage = 40, to = scale * Vector2(0.9, 0.9), easing_points = [0.215, 0.61, 0.355, 1] },
|
||||
{ percentage = 60, to = scale * Vector2(1.03, 1.03), easing_points = [0.215, 0.61, 0.355, 1] },
|
||||
{ percentage = 80, to = scale * Vector2(0.97, 0.97), easing_points = [0.215, 0.61, 0.355, 1] },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0 },
|
||||
{ percentage = 60, to = 1 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,5 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 1, to = 1 },
|
||||
]
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,5 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var opacity_frames = [
|
||||
{ from = 0, to = 0 },
|
||||
]
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,19 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = -2000 },
|
||||
{ percentage = 80, to = +2000 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0.7 },
|
||||
{ percentage = 80, to = 0.7 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
#anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,25 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = 2000 },
|
||||
{ percentage = 80, to = -2000 },
|
||||
{ percentage = 100, to = 0 },
|
||||
]
|
||||
|
||||
var scale = DialogicAnimaPropertiesHelper.get_scale(data.node)
|
||||
var scale_frames = [
|
||||
{ percentage = 0, from = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 80, to = scale * Vector2(0.7, 0.7) },
|
||||
{ percentage = 100, to = scale * Vector2(1, 1) },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 0.7 },
|
||||
{ percentage = 80, to = 0.7 },
|
||||
{ percentage = 100, to = 1 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "scale", scale_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,17 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 100, to = -2000 },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 0.7 },
|
||||
{ percentage = 100, to = 0.7 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,17 @@
|
||||
func generate_animation(anima_tween: Tween, data: Dictionary) -> void:
|
||||
var x_frames = [
|
||||
{ percentage = 0, to = 0 },
|
||||
{ percentage = 20, to = 0 },
|
||||
{ percentage = 100, to = 2000 },
|
||||
]
|
||||
|
||||
var opacity_frames = [
|
||||
{ percentage = 0, from = 1 },
|
||||
{ percentage = 20, to = 0.7 },
|
||||
{ percentage = 100, to = 0.7 },
|
||||
]
|
||||
|
||||
DialogicAnimaPropertiesHelper.set_2D_pivot(data.node, DialogicAnimaPropertiesHelper.PIVOT.CENTER)
|
||||
|
||||
anima_tween.add_relative_frames(data, "x", x_frames)
|
||||
anima_tween.add_frames(data, "opacity", opacity_frames)
|
@ -0,0 +1,48 @@
|
||||
extends TextureRect
|
||||
|
||||
var native_dialogic_background = true
|
||||
var tween
|
||||
|
||||
func _ready():
|
||||
expand = true
|
||||
name = 'Background'
|
||||
anchor_right = 1
|
||||
anchor_bottom = 1
|
||||
if DialogicResources.get_settings_value('dialog', 'stretch_backgrounds', true):
|
||||
stretch_mode = TextureRect.STRETCH_SCALE
|
||||
else:
|
||||
stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
|
||||
show_behind_parent = true
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
func _init():
|
||||
tween = Tween.new()
|
||||
add_child(tween)
|
||||
|
||||
|
||||
func fade_in(time = 1):
|
||||
modulate = Color(1, 1,1,0)
|
||||
tween.interpolate_property(self, "modulate",
|
||||
null, Color(1,1,1,1), time,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
|
||||
|
||||
func fade_out(time = 1):
|
||||
if tween:
|
||||
tween.connect('tween_all_completed', self, '_on_tween_over')
|
||||
tween.interpolate_property(self, "modulate",
|
||||
Color(1,1,1,1), Color(1,1,1,0), time,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
else:
|
||||
_on_tween_over()
|
||||
|
||||
func remove_with_delay(time =1):
|
||||
var timer = Timer.new()
|
||||
timer.connect("timeout", self, "queue_free")
|
||||
add_child(timer)
|
||||
timer.start(time+0.1)
|
||||
|
||||
func _on_tween_over():
|
||||
queue_free()
|
@ -0,0 +1,9 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Nodes/Background.gd" type="Script" id=1]
|
||||
|
||||
[node name="Background" type="TextureRect"]
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
extends Control
|
||||
class_name DialogicBackgroundMusic
|
||||
|
||||
onready var _track1 := $Track1
|
||||
onready var _track2 := $Track2
|
||||
|
||||
var current_path = ""
|
||||
var current_track = null
|
||||
|
||||
func _ready():
|
||||
$Tween.connect("tween_completed", self, "_on_Tween_tween_completed")
|
||||
|
||||
func crossfade_to(path: String, audio_bus:String, volume:float, fade_length: float) -> void:
|
||||
# find a better solution for this
|
||||
if _track1.playing and _track2.playing:
|
||||
return
|
||||
|
||||
var stream: AudioStream = load(path)
|
||||
var fade_out_track = _track1
|
||||
var fade_in_track = _track2
|
||||
|
||||
if _track2.playing:
|
||||
fade_out_track = _track2
|
||||
fade_in_track = _track1
|
||||
|
||||
# setup the new track
|
||||
fade_in_track.stream = stream
|
||||
fade_in_track.bus = audio_bus
|
||||
fade_in_track.volume_db = -60
|
||||
|
||||
|
||||
$Tween.interpolate_property(fade_out_track, "volume_db", null, -60, fade_length, Tween.TRANS_EXPO)
|
||||
$Tween.interpolate_property(fade_in_track, "volume_db", -60, volume, fade_length, Tween.TRANS_EXPO)
|
||||
$Tween.start()
|
||||
|
||||
# in case the audio is already playing we will attempt a fade into the new one from the current position
|
||||
if current_path == path:
|
||||
fade_in_track.play(fade_out_track.get_playback_position())
|
||||
# else just play it from the beginning
|
||||
else:
|
||||
fade_in_track.play()
|
||||
current_track = fade_in_track
|
||||
|
||||
current_path = path
|
||||
|
||||
func fade_out(fade_length:float = 1) -> void:
|
||||
current_path = ""
|
||||
current_track = null
|
||||
$Tween.interpolate_property(_track1, "volume_db", null, -60, fade_length, Tween.TRANS_EXPO)
|
||||
$Tween.interpolate_property(_track2, "volume_db", null, -60, fade_length, Tween.TRANS_EXPO)
|
||||
$Tween.start()
|
||||
|
||||
func _on_Tween_tween_completed(object, key):
|
||||
# if the stream was faded out
|
||||
if object.volume_db == -60:
|
||||
object.playing = false
|
||||
object.stream = null
|
||||
|
||||
func get_current_info():
|
||||
if current_track != null:
|
||||
return {"file":current_path, "volume": current_track.volume_db, "audio_bus": current_track.bus}
|
||||
return null
|
@ -0,0 +1,19 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Nodes/BackgroundMusic.gd" type="Script" id=1]
|
||||
|
||||
[node name="BackgroundMusic" type="Control"]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Track1" type="AudioStreamPlayer" parent="."]
|
||||
volume_db = -80.0
|
||||
|
||||
[node name="Track2" type="AudioStreamPlayer" parent="."]
|
||||
volume_db = -80.0
|
||||
|
||||
[node name="Tween" type="Tween" parent="."]
|
@ -0,0 +1,51 @@
|
||||
extends AudioStreamPlayer
|
||||
|
||||
var stop_time:float
|
||||
|
||||
func play_voice(data:Dictionary) -> void:
|
||||
if data == {}:
|
||||
stop_voice()
|
||||
return
|
||||
|
||||
if data.has('volume'):
|
||||
volume_db = data['volume']
|
||||
|
||||
if data.has('audio_bus'):
|
||||
bus = data['audio_bus']
|
||||
|
||||
if data.has('file'):
|
||||
if data['file'] == '':
|
||||
stop_voice()
|
||||
return
|
||||
var s:AudioStream = load(data['file'])
|
||||
if s != null:
|
||||
stream = s
|
||||
#Will play from start_time when possible
|
||||
if data.has('start_time'):
|
||||
play(data['start_time'])
|
||||
else:
|
||||
play()
|
||||
#Stop time will fall back to length of audiostream minus 0.1 secund
|
||||
#if not defined otherwise. This should allow _process to stop the
|
||||
#audio before it autorepeats
|
||||
if data.has('stop_time'):
|
||||
stop_time = data['stop_time']
|
||||
if stop_time <= 0:
|
||||
stop_time = s.get_length() - 0.1
|
||||
else:
|
||||
stop_time = s.get_length() - 0.1
|
||||
else:
|
||||
stop_voice()
|
||||
func stop_voice():
|
||||
stop()
|
||||
#this is part of a hack, and could be replaced with something more elegant. - KvaGram
|
||||
func remaining_time():
|
||||
if !playing:
|
||||
return 0
|
||||
return stop_time - get_playback_position()
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
#Will automatically stop playing when reaching stop_time
|
||||
if(playing && get_playback_position() >= stop_time):
|
||||
stop_voice()
|
@ -0,0 +1,10 @@
|
||||
extends Button
|
||||
|
||||
func _process(delta):
|
||||
if Input.is_action_pressed(get_meta('input_next')):
|
||||
if has_focus():
|
||||
emit_signal("button_down")
|
||||
if Input.is_action_just_released(get_meta('input_next')):
|
||||
if has_focus():
|
||||
emit_signal("button_up")
|
||||
emit_signal("pressed")
|
@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Nodes/ChoiceButton.gd" type="Script" id=1]
|
||||
|
||||
[node name="ChoiceButton" type="Button"]
|
||||
size_flags_horizontal = 4
|
||||
size_flags_vertical = 4
|
||||
text = "Testing button "
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
1556
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/DialogNode.gd
Normal file
1556
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/DialogNode.gd
Normal file
File diff suppressed because it is too large
Load Diff
184
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/DialogNode.tscn
Normal file
184
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/DialogNode.tscn
Normal file
@ -0,0 +1,184 @@
|
||||
[gd_scene load_steps=14 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Nodes/TextBubble.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/backgrounds/GlossaryBackground.tres" type="StyleBox" id=2]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/CharacterVoice.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres" type="DynamicFont" id=4]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/glossary_info.gd" type="Script" id=5]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/DialogNode.gd" type="Script" id=6]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/BackgroundMusic.tscn" type="PackedScene" id=7]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/random_audio_stream_player.gd" type="Script" id=8]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/Sound Effects/Beep.wav" type="AudioStream" id=9]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/DialogicCustomEvents.gd" type="Script" id=10]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/History.tscn" type="PackedScene" id=11]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 1, 1, 1, 0 )
|
||||
expand_margin_left = 10.0
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=2]
|
||||
extents = Vector2( 1280, 720 )
|
||||
|
||||
[node name="DialogNode" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 6 )
|
||||
|
||||
[node name="Portraits" type="Control" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 640.0
|
||||
margin_top = 720.0
|
||||
margin_right = 640.0
|
||||
margin_bottom = 720.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TextBubble" parent="." instance=ExtResource( 1 )]
|
||||
margin_left = 185.0
|
||||
margin_top = 513.0
|
||||
margin_right = 1095.0
|
||||
margin_bottom = 680.0
|
||||
|
||||
[node name="Options" type="VBoxContainer" parent="."]
|
||||
visible = false
|
||||
margin_right = 1280.0
|
||||
margin_bottom = 720.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="FX" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="BackgroundMusic" parent="FX" instance=ExtResource( 7 )]
|
||||
|
||||
[node name="CharacterVoice" type="AudioStreamPlayer" parent="FX"]
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="Audio" type="Node" parent="FX"]
|
||||
|
||||
[node name="Typing" type="AudioStreamPlayer" parent="FX/Audio"]
|
||||
script = ExtResource( 8 )
|
||||
samples = [ ExtResource( 9 ) ]
|
||||
random_strategy = 2
|
||||
|
||||
[node name="Waiting" type="AudioStreamPlayer" parent="FX/Audio"]
|
||||
script = ExtResource( 8 )
|
||||
samples = [ ExtResource( 9 ) ]
|
||||
random_strategy = 2
|
||||
|
||||
[node name="Passing" type="AudioStreamPlayer" parent="FX/Audio"]
|
||||
script = ExtResource( 8 )
|
||||
samples = [ ExtResource( 9 ) ]
|
||||
random_strategy = 2
|
||||
|
||||
[node name="Hovering" type="AudioStreamPlayer" parent="FX/Audio"]
|
||||
script = ExtResource( 8 )
|
||||
samples = [ ExtResource( 9 ) ]
|
||||
random_strategy = 2
|
||||
|
||||
[node name="Selecting" type="AudioStreamPlayer" parent="FX/Audio"]
|
||||
script = ExtResource( 8 )
|
||||
samples = [ ExtResource( 9 ) ]
|
||||
random_strategy = 2
|
||||
|
||||
[node name="DefinitionInfo" type="PanelContainer" parent="."]
|
||||
visible = false
|
||||
margin_right = 208.0
|
||||
mouse_filter = 1
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
custom_styles/panel = ExtResource( 2 )
|
||||
script = ExtResource( 5 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="DefinitionInfo"]
|
||||
margin_right = 208.0
|
||||
margin_bottom = 143.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 2
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Title" type="RichTextLabel" parent="DefinitionInfo/VBoxContainer"]
|
||||
margin_right = 208.0
|
||||
margin_bottom = 27.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
custom_colors/default_color = Color( 1, 1, 1, 1 )
|
||||
custom_fonts/normal_font = ExtResource( 4 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
bbcode_enabled = true
|
||||
bbcode_text = "This is the title"
|
||||
text = "This is the title"
|
||||
fit_content_height = true
|
||||
scroll_active = false
|
||||
|
||||
[node name="Content" type="RichTextLabel" parent="DefinitionInfo/VBoxContainer"]
|
||||
margin_top = 31.0
|
||||
margin_right = 208.0
|
||||
margin_bottom = 112.0
|
||||
size_flags_horizontal = 3
|
||||
custom_colors/default_color = Color( 0.756863, 0.756863, 0.756863, 1 )
|
||||
custom_fonts/normal_font = ExtResource( 4 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
bbcode_enabled = true
|
||||
fit_content_height = true
|
||||
scroll_active = false
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Extra" type="RichTextLabel" parent="DefinitionInfo/VBoxContainer"]
|
||||
margin_top = 116.0
|
||||
margin_right = 208.0
|
||||
margin_bottom = 143.0
|
||||
size_flags_horizontal = 3
|
||||
custom_colors/default_color = Color( 0.756863, 0.756863, 0.756863, 1 )
|
||||
custom_fonts/normal_font = ExtResource( 4 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
bbcode_enabled = true
|
||||
fit_content_height = true
|
||||
scroll_active = false
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Timer" type="Timer" parent="DefinitionInfo"]
|
||||
|
||||
[node name="OptionsDelayedInput" type="Timer" parent="."]
|
||||
|
||||
[node name="DialogicTimer" type="Timer" parent="."]
|
||||
one_shot = true
|
||||
|
||||
[node name="CustomEvents" type="Node" parent="."]
|
||||
script = ExtResource( 10 )
|
||||
|
||||
[node name="History" parent="." instance=ExtResource( 11 )]
|
||||
|
||||
[node name="TouchScreenButton" type="TouchScreenButton" parent="."]
|
||||
shape = SubResource( 2 )
|
||||
shape_visible = false
|
||||
action = "dialogic_default_action"
|
||||
visibility_mode = 1
|
||||
|
||||
[connection signal="timeout" from="DefinitionInfo/Timer" to="." method="_on_Definition_Timer_timeout"]
|
@ -0,0 +1,50 @@
|
||||
extends Control
|
||||
|
||||
|
||||
## The timeline to load when starting the scene
|
||||
export(String, "TimelineDropdown") var timeline: String
|
||||
export(bool) var add_canvas = true
|
||||
export(bool) var reset_saves = true
|
||||
|
||||
func _ready():
|
||||
if reset_saves:
|
||||
Dialogic.reset_saves()
|
||||
var d = Dialogic.start(timeline, '', "res://addons/dialogic/Nodes/DialogNode.tscn", add_canvas)
|
||||
get_parent().call_deferred('add_child', d)
|
||||
_copy_signals(d if not add_canvas else d.dialog_node)
|
||||
queue_free()
|
||||
|
||||
func _copy_signals(dialogic:Node):
|
||||
var sigs = self.get_signal_list()
|
||||
for s in sigs:
|
||||
if not s['name'] in _signals_to_copy:
|
||||
continue
|
||||
if not dialogic.has_signal(s['name']):
|
||||
print("Cannot copy connections of signal " + s['name'] + " from " + self.to_string() + " to " + dialogic.to_string())
|
||||
continue
|
||||
var conns = self.get_signal_connection_list(s['name'])
|
||||
for c in conns:
|
||||
dialogic.connect(c['signal'], c['target'], c['method'], c['binds'], c['flags'])
|
||||
|
||||
|
||||
var _signals_to_copy = [
|
||||
'event_start',
|
||||
'event_end',
|
||||
'text_complete',
|
||||
'timeline_start',
|
||||
'timeline_end',
|
||||
'dialogic_signal'
|
||||
]
|
||||
## -----------------------------------------------------------------------------
|
||||
## SIGNALS (proxy copy of DialogNode signals)
|
||||
## -----------------------------------------------------------------------------
|
||||
# Event end/start
|
||||
signal event_start(type, event)
|
||||
signal event_end(type)
|
||||
# Text Signals
|
||||
signal text_complete(text_data)
|
||||
# Timeline end/start
|
||||
signal timeline_start(timeline_name)
|
||||
signal timeline_end(timeline_name)
|
||||
# Custom user signal
|
||||
signal dialogic_signal(value)
|
@ -0,0 +1,75 @@
|
||||
tool
|
||||
extends Node
|
||||
class_name DialogicCustomEvents
|
||||
|
||||
# references to the nodes with the handler script
|
||||
# to be used later by the "event_handler"
|
||||
# keys: event_id
|
||||
# values: reference to handler node.
|
||||
var handlers : = {}
|
||||
|
||||
|
||||
## -----------------------------------------------------------------------------
|
||||
## Loops through the custom events folder and creates a handler node
|
||||
## for every custom event.
|
||||
##
|
||||
## To handle a custom event simply check if the event_id is in the handlers dicionary keys,
|
||||
## then get the value (which is the handler node) to call its hadler function
|
||||
func update() -> void:
|
||||
var path : String = DialogicResources.get_working_directories()["CUSTOM_EVENTS_DIR"]
|
||||
var dir = Directory.new()
|
||||
if dir.open(path) == OK:
|
||||
dir.list_dir_begin()
|
||||
var file_name = dir.get_next()
|
||||
# goes through all the folders in the custom events folder
|
||||
while file_name != "":
|
||||
# if it found a folder
|
||||
if dir.current_is_dir() and not file_name in ['.', '..']:
|
||||
|
||||
# look through that folder
|
||||
#print("Found custom event folder: " + file_name)
|
||||
var event = load(path.plus_file(file_name).plus_file('EventBlock.tscn')).instance()
|
||||
|
||||
if event:
|
||||
var handler_script_path = path.plus_file(file_name).plus_file('event_'+event.event_data['event_id']+'.gd')
|
||||
var event_id = event.event_data['event_id']
|
||||
var event_name = event.event_name
|
||||
|
||||
# not necesary, we now have the data in the handlers dict
|
||||
#custom_events[event.event_data['event_id']] = {
|
||||
# 'event_script' : handler_script_path,
|
||||
# 'event_name' : event.event_name,
|
||||
#}
|
||||
|
||||
# Check if we already have a handler node for this event.
|
||||
if handlers.has(event_id):
|
||||
#print("Custom event ",event_id," already loaded")
|
||||
#print("Continuing...")
|
||||
file_name = dir.get_next()
|
||||
continue
|
||||
else:
|
||||
#print("No handler node for event ",event_id," found.")
|
||||
#print("Creating...")
|
||||
# create a node for the custom event an attach the script
|
||||
var handler = Node.new()
|
||||
handler.set_script(load(handler_script_path))
|
||||
handler.set_name(event_name)
|
||||
|
||||
# not really necessary, but just in case
|
||||
handler.set_meta("event_id",event_id)
|
||||
|
||||
#add data to dictionary
|
||||
handlers[event_id] = handler
|
||||
#add node as a child of this
|
||||
self.add_child(handler)
|
||||
|
||||
event.queue_free()
|
||||
else:
|
||||
print("[D] An error occurred when trying to access a custom event.")
|
||||
|
||||
|
||||
else:
|
||||
pass # files in the directory are ignored
|
||||
file_name = dir.get_next()
|
||||
else:
|
||||
print("[D] An error occurred when trying to access the custom event folder.")
|
311
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/History.gd
Normal file
311
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/History.gd
Normal file
@ -0,0 +1,311 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
|
||||
export(PackedScene) var HistoryRow = load("res://addons/dialogic/Example Assets/History/HistoryRow.tscn")
|
||||
export(PackedScene) var HistoryDefaultBackground = load("res://addons/dialogic/Example Assets/History/HistoryBackground.tscn")
|
||||
export(PackedScene) var HistoryOpenButton = load("res://addons/dialogic/Example Assets/History/HistoryButton.tscn")
|
||||
export(PackedScene) var HistoryCloseButton = load("res://addons/dialogic/Example Assets/History/HistoryButton.tscn")
|
||||
export(int) var Vertical_Separation = 16
|
||||
|
||||
onready var HistoryTimeline = $HistoryPopup/ScrollHistoryContainer/MarginContainer/HistoryTimeline
|
||||
onready var scrollbar = $HistoryPopup/ScrollHistoryContainer.get_v_scrollbar()
|
||||
onready var ScrollHistoryContainer = $HistoryPopup/ScrollHistoryContainer
|
||||
onready var HistoryPopup = $HistoryPopup
|
||||
onready var HistoryAudio = $HistoryPopup/HistoryAudio
|
||||
|
||||
var HistoryButton
|
||||
var CloseButton
|
||||
var HistoryBackground
|
||||
|
||||
var is_history_open = false
|
||||
var is_mouse_on_button = false
|
||||
var block_dialog_advance = false setget , history_advance_block
|
||||
|
||||
var lastQuestionNode = null
|
||||
var curTheme = null
|
||||
var prevState
|
||||
|
||||
var eventsToLog = ['dialogic_001', 'dialogic_010']
|
||||
var logArrivals = false
|
||||
var logExits = false
|
||||
|
||||
var scrollToBottom = true
|
||||
var reverseTimeline = false
|
||||
var characterNameColorOn = true
|
||||
var lineBreakAfterName = true
|
||||
|
||||
var scrollToggle = false
|
||||
|
||||
func _ready():
|
||||
var testHistoryRow = HistoryRow.instance()
|
||||
assert(testHistoryRow.has_method('add_history'), 'HistoryRow Scene must implement add_history(string, string) method.')
|
||||
testHistoryRow.queue_free()
|
||||
|
||||
HistoryBackground = HistoryDefaultBackground.instance()
|
||||
HistoryPopup.add_child(HistoryBackground)
|
||||
HistoryPopup.move_child(HistoryBackground, 0)
|
||||
|
||||
#Scrollbar only updates when visible, so need it to be handled
|
||||
scrollbar.connect("changed",self,"handle_scrollbar_changed")
|
||||
|
||||
func handle_scrollbar_changed():
|
||||
#It's firing every frame, we only want to check it once on opening
|
||||
if(scrollToggle):
|
||||
scrollToggle = false
|
||||
if (scrollToBottom):
|
||||
ScrollHistoryContainer.scroll_vertical = scrollbar.max_value
|
||||
else:
|
||||
ScrollHistoryContainer.scroll_vertical = 0
|
||||
|
||||
|
||||
func initalize_history():
|
||||
if get_parent().settings.get_value('history', 'enable_open_button', true):
|
||||
HistoryButton = HistoryOpenButton.instance()
|
||||
add_child(HistoryButton)
|
||||
HistoryButton.connect("pressed", self, '_on_toggle_history')
|
||||
HistoryButton.connect("mouse_entered", self, '_on_HistoryButton_mouse_entered')
|
||||
HistoryButton.connect("mouse_exited", self, '_on_HistoryButton_mouse_exited')
|
||||
HistoryButton.disabled = false
|
||||
HistoryButton.show()
|
||||
|
||||
if get_parent().settings.get_value('history', 'enable_close_button', true):
|
||||
CloseButton = HistoryCloseButton.instance()
|
||||
add_child(CloseButton)
|
||||
CloseButton.connect("pressed", self, '_on_toggle_history')
|
||||
CloseButton.disabled = true
|
||||
CloseButton.hide()
|
||||
|
||||
# See if we're logging arrivals and exits
|
||||
logArrivals = get_parent().settings.get_value('history', 'log_arrivals', true)
|
||||
logExits = get_parent().settings.get_value('history', 'log_exits', true)
|
||||
if logExits or logArrivals:
|
||||
eventsToLog.push_back('dialogic_002')
|
||||
|
||||
# Set the other selectable settings options
|
||||
scrollToBottom = get_parent().settings.get_value('history', 'history_scroll_to_bottom', true)
|
||||
reverseTimeline = get_parent().settings.get_value('history', 'history_reverse_timeline', false)
|
||||
characterNameColorOn = get_parent().settings.get_value('history', 'history_name_color_on', true)
|
||||
lineBreakAfterName = get_parent().settings.get_value('history', 'history_break_after_name', false)
|
||||
|
||||
|
||||
# Grab some settings and make the boxes up right
|
||||
var button_anchor = int(get_parent().settings.get_value('history', 'history_button_position', 2))
|
||||
var screen_margin_x = get_parent().settings.get_value('history', 'history_screen_margin_x', 0)
|
||||
var screen_margin_y = get_parent().settings.get_value('history', 'history_screen_margin_y', 0)
|
||||
var container_margin_X = get_parent().settings.get_value('history', 'history_container_margin_x', 0)
|
||||
var container_margin_y = get_parent().settings.get_value('history', 'history_container_margin_y', 0)
|
||||
|
||||
HistoryPopup.margin_left = screen_margin_x
|
||||
HistoryPopup.margin_right = -screen_margin_x
|
||||
HistoryPopup.margin_top = screen_margin_y
|
||||
HistoryPopup.margin_bottom = -screen_margin_y
|
||||
|
||||
ScrollHistoryContainer.margin_left = container_margin_X
|
||||
ScrollHistoryContainer.margin_right = -container_margin_X
|
||||
ScrollHistoryContainer.margin_top = container_margin_y
|
||||
ScrollHistoryContainer.margin_bottom = -container_margin_y
|
||||
|
||||
for button in [HistoryButton, CloseButton]:
|
||||
if button == null:
|
||||
continue
|
||||
|
||||
var reference = button.get_parent().rect_size
|
||||
|
||||
# Adding audio when focused or hovered
|
||||
button.connect('focus_entered', get_parent(), '_on_option_hovered', [button])
|
||||
button.connect('mouse_entered', get_parent(), '_on_option_focused')
|
||||
|
||||
# Button positioning
|
||||
var anchor_values = [0,0,1,1]
|
||||
var position_offset = Vector2(0,0)
|
||||
|
||||
# Top Left
|
||||
if button_anchor == 0:
|
||||
anchor_values = [0, 0, 0, 0]
|
||||
position_offset.x = 0
|
||||
position_offset.y = 0
|
||||
# Top Center
|
||||
elif button_anchor == 1:
|
||||
anchor_values = [.5, 0, .5, 0]
|
||||
position_offset.x = reference.x/2 - button.rect_size.x
|
||||
position_offset.y = 0
|
||||
# Top Right
|
||||
elif button_anchor == 2:
|
||||
anchor_values = [1, 0, 1, 0]
|
||||
position_offset.x = reference.x - button.rect_size.x
|
||||
position_offset.y = 0
|
||||
# 3 - Number skip because of the separator
|
||||
# Center Left
|
||||
elif button_anchor == 4:
|
||||
anchor_values = [0, .5, 0, .5]
|
||||
position_offset.x = 0
|
||||
position_offset.y = reference.y/2 - button.rect_size.y
|
||||
# True Center
|
||||
elif button_anchor == 5:
|
||||
anchor_values = [.5, .5, .5, .5]
|
||||
position_offset.x = reference.x/2 - button.rect_size.x
|
||||
position_offset.y = reference.y/2 - button.rect_size.y
|
||||
# Center Right
|
||||
elif button_anchor == 6:
|
||||
anchor_values = [1, .5, 1, .5]
|
||||
position_offset.x = reference.x - button.rect_size.x
|
||||
position_offset.y = reference.y/2 - button.rect_size.y
|
||||
# Number skip because of the separator
|
||||
elif button_anchor == 8:
|
||||
anchor_values = [0, 1, 0, 1]
|
||||
position_offset.x = 0
|
||||
position_offset.y = reference.y - button.rect_size.y
|
||||
elif button_anchor == 9:
|
||||
anchor_values = [.5, 1, .5, 1]
|
||||
position_offset.x = reference.x/2 - button.rect_size.x
|
||||
position_offset.y = reference.y - button.rect_size.y
|
||||
elif button_anchor == 10:
|
||||
anchor_values = [1, 1, 1, 1]
|
||||
position_offset.x = reference.x - button.rect_size.x
|
||||
position_offset.y = reference.y - button.rect_size.y
|
||||
|
||||
button.anchor_left = anchor_values[0]
|
||||
button.anchor_top = anchor_values[1]
|
||||
button.anchor_right = anchor_values[2]
|
||||
button.anchor_bottom = anchor_values[3]
|
||||
|
||||
button.rect_global_position = button.get_parent().rect_global_position + position_offset
|
||||
|
||||
|
||||
# Add history based on the passed event, using some logic to get it right
|
||||
func add_history_row_event(eventData):
|
||||
# Abort if we aren't logging the event, or if its a character event of type update
|
||||
if !eventsToLog.has(eventData.event_id) or (eventData.event_id == 'dialogic_002' and eventData.get('type') == 2 ):
|
||||
return
|
||||
# Abort if we aren't logging arrivals and its a character event of type arrival
|
||||
if eventData.event_id == 'dialogic_002' and eventData.get('type') == 0 and !logArrivals:
|
||||
return
|
||||
# Abort if we aren't logging exits and its a character event of type exit
|
||||
if eventData.event_id == 'dialogic_002' and eventData.get('type') == 1 and !logExits:
|
||||
return
|
||||
|
||||
var newHistoryRow = HistoryRow.instance()
|
||||
HistoryTimeline.add_child(newHistoryRow)
|
||||
if(reverseTimeline):
|
||||
HistoryTimeline.move_child(newHistoryRow,0)
|
||||
if newHistoryRow.has_method('load_theme') and get_parent().settings.get_value('history', 'enable_dynamic_theme', false) == true:
|
||||
newHistoryRow.load_theme(curTheme)
|
||||
|
||||
var characterPrefix = ''
|
||||
if eventData.has('character') and eventData.character != '':
|
||||
var characterData = DialogicUtil.get_character(eventData.character)
|
||||
var characterName = characterData.get('name', '')
|
||||
if eventData.has('character') and eventData.character == '[All]':
|
||||
characterPrefix = str('Everyone')
|
||||
elif characterData.data.get('display_name_bool', false) == true:
|
||||
characterName = characterData.data.get('display_name', '')
|
||||
|
||||
if characterName != '':
|
||||
var charDelimiter = get_parent().settings.get_value('history', 'history_character_delimiter', '')
|
||||
var parsed_name = DialogicParser.parse_definitions(get_parent(), characterName, true, false)
|
||||
var characterColor = characterData.data.get('color', Color.white)
|
||||
if (!characterNameColorOn):
|
||||
characterColor = Color.white
|
||||
var lineBreak = ''
|
||||
if (lineBreakAfterName):
|
||||
lineBreak = '\n'
|
||||
characterPrefix = str("[color=",characterColor,"]", parsed_name, "[/color]", charDelimiter, ' ', lineBreak)
|
||||
|
||||
var audioData = ''
|
||||
if eventData.has('voice_data'):
|
||||
if eventData['voice_data'].has('0'):
|
||||
audioData = eventData['voice_data']['0'].file
|
||||
newHistoryRow.AudioButton.connect('pressed', self, '_on_audio_trigger', [audioData])
|
||||
|
||||
|
||||
# event logging handled here
|
||||
# Text Events
|
||||
if eventData.event_id == 'dialogic_001':
|
||||
newHistoryRow.add_history(str(characterPrefix, eventData.text), audioData)
|
||||
# Character Arrivals
|
||||
elif eventData.event_id == 'dialogic_002':
|
||||
var logText = get_parent().settings.get_value('history', 'text_arrivals', 'has arrived')
|
||||
if eventData.get('type') == 1:
|
||||
logText = get_parent().settings.get_value('history', 'text_exits', 'has left')
|
||||
newHistoryRow.add_history(str(characterPrefix, ' ', logText), audioData)
|
||||
# List Choices
|
||||
elif eventData.event_id == 'dialogic_010':
|
||||
newHistoryRow.add_history(str(characterPrefix, eventData.question), audioData)
|
||||
if eventData.has('options') and get_parent().settings.get_value('history', 'log_choices', true):
|
||||
var choiceString = "\n\t"
|
||||
for choice in eventData['options']:
|
||||
choiceString = str(choiceString, '[', choice.label, ']\t')
|
||||
newHistoryRow.add_history(choiceString, audioData)
|
||||
lastQuestionNode = newHistoryRow
|
||||
|
||||
|
||||
func add_answer_to_question(stringData):
|
||||
if lastQuestionNode != null:
|
||||
lastQuestionNode.add_history(str('\n\t', stringData), lastQuestionNode.audioPath)
|
||||
lastQuestionNode = null
|
||||
|
||||
|
||||
func change_theme(newTheme: ConfigFile):
|
||||
if get_parent().settings.get_value('history', 'enable_dynamic_theme', false):
|
||||
curTheme = newTheme
|
||||
|
||||
|
||||
func load_theme(theme: ConfigFile):
|
||||
curTheme = theme
|
||||
|
||||
|
||||
func _on_audio_trigger(audioFilepath):
|
||||
HistoryAudio.stream = load(audioFilepath)
|
||||
HistoryAudio.play()
|
||||
|
||||
|
||||
func _on_HistoryPopup_popup_hide():
|
||||
HistoryAudio.stop()
|
||||
|
||||
|
||||
func _on_HistoryPopup_about_to_show():
|
||||
if HistoryButton != null:
|
||||
scrollToggle = true
|
||||
HistoryButton.show()
|
||||
|
||||
|
||||
|
||||
func _on_HistoryButton_mouse_entered():
|
||||
is_mouse_on_button = true
|
||||
|
||||
|
||||
func _on_HistoryButton_mouse_exited():
|
||||
is_mouse_on_button = false
|
||||
|
||||
|
||||
func history_advance_block() -> bool:
|
||||
return is_mouse_on_button or is_history_open
|
||||
|
||||
# Used to manually toggle the history visibility on or off
|
||||
# This is most useful when you wish to make your own custom controls
|
||||
func _on_toggle_history():
|
||||
if HistoryPopup.visible == false:
|
||||
_on_HistoryPopup_about_to_show()
|
||||
HistoryPopup.show()
|
||||
if HistoryButton != null:
|
||||
HistoryButton.hide()
|
||||
HistoryButton.disabled = true
|
||||
if CloseButton != null:
|
||||
CloseButton.disabled = false
|
||||
CloseButton.show()
|
||||
is_history_open = true
|
||||
is_mouse_on_button = false
|
||||
else:
|
||||
_on_HistoryPopup_popup_hide()
|
||||
HistoryPopup.hide()
|
||||
if HistoryButton != null:
|
||||
HistoryButton.show()
|
||||
HistoryButton.disabled = false
|
||||
if CloseButton != null:
|
||||
CloseButton.disabled = true
|
||||
CloseButton.hide()
|
||||
is_history_open = false
|
||||
is_mouse_on_button = false
|
||||
|
||||
|
54
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/History.tscn
Normal file
54
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/History.tscn
Normal file
@ -0,0 +1,54 @@
|
||||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryBackground.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryRow.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/History.gd" type="Script" id=3]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryButton.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/History/HistoryReturnButton.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="History" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
HistoryRow = ExtResource( 2 )
|
||||
HistoryDefaultBackground = ExtResource( 1 )
|
||||
HistoryOpenButton = ExtResource( 4 )
|
||||
HistoryCloseButton = ExtResource( 5 )
|
||||
|
||||
[node name="HistoryPopup" type="Control" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="HistoryAudio" type="AudioStreamPlayer" parent="HistoryPopup"]
|
||||
|
||||
[node name="ScrollHistoryContainer" type="ScrollContainer" parent="HistoryPopup"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="HistoryPopup/ScrollHistoryContainer"]
|
||||
margin_right = 1024.0
|
||||
margin_bottom = 10.0
|
||||
size_flags_horizontal = 3
|
||||
custom_constants/margin_right = 5
|
||||
custom_constants/margin_top = 5
|
||||
custom_constants/margin_left = 5
|
||||
custom_constants/margin_bottom = 5
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HistoryTimeline" type="VBoxContainer" parent="HistoryPopup/ScrollHistoryContainer/MarginContainer"]
|
||||
margin_left = 5.0
|
||||
margin_top = 5.0
|
||||
margin_right = 1019.0
|
||||
margin_bottom = 5.0
|
||||
custom_constants/separation = 16
|
204
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/Portrait.gd
Normal file
204
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/Portrait.gd
Normal file
@ -0,0 +1,204 @@
|
||||
extends Control
|
||||
|
||||
var z_index = 0
|
||||
|
||||
var character_data = {
|
||||
'name': 'Default',
|
||||
'image': "res://addons/dialogic/Example Assets/portraits/df-3.png",
|
||||
'color': Color(0.973511, 1, 0.152344),
|
||||
'file': '',
|
||||
'mirror_portraits': false
|
||||
}
|
||||
|
||||
var single_portrait_mode = false
|
||||
var dim_time = 0.5
|
||||
var direction = 'left'
|
||||
var debug = false
|
||||
var fading_out = false
|
||||
var custom_instance : Node2D = null
|
||||
|
||||
var current_state := {'character':'', 'portrait':'', 'position':'', 'mirrored':false}
|
||||
|
||||
signal animation_finished
|
||||
|
||||
func init(expression: String = '') -> void:
|
||||
set_portrait(expression)
|
||||
|
||||
|
||||
func _ready():
|
||||
if debug:
|
||||
print('Character data loaded: ', character_data)
|
||||
print(rect_position, $TextureRect.rect_size)
|
||||
|
||||
$AnimationTween.connect('finished_animation', self, 'emit_signal', ['animation_finished'])
|
||||
|
||||
|
||||
func set_portrait(expression: String) -> void:
|
||||
if expression == "(Don't change)":
|
||||
return
|
||||
|
||||
if expression == '':
|
||||
expression = 'Default'
|
||||
|
||||
current_state['portrait'] = expression
|
||||
|
||||
# Clearing old custom scenes
|
||||
for n in get_children():
|
||||
if 'DialogicCustomPortraitScene' in n.name:
|
||||
n.queue_free()
|
||||
|
||||
custom_instance = null
|
||||
|
||||
var default
|
||||
for p in character_data['portraits']:
|
||||
if p['name'] == expression:
|
||||
if is_scene(p['path']):
|
||||
# Creating a scene portrait
|
||||
var custom_node = load(p['path'])
|
||||
custom_instance = custom_node.instance()
|
||||
custom_instance.name = 'DialogicCustomPortraitScene'
|
||||
add_child(custom_instance)
|
||||
|
||||
$TextureRect.texture = ImageTexture.new()
|
||||
return
|
||||
else:
|
||||
# Creating an image portrait
|
||||
if ResourceLoader.exists(p['path']):
|
||||
$TextureRect.texture = load(p['path'])
|
||||
else:
|
||||
$TextureRect.texture = ImageTexture.new()
|
||||
return
|
||||
|
||||
# Saving what the default is to fallback to it.
|
||||
if p['name'] == 'Default':
|
||||
default = p['path']
|
||||
|
||||
|
||||
# Everything failed, go with the default one
|
||||
if is_scene(default):
|
||||
push_warning('[Dialogic] Portrait missing: "' + expression + '". Maybe you deleted it? Update your timeline.')
|
||||
# Creating a scene portrait
|
||||
var custom_node = load(default)
|
||||
custom_instance = custom_node.instance()
|
||||
custom_instance.name = 'DialogicCustomPortraitScene'
|
||||
add_child(custom_instance)
|
||||
|
||||
$TextureRect.texture = ImageTexture.new()
|
||||
return
|
||||
else:
|
||||
# Creating an image portrait
|
||||
if ResourceLoader.exists(default):
|
||||
$TextureRect.texture = load(default)
|
||||
else:
|
||||
$TextureRect.texture = ImageTexture.new()
|
||||
return
|
||||
|
||||
|
||||
|
||||
func set_mirror(value):
|
||||
current_state['mirrored'] = value
|
||||
if character_data["data"].has('mirror_portraits'):
|
||||
if character_data["data"]['mirror_portraits']:
|
||||
if custom_instance != null:
|
||||
custom_instance.scale.x *= get_mirror_scale(custom_instance.scale.x, !value)
|
||||
else:
|
||||
$TextureRect.flip_h = !value
|
||||
else:
|
||||
if custom_instance != null:
|
||||
custom_instance.scale.x *= get_mirror_scale(custom_instance.scale.x, value)
|
||||
else:
|
||||
$TextureRect.flip_h = value
|
||||
else:
|
||||
if custom_instance != null:
|
||||
custom_instance.scale.x *= get_mirror_scale(custom_instance.scale.x, value)
|
||||
else:
|
||||
$TextureRect.flip_h = value
|
||||
|
||||
|
||||
func move_to_position(position_offset):
|
||||
var positions = {
|
||||
'left': Vector2(-400, 0),
|
||||
'right': Vector2(+400, 0),
|
||||
'center': Vector2(0, 0),
|
||||
'center_right': Vector2(200, 0),
|
||||
'center_left': Vector2(-200, 0)}
|
||||
|
||||
direction = position_offset
|
||||
rect_position = positions[position_offset]
|
||||
|
||||
# Setting the scale of the portrait
|
||||
var custom_scale = Vector2(1, 1)
|
||||
if character_data.has('data'):
|
||||
if character_data['data'].has('scale'):
|
||||
custom_scale = Vector2(
|
||||
float(character_data['data']['scale']) / 100,
|
||||
float(character_data['data']['scale']) / 100
|
||||
)
|
||||
rect_scale = custom_scale
|
||||
if character_data['data'].has('offset_x'):
|
||||
rect_position += Vector2(
|
||||
character_data['data']['offset_x'],
|
||||
character_data['data']['offset_y']
|
||||
)
|
||||
|
||||
if $TextureRect.get('texture'):
|
||||
rect_position -= Vector2(
|
||||
$TextureRect.texture.get_width() * 0.5,
|
||||
$TextureRect.texture.get_height()
|
||||
) * custom_scale
|
||||
|
||||
|
||||
func animate(animation_name = '[No Animation]', time = 1, loop = 1, delete = false ):
|
||||
if animation_name == "[No Animation]":
|
||||
return
|
||||
|
||||
if '_in' in animation_name:
|
||||
if custom_instance != null:
|
||||
custom_instance.modulate.a = 0
|
||||
else:
|
||||
$TextureRect.modulate = Color(1,1,1,0)
|
||||
|
||||
|
||||
$AnimationTween.loop = loop
|
||||
if custom_instance != null:
|
||||
$AnimationTween.play(custom_instance, animation_name, time)
|
||||
else:
|
||||
$AnimationTween.play($TextureRect, animation_name, time)
|
||||
|
||||
if delete:
|
||||
if !$AnimationTween.is_connected("tween_all_completed", self, "queue_free"):
|
||||
$AnimationTween.connect("tween_all_completed", self, "queue_free")
|
||||
|
||||
|
||||
func focus():
|
||||
if not fading_out:
|
||||
tween_modulate(modulate, Color(1,1,1, 1))
|
||||
|
||||
|
||||
func focusout(dim_color = Color(0.5, 0.5, 0.5, 1.0)):
|
||||
if single_portrait_mode:
|
||||
dim_color.a = 0
|
||||
if not fading_out:
|
||||
tween_modulate(modulate, dim_color)
|
||||
|
||||
|
||||
func tween_modulate(from_value, to_value):
|
||||
$ModulationTween.stop(self, 'modulation')
|
||||
$ModulationTween.interpolate_property(
|
||||
self, "modulate", from_value, to_value, dim_time,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
|
||||
)
|
||||
$ModulationTween.start()
|
||||
return $ModulationTween
|
||||
|
||||
|
||||
func is_scene(path) -> bool:
|
||||
if '.tscn' in path.to_lower():
|
||||
return true
|
||||
return false
|
||||
|
||||
func get_mirror_scale(current_scale:float, mirror_value:bool) -> int:
|
||||
if mirror_value and current_scale > 0:
|
||||
return -1
|
||||
else:
|
||||
return 1
|
@ -0,0 +1,24 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Nodes/Anima/DialogicAnimaTween.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/Portrait.gd" type="Script" id=2]
|
||||
|
||||
[node name="Portrait" type="Control"]
|
||||
rect_scale = Vector2( 0.7, 0.7 )
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="."]
|
||||
stretch_mode = 6
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="AnimationTween" type="Tween" parent="."]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="ModulationTween" type="Tween" parent="."]
|
||||
|
||||
[node name="TweenPosition" type="Tween" parent="."]
|
332
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/TextBubble.gd
Normal file
332
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/TextBubble.gd
Normal file
@ -0,0 +1,332 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var text_speed := 0.02 # Higher = lower speed
|
||||
var theme_text_speed = text_speed
|
||||
var theme_text_max_height = 0
|
||||
|
||||
#experimental database of current commands
|
||||
var commands = []
|
||||
#the regex matching object
|
||||
var regex = RegEx.new()
|
||||
var bbcoderemoverregex = RegEx.new()
|
||||
|
||||
onready var text_container = $TextContainer
|
||||
onready var text_label = $TextContainer/RichTextLabel
|
||||
onready var name_label = $NameLabel
|
||||
onready var next_indicator = $NextIndicatorContainer/NextIndicator
|
||||
|
||||
var _finished := false
|
||||
var _theme
|
||||
|
||||
signal text_completed()
|
||||
signal letter_written()
|
||||
signal signal_request(arg)
|
||||
|
||||
## *****************************************************************************
|
||||
## PUBLIC METHODS
|
||||
## *****************************************************************************
|
||||
|
||||
|
||||
func update_name(name: String, color: Color = Color.white, autocolor: bool=false) -> void:
|
||||
var name_is_hidden = _theme.get_value('name', 'is_hidden', false)
|
||||
if name_is_hidden:
|
||||
name_label.visible = false
|
||||
return
|
||||
|
||||
if not name.empty():
|
||||
name_label.visible = true
|
||||
# Hack to reset the size
|
||||
name_label.rect_min_size = Vector2(0, 0)
|
||||
name_label.rect_size = Vector2(-1, 40)
|
||||
# Setting the color and text
|
||||
name_label.text = name
|
||||
# Alignment
|
||||
call_deferred('align_name_label')
|
||||
if autocolor:
|
||||
name_label.set('custom_colors/font_color', color)
|
||||
else:
|
||||
name_label.visible = false
|
||||
|
||||
func clear():
|
||||
text_label.bbcode_text = ""
|
||||
name_label.text = ""
|
||||
$WritingTimer.stop()
|
||||
|
||||
func update_text(text:String):
|
||||
|
||||
var orig_text = text
|
||||
text_label.bbcode_text = text
|
||||
var text_bbcodefree = text_label.text
|
||||
|
||||
#regex moved from func scope to class scope
|
||||
#regex compilation moved to _ready
|
||||
# - KvaGram
|
||||
#var regex = RegEx.new()
|
||||
var result:RegExMatch = null
|
||||
text_speed = theme_text_speed # Resetting the speed to the default
|
||||
commands = []
|
||||
|
||||
### remove commands from text, and store where and what they are
|
||||
#current regex: \[\s*(nw|(nw|speed|signal|play|pause)\s*=\s*(.+?)\s*)\](.*?)
|
||||
#Note: The version defined in _ready will have aditional escape characers.
|
||||
# DO NOT JUST COPY/PASTE
|
||||
#remeber regex101.com is your friend. Do not shoot it. You may ask it to verify the code.
|
||||
#The capture groups, and what they do:
|
||||
# 0 everything ex [speed=5]
|
||||
# 1 the "nw" single command or one of the variable commands ex "nw" or "speed=5"
|
||||
# 2 the command, assuming it is an variable command ex "speed"
|
||||
# 3 the argument, again assuming a variable command ex "5"
|
||||
# 4 nothing (ignore it)
|
||||
#keep this up to date whenever the regex string is updated! - KvaGram
|
||||
|
||||
result = regex.search(text_bbcodefree)
|
||||
#loops until all commands are cleared from the text
|
||||
while result:
|
||||
if result.get_string(1) == "nw" || result.get_string(2) == "nw":
|
||||
#The no wait command is handled elsewhere. Ignore it.
|
||||
pass
|
||||
else:
|
||||
#Store an assigned varible command as an array by 0 index in text, 1 command-name, 2 argument
|
||||
commands.append([result.get_start()-1, result.get_string(2).strip_edges(), result.get_string(3).strip_edges()])
|
||||
text_bbcodefree = text_bbcodefree.substr(0, result.get_start()) + text_bbcodefree.substr(result.get_end())
|
||||
text = text.replace(result.get_string(), "")
|
||||
|
||||
result = regex.search(text_bbcodefree)
|
||||
|
||||
text_label.bbcode_text = text
|
||||
text_label.visible_characters = 0
|
||||
|
||||
## SIZING THE RICHTEXTLABEL
|
||||
# The sizing is done in a very terrible way because the RichtTextLabel has
|
||||
# a hard time knowing what size it will be and how to display this.
|
||||
# for this reason the RichTextLabel ist first set to just go for the size it needs,
|
||||
# even if this might be more than available.
|
||||
text_label.size_flags_vertical = 0
|
||||
text_label.rect_clip_content = 0
|
||||
text_label.fit_content_height = true
|
||||
# a frame later, when the sizes have been updated, it will check if there
|
||||
# is enough space or the scrollbar should be activated.
|
||||
call_deferred("update_sizing")
|
||||
|
||||
|
||||
# updating the size alignment stuff
|
||||
text_label.grab_focus()
|
||||
start_text_timer()
|
||||
return true
|
||||
|
||||
func update_sizing():
|
||||
# this will enable/disable the scrollbar based on the size of the text
|
||||
theme_text_max_height = text_container.rect_size.y
|
||||
|
||||
if text_label.rect_size.y >= theme_text_max_height:
|
||||
text_label.fit_content_height = false
|
||||
text_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
else:
|
||||
text_label.fit_content_height = true
|
||||
text_label.size_flags_vertical = 0
|
||||
|
||||
|
||||
#handle an activated command.
|
||||
func handle_command(command:Array):
|
||||
if(command[1] == "speed"):
|
||||
text_speed = float(command[2]) * 0.01
|
||||
$WritingTimer.stop()
|
||||
start_text_timer()
|
||||
elif(command[1] == "signal"):
|
||||
emit_signal("signal_request", command[2])
|
||||
elif(command[1] == "play"):
|
||||
var path = "res://dialogic/sounds/" + command[2]
|
||||
if ResourceLoader.exists(path, "AudioStream"):
|
||||
var audio:AudioStream = ResourceLoader.load(path, "AudioStream")
|
||||
$sounds.stream = audio
|
||||
$sounds.play()
|
||||
elif(command[1] == "pause"):
|
||||
$WritingTimer.stop()
|
||||
var x = text_label.visible_characters
|
||||
get_parent().get_node("DialogicTimer").start(float(command[2]))
|
||||
yield(get_parent().get_node("DialogicTimer"), "timeout")
|
||||
# only continue, if no skip was performed
|
||||
if text_label.visible_characters == x:
|
||||
start_text_timer()
|
||||
|
||||
|
||||
func skip():
|
||||
text_label.visible_characters = -1
|
||||
_handle_text_completed()
|
||||
|
||||
|
||||
func reset():
|
||||
name_label.text = ''
|
||||
name_label.visible = false
|
||||
|
||||
|
||||
func load_theme(theme: ConfigFile):
|
||||
# Text
|
||||
var theme_font = DialogicUtil.path_fixer_load(theme.get_value('text', 'font', 'res://addons/dialogic/Example Assets/Fonts/DefaultFont.tres'))
|
||||
text_label.set('custom_fonts/normal_font', theme_font)
|
||||
text_label.set('custom_fonts/bold_font', DialogicUtil.path_fixer_load(theme.get_value('text', 'bold_font', 'res://addons/dialogic/Example Assets/Fonts/DefaultBoldFont.tres')))
|
||||
text_label.set('custom_fonts/italics_font', DialogicUtil.path_fixer_load(theme.get_value('text', 'italic_font', 'res://addons/dialogic/Example Assets/Fonts/DefaultItalicFont.tres')))
|
||||
name_label.set('custom_fonts/font', DialogicUtil.path_fixer_load(theme.get_value('name', 'font', 'res://addons/dialogic/Example Assets/Fonts/NameFont.tres')))
|
||||
|
||||
# setting the vertical alignment
|
||||
var alignment = theme.get_value('text', 'alignment',0)
|
||||
if alignment <= 2: # top
|
||||
text_container.alignment = BoxContainer.ALIGN_BEGIN
|
||||
elif alignment <= 5: # center
|
||||
text_container.alignment = BoxContainer.ALIGN_CENTER
|
||||
elif alignment <= 8: # bottom
|
||||
text_container.alignment = BoxContainer.ALIGN_END
|
||||
|
||||
var text_color = Color(theme.get_value('text', 'color', '#ffffffff'))
|
||||
text_label.set('custom_colors/default_color', text_color)
|
||||
name_label.set('custom_colors/font_color', text_color)
|
||||
|
||||
text_label.set('custom_colors/font_color_shadow', Color('#00ffffff'))
|
||||
name_label.set('custom_colors/font_color_shadow', Color('#00ffffff'))
|
||||
|
||||
if theme.get_value('text', 'shadow', false):
|
||||
var text_shadow_color = Color(theme.get_value('text', 'shadow_color', '#9e000000'))
|
||||
text_label.set('custom_colors/font_color_shadow', text_shadow_color)
|
||||
|
||||
var shadow_offset = theme.get_value('text', 'shadow_offset', Vector2(2,2))
|
||||
text_label.set('custom_constants/shadow_offset_x', shadow_offset.x)
|
||||
text_label.set('custom_constants/shadow_offset_y', shadow_offset.y)
|
||||
|
||||
|
||||
# Text speed
|
||||
text_speed = theme.get_value('text','speed', 2) * 0.01
|
||||
theme_text_speed = text_speed
|
||||
|
||||
# Margin
|
||||
text_container.set('margin_left', theme.get_value('text', 'text_margin_left', 20))
|
||||
text_container.set('margin_right', theme.get_value('text', 'text_margin_right', -20))
|
||||
text_container.set('margin_top', theme.get_value('text', 'text_margin_top', 10))
|
||||
text_container.set('margin_bottom', theme.get_value('text', 'text_margin_bottom', -10))
|
||||
|
||||
# Backgrounds
|
||||
$TextureRect.texture = DialogicUtil.path_fixer_load(theme.get_value('background','image', "res://addons/dialogic/Example Assets/backgrounds/background-2.png"))
|
||||
$ColorRect.color = Color(theme.get_value('background','color', "#ff000000"))
|
||||
|
||||
if theme.get_value('background', 'modulation', false):
|
||||
$TextureRect.modulate = Color(theme.get_value('background', 'modulation_color', '#ffffffff'))
|
||||
else:
|
||||
$TextureRect.modulate = Color('#ffffffff')
|
||||
|
||||
$ColorRect.visible = theme.get_value('background', 'use_color', false)
|
||||
$TextureRect.visible = theme.get_value('background', 'use_image', true)
|
||||
$TextureRect.visible = theme.get_value('background', 'use_image', true)
|
||||
$TextureRect.patch_margin_left = theme.get_value('ninepatch', 'ninepatch_margin_left', 0)
|
||||
$TextureRect.patch_margin_right = theme.get_value('ninepatch', 'ninepatch_margin_right', 0)
|
||||
$TextureRect.patch_margin_top = theme.get_value('ninepatch', 'ninepatch_margin_top', 0)
|
||||
$TextureRect.patch_margin_bottom = theme.get_value('ninepatch', 'ninepatch_margin_bottom', 0)
|
||||
|
||||
# Next image
|
||||
$NextIndicatorContainer.rect_position = Vector2(0,0)
|
||||
next_indicator.texture = DialogicUtil.path_fixer_load(theme.get_value('next_indicator', 'image', 'res://addons/dialogic/Example Assets/next-indicator/next-indicator.png'))
|
||||
# Reset for up and down animation
|
||||
next_indicator.margin_top = 0
|
||||
next_indicator.margin_bottom = 0
|
||||
next_indicator.margin_left = 0
|
||||
next_indicator.margin_right = 0
|
||||
# Scale
|
||||
var indicator_scale = theme.get_value('next_indicator', 'scale', 0.4)
|
||||
next_indicator.rect_scale = Vector2(indicator_scale, indicator_scale)
|
||||
# Offset
|
||||
var offset = theme.get_value('next_indicator', 'offset', Vector2(13, 10))
|
||||
next_indicator.rect_position = theme.get_value('box', 'size', Vector2(910, 167)) - (next_indicator.texture.get_size() * indicator_scale)
|
||||
next_indicator.rect_position -= offset
|
||||
|
||||
# Character Name
|
||||
$NameLabel/ColorRect.visible = theme.get_value('name', 'background_visible', false)
|
||||
$NameLabel/ColorRect.color = Color(theme.get_value('name', 'background', '#282828'))
|
||||
$NameLabel/TextureRect.visible = theme.get_value('name', 'image_visible', false)
|
||||
$NameLabel/TextureRect.texture = DialogicUtil.path_fixer_load(theme.get_value('name','image', "res://addons/dialogic/Example Assets/backgrounds/background-2.png"))
|
||||
|
||||
var name_padding = theme.get_value('name', 'name_padding', Vector2( 10, 0 ))
|
||||
var name_style = name_label.get('custom_styles/normal')
|
||||
name_style.set('content_margin_left', name_padding.x)
|
||||
name_style.set('content_margin_right', name_padding.x)
|
||||
name_style.set('content_margin_bottom', name_padding.y)
|
||||
name_style.set('content_margin_top', name_padding.y)
|
||||
|
||||
var name_shadow_offset = theme.get_value('name', 'shadow_offset', Vector2(2,2))
|
||||
if theme.get_value('name', 'shadow_visible', true):
|
||||
name_label.set('custom_colors/font_color_shadow', Color(theme.get_value('name', 'shadow', '#9e000000')))
|
||||
name_label.set('custom_constants/shadow_offset_x', name_shadow_offset.x)
|
||||
name_label.set('custom_constants/shadow_offset_y', name_shadow_offset.y)
|
||||
name_label.rect_position.y = theme.get_value('name', 'bottom_gap', 48) * -1 - (name_padding.y)
|
||||
if theme.get_value('name', 'modulation', false) == true:
|
||||
$NameLabel/TextureRect.modulate = Color(theme.get_value('name', 'modulation_color', '#ffffffff'))
|
||||
else:
|
||||
$NameLabel/TextureRect.modulate = Color('#ffffffff')
|
||||
|
||||
|
||||
# Setting next indicator animation
|
||||
next_indicator.self_modulate = Color('#ffffff')
|
||||
var animation = theme.get_value('next_indicator', 'animation', 'Up and down')
|
||||
next_indicator.get_node('AnimationPlayer').play(animation)
|
||||
|
||||
# Saving reference to the current theme
|
||||
_theme = theme
|
||||
|
||||
## *****************************************************************************
|
||||
## PRIVATE METHODS
|
||||
## *****************************************************************************
|
||||
|
||||
|
||||
func _on_writing_timer_timeout():
|
||||
if _finished == false:
|
||||
text_label.visible_characters += 1
|
||||
if(commands.size()>0 && commands[0][0] <= text_label.visible_characters):
|
||||
handle_command(commands.pop_front()) #handles the command, and removes it from the queue
|
||||
if text_label.visible_characters > text_label.get_total_character_count():
|
||||
_handle_text_completed()
|
||||
elif (
|
||||
text_label.visible_characters > 0 and
|
||||
#text_label.text.length() > text_label.visible_characters-1 and
|
||||
text_label.text[text_label.visible_characters-1] != " "
|
||||
):
|
||||
emit_signal('letter_written')
|
||||
else:
|
||||
$WritingTimer.stop()
|
||||
|
||||
|
||||
func start_text_timer():
|
||||
if text_speed == 0:
|
||||
text_label.visible_characters = -1
|
||||
_handle_text_completed()
|
||||
else:
|
||||
$WritingTimer.start(text_speed)
|
||||
_finished = false
|
||||
|
||||
|
||||
func _handle_text_completed():
|
||||
$WritingTimer.stop()
|
||||
_finished = true
|
||||
emit_signal("text_completed")
|
||||
|
||||
|
||||
func align_name_label():
|
||||
var name_padding = _theme.get_value('name', 'name_padding', Vector2( 10, 0 ))
|
||||
var horizontal_offset = _theme.get_value('name', 'horizontal_offset', 0)
|
||||
var name_label_position = _theme.get_value('name', 'position', 0)
|
||||
var label_size = name_label.rect_size.x
|
||||
if name_label_position == 0:
|
||||
name_label.rect_global_position.x = rect_global_position.x + horizontal_offset
|
||||
elif name_label_position == 1: # Center
|
||||
name_label.rect_global_position.x = rect_global_position.x + (rect_size.x / 2) - (label_size / 2) + horizontal_offset
|
||||
elif name_label_position == 2: # Right
|
||||
name_label.rect_global_position.x = rect_global_position.x + rect_size.x - label_size + horizontal_offset
|
||||
|
||||
## *****************************************************************************
|
||||
## OVERRIDES
|
||||
## *****************************************************************************
|
||||
|
||||
|
||||
func _ready():
|
||||
reset()
|
||||
$WritingTimer.connect("timeout", self, "_on_writing_timer_timeout")
|
||||
text_label.meta_underlined = false
|
||||
regex.compile("\\[\\s*(nw|(nw|speed|signal|play|pause)\\s*=\\s*(.+?)\\s*)\\](.*?)")
|
||||
|
194
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/TextBubble.tscn
Normal file
194
Phase2/Godot_Toolset/Luke/addons/dialogic/Nodes/TextBubble.tscn
Normal file
@ -0,0 +1,194 @@
|
||||
[gd_scene load_steps=11 format=2]
|
||||
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/Fonts/DefaultFont.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/backgrounds/background-2.png" type="Texture" id=2]
|
||||
[ext_resource path="res://addons/dialogic/Example Assets/next-indicator/next-indicator.png" type="Texture" id=3]
|
||||
[ext_resource path="res://addons/dialogic/Nodes/TextBubble.gd" type="Script" id=4]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id=1]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=2]
|
||||
bg_color = Color( 1, 1, 1, 0 )
|
||||
expand_margin_left = 10.0
|
||||
|
||||
[sub_resource type="Animation" id=3]
|
||||
loop = true
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath(".:self_modulate")
|
||||
tracks/0/interp = 2
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0, 0.5 ),
|
||||
"transitions": PoolRealArray( 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Color( 1, 1, 1, 1 ), Color( 1, 1, 1, 0 ) ]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id=4]
|
||||
|
||||
[sub_resource type="Animation" id=5]
|
||||
loop = true
|
||||
tracks/0/type = "value"
|
||||
tracks/0/path = NodePath("..:rect_position")
|
||||
tracks/0/interp = 2
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/keys = {
|
||||
"times": PoolRealArray( 0, 0.5 ),
|
||||
"transitions": PoolRealArray( 1, 1 ),
|
||||
"update": 0,
|
||||
"values": [ Vector2( 0, 0 ), Vector2( 0, -10 ) ]
|
||||
}
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=6]
|
||||
content_margin_left = 10.0
|
||||
content_margin_right = 10.0
|
||||
content_margin_top = 0.0
|
||||
content_margin_bottom = 0.0
|
||||
bg_color = Color( 1, 1, 1, 0 )
|
||||
expand_margin_left = 10.0
|
||||
|
||||
[node name="TextBubble" type="Control"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -455.0
|
||||
margin_top = 399.0
|
||||
margin_right = 455.0
|
||||
margin_bottom = 560.0
|
||||
script = ExtResource( 4 )
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color( 0, 0, 0, 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TextureRect" type="NinePatchRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
texture = ExtResource( 2 )
|
||||
|
||||
[node name="TextContainer" type="VBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = 12.0
|
||||
margin_right = -10.0
|
||||
margin_bottom = -12.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="TextContainer"]
|
||||
margin_top = 11.0
|
||||
margin_right = 890.0
|
||||
margin_bottom = 125.0
|
||||
focus_mode = 2
|
||||
custom_colors/default_color = Color( 1, 1, 1, 1 )
|
||||
custom_colors/selection_color = Color( 0, 0, 0, 0 )
|
||||
custom_colors/font_color_shadow = Color( 1, 1, 1, 0 )
|
||||
custom_constants/shadow_offset_x = 2
|
||||
custom_constants/shadow_offset_y = 2
|
||||
custom_fonts/normal_font = ExtResource( 1 )
|
||||
custom_styles/focus = SubResource( 1 )
|
||||
custom_styles/normal = SubResource( 2 )
|
||||
bbcode_enabled = true
|
||||
bbcode_text = "Placeholder text for testing an formatting.
|
||||
Placeholder text for testing an formatting.
|
||||
adsd"
|
||||
visible_characters = 0
|
||||
percent_visible = 0.0
|
||||
meta_underlined = false
|
||||
text = "Placeholder text for testing an formatting.
|
||||
Placeholder text for testing an formatting.
|
||||
adsd"
|
||||
fit_content_height = true
|
||||
selection_enabled = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="NextIndicatorContainer" type="Control" parent="."]
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="NextIndicator" type="TextureRect" parent="NextIndicatorContainer"]
|
||||
margin_top = -10.0
|
||||
margin_right = 51.0
|
||||
margin_bottom = 41.0
|
||||
texture = ExtResource( 3 )
|
||||
stretch_mode = 4
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="NextIndicatorContainer/NextIndicator"]
|
||||
autoplay = "Up and down"
|
||||
anims/Pulse = SubResource( 3 )
|
||||
anims/Static = SubResource( 4 )
|
||||
"anims/Up and down" = SubResource( 5 )
|
||||
|
||||
[node name="NameLabel" type="Label" parent="."]
|
||||
visible = false
|
||||
margin_top = -48.0
|
||||
margin_right = 58.0
|
||||
margin_bottom = -8.0
|
||||
size_flags_vertical = 1
|
||||
custom_colors/font_color = Color( 0.423529, 0.580392, 0.74902, 1 )
|
||||
custom_colors/font_color_shadow = Color( 0, 0, 0, 0.619608 )
|
||||
custom_constants/shadow_offset_x = 2
|
||||
custom_constants/shadow_offset_y = 2
|
||||
custom_fonts/font = ExtResource( 1 )
|
||||
custom_styles/normal = SubResource( 6 )
|
||||
align = 1
|
||||
valign = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ColorRect" type="ColorRect" parent="NameLabel"]
|
||||
visible = false
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 15
|
||||
size_flags_vertical = 15
|
||||
color = Color( 0.156863, 0.156863, 0.156863, 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="NameLabel"]
|
||||
visible = false
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
texture = ExtResource( 2 )
|
||||
expand = true
|
||||
stretch_mode = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="WritingTimer" type="Timer" parent="."]
|
||||
|
||||
[node name="Tween" type="Tween" parent="."]
|
||||
|
||||
[node name="sounds" type="AudioStreamPlayer" parent="."]
|
||||
autoplay = true
|
@ -0,0 +1,78 @@
|
||||
extends CanvasLayer
|
||||
|
||||
## Mirror node to Dialogic node that duplicate its signals
|
||||
## and had a reference to that Dialogic node
|
||||
|
||||
# Copied
|
||||
# Event end/start
|
||||
signal event_start(type, event)
|
||||
signal event_end(type)
|
||||
# Timeline end/start
|
||||
signal timeline_start(timeline_name)
|
||||
signal timeline_end(timeline_name)
|
||||
signal text_complete(text_event)
|
||||
# Custom user signal
|
||||
signal dialogic_signal(value)
|
||||
|
||||
|
||||
var _dialog_node_scene = load("res://addons/dialogic/Nodes/DialogNode.tscn")
|
||||
var dialog_node = null
|
||||
|
||||
|
||||
func set_dialog_node_scene(scene) -> void:
|
||||
_dialog_node_scene = scene
|
||||
dialog_node = _dialog_node_scene.instance()
|
||||
var _err:int
|
||||
if dialog_node:
|
||||
_err = dialog_node.connect("event_start", self, "_on_event_start")
|
||||
assert(_err == OK)
|
||||
_err = dialog_node.connect("event_end", self, "_on_event_end")
|
||||
assert(_err == OK)
|
||||
_err = dialog_node.connect("timeline_start", self, "_on_timeline_start")
|
||||
assert(_err == OK)
|
||||
_err = dialog_node.connect("timeline_end", self, "_on_timeline_end")
|
||||
assert(_err == OK)
|
||||
_err = dialog_node.connect("text_complete", self, "_on_text_complete")
|
||||
assert(_err == OK)
|
||||
_err = dialog_node.connect("dialogic_signal", self, "_on_dialogic_signal")
|
||||
assert(_err == OK)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
if dialog_node:
|
||||
add_child(dialog_node)
|
||||
dialog_node.connect('tree_exited', self, 'dialog_finished')
|
||||
|
||||
func dialog_finished():
|
||||
queue_free()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# change the canvas layer
|
||||
var config = DialogicResources.get_settings_config()
|
||||
layer = int(config.get_value("theme", "canvas_layer", 1))
|
||||
|
||||
|
||||
|
||||
|
||||
func _on_event_start(type, event) -> void:
|
||||
emit_signal("event_start", type, event)
|
||||
|
||||
|
||||
func _on_event_end(type) -> void:
|
||||
emit_signal("event_end", type)
|
||||
|
||||
|
||||
func _on_timeline_start(timeline_name) -> void:
|
||||
emit_signal("timeline_start", timeline_name)
|
||||
|
||||
|
||||
func _on_timeline_end(timeline_name) -> void:
|
||||
emit_signal("timeline_end", timeline_name)
|
||||
|
||||
|
||||
func _on_text_complete(text_event) -> void:
|
||||
emit_signal("text_complete", text_event)
|
||||
|
||||
|
||||
func _on_dialogic_signal(value) -> void:
|
||||
emit_signal("dialogic_signal", value)
|
@ -0,0 +1,66 @@
|
||||
tool
|
||||
extends PanelContainer
|
||||
|
||||
onready var nodes = {
|
||||
'title': $VBoxContainer/Title,
|
||||
'body': $VBoxContainer/Content,
|
||||
'extra': $VBoxContainer/Extra,
|
||||
}
|
||||
|
||||
var in_theme_editor = false
|
||||
var margin = 10
|
||||
|
||||
|
||||
func _ready():
|
||||
set_deferred('rect_size.y', 0)
|
||||
nodes['title'].bbcode_enabled = true
|
||||
nodes['body'].bbcode_enabled = true
|
||||
nodes['extra'].bbcode_enabled = true
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
if Engine.is_editor_hint() == false or in_theme_editor == true:
|
||||
if visible:
|
||||
if get_global_mouse_position().x < get_viewport().size.x * 0.5:
|
||||
rect_global_position = get_global_mouse_position() - Vector2(0, rect_size.y + (margin * 2))
|
||||
else:
|
||||
rect_global_position = get_global_mouse_position() - rect_size - Vector2(0, (margin * 2))
|
||||
rect_size.y = 0
|
||||
#
|
||||
|
||||
func load_preview(info):
|
||||
nodes['title'].visible = false
|
||||
nodes['body'].visible = false
|
||||
nodes['extra'].visible = false
|
||||
|
||||
if info['title'] != '':
|
||||
nodes['title'].bbcode_text = info['title']
|
||||
nodes['title'].visible = true
|
||||
|
||||
if info['body'] != '':
|
||||
nodes['body'].bbcode_text = info['body']
|
||||
nodes['body'].visible = true
|
||||
|
||||
if info['extra'] != '':
|
||||
nodes['extra'].bbcode_text = info['extra']
|
||||
nodes['extra'].visible = true
|
||||
|
||||
|
||||
func load_theme(theme):
|
||||
# Fonts
|
||||
$VBoxContainer/Title.set(
|
||||
'custom_fonts/normal_font',
|
||||
DialogicUtil.path_fixer_load(theme.get_value('definitions', 'font', "res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres")))
|
||||
$VBoxContainer/Title.set('custom_colors/default_color', theme.get_value('definitions', 'title_color', "#ffffffff"))
|
||||
|
||||
$VBoxContainer/Content.set(
|
||||
'custom_fonts/normal_font',
|
||||
DialogicUtil.path_fixer_load(theme.get_value('definitions', 'text_font', "res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres")))
|
||||
$VBoxContainer/Content.set('custom_colors/default_color', theme.get_value('definitions', 'text_color', "#c1c1c1"))
|
||||
|
||||
$VBoxContainer/Extra.set(
|
||||
'custom_fonts/normal_font',
|
||||
DialogicUtil.path_fixer_load(theme.get_value('definitions', 'extra_font', "res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres")))
|
||||
$VBoxContainer/Extra.set('custom_colors/default_color', theme.get_value('definitions', 'extra_color', "#c1c1c1"))
|
||||
|
||||
set("custom_styles/panel", load(theme.get_value('definitions', 'background_panel', "res://addons/dialogic/Example Assets/backgrounds/GlossaryBackground.tres")))
|
@ -0,0 +1,91 @@
|
||||
# Random Audio Stream PLayer Godot Engine Add-on
|
||||
# Copyright (c) Tim Krief.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
tool
|
||||
extends AudioStreamPlayer
|
||||
|
||||
export(Array, AudioStream) var samples = []
|
||||
export(String, DIR) var select_samples_from_folder setget load_samples_from_folder
|
||||
export(int, "Pure", "No consecutive repetition", "Use all samples before repeat") var random_strategy = 0
|
||||
onready var base_volume = volume_db
|
||||
export(float, 0, 80) var random_volume_range = 0
|
||||
onready var base_pitch = pitch_scale
|
||||
export(float, 0, 4) var random_pitch_range = 0
|
||||
|
||||
var playing_sample_nb : int = -1
|
||||
var last_played_sample_nb : int = -1 # only used if random_strategy = 1
|
||||
var to_play = [] # only used if random_strategy = 2
|
||||
|
||||
# You can use playing_sample_nb to choose what sample to use
|
||||
func play(from_position=0.0, playing_sample_nb=-1):
|
||||
var number_of_samples = len(samples)
|
||||
if number_of_samples > 0:
|
||||
if playing_sample_nb < 0:
|
||||
if number_of_samples == 1:
|
||||
playing_sample_nb = 0
|
||||
else:
|
||||
match random_strategy:
|
||||
1:
|
||||
playing_sample_nb = randi() % (number_of_samples - 1)
|
||||
if last_played_sample_nb == playing_sample_nb:
|
||||
playing_sample_nb += 1
|
||||
last_played_sample_nb = playing_sample_nb
|
||||
2:
|
||||
if len(to_play) == 0:
|
||||
for i in range(number_of_samples):
|
||||
if i != last_played_sample_nb:
|
||||
to_play.append(i)
|
||||
to_play.shuffle()
|
||||
playing_sample_nb = to_play.pop_back()
|
||||
last_played_sample_nb = playing_sample_nb
|
||||
_:
|
||||
playing_sample_nb = randi() % number_of_samples
|
||||
if random_volume_range != 0:
|
||||
.set_volume_db(base_volume + (randf() - .5) * random_volume_range)
|
||||
if random_pitch_range != 0:
|
||||
.set_pitch_scale(max(0.0001, base_pitch + (randf() - .5) * random_pitch_range))
|
||||
set_stream(samples[playing_sample_nb])
|
||||
.play(from_position)
|
||||
|
||||
func set_volume_db(new_volume_db):
|
||||
.set_volume_db(new_volume_db)
|
||||
base_volume = new_volume_db
|
||||
|
||||
func set_pitch_scale(new_pitch):
|
||||
.set_pitch_scale(max(0.0001, new_pitch))
|
||||
base_pitch = new_pitch
|
||||
|
||||
func load_samples_from_folder(path):
|
||||
if path != "":
|
||||
samples.clear()
|
||||
var dir = Directory.new()
|
||||
if dir.open(path) == OK:
|
||||
dir.list_dir_begin(true)
|
||||
var file_name = dir.get_next()
|
||||
while file_name != "":
|
||||
if not dir.current_is_dir() and file_name.ends_with(".import"):
|
||||
var resource_path = dir.get_current_dir() + "/" + file_name.replace('.import', '')
|
||||
if resource_path.get_extension().to_lower() in ["wav", "ogg"]:
|
||||
var resource = load(resource_path)
|
||||
if resource != null:
|
||||
samples.append(resource)
|
||||
file_name = dir.get_next()
|
||||
select_samples_from_folder = ""
|
Reference in New Issue
Block a user