Rebrand project and refresh title presentation
|
Before Width: | Height: | Size: 22 KiB |
BIN
ui/assets/title/straywild_logo.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
42
ui/assets/title/straywild_logo.png.import
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dwe5p5t0ode73"
|
||||
path.s3tc="res://.godot/imported/straywild_logo.png-de66accac60dbd31604d2c39ab8d2775.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/straywild_logo.png-de66accac60dbd31604d2c39ab8d2775.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/assets/title/straywild_logo.png"
|
||||
dest_files=["res://.godot/imported/straywild_logo.png-de66accac60dbd31604d2c39ab8d2775.s3tc.ctex", "res://.godot/imported/straywild_logo.png-de66accac60dbd31604d2c39ab8d2775.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
|
|
@ -2,6 +2,13 @@ class_name BubbleButton
|
|||
extends Button
|
||||
|
||||
const ICON_FILL_RATIO: float = 0.76
|
||||
const LABELED_ICON_FILL_RATIO: float = 0.58
|
||||
const BubbleGradientBackgroundType = preload(
|
||||
"res://ui/components/bubble_menu/bubble_gradient_background.gd"
|
||||
)
|
||||
const BubbleHoverDrawerType = preload(
|
||||
"res://ui/components/bubble_menu/bubble_hover_drawer.gd"
|
||||
)
|
||||
|
||||
@export var profile: BubbleMenuProfile
|
||||
|
||||
|
|
@ -16,6 +23,9 @@ const ICON_FILL_RATIO: float = 0.76
|
|||
@export_range(1, 256, 1) var minimum_font_size: int = 14
|
||||
@export_range(1, 256, 1) var maximum_font_size: int = 32
|
||||
|
||||
@export_group("Icon")
|
||||
@export_range(0.0, 1.0, 0.01) var icon_fill_ratio_override: float = 0.0
|
||||
|
||||
@export_group("Motion")
|
||||
@export_range(0.0, 32.0, 0.1) var horizontal_amplitude: float = 1.8
|
||||
@export_range(0.0, 32.0, 0.1) var vertical_amplitude: float = 4.0
|
||||
|
|
@ -23,20 +33,37 @@ const ICON_FILL_RATIO: float = 0.76
|
|||
@export_range(0.0, TAU, 0.01) var motion_phase: float = 0.0
|
||||
@export_range(0.0, 0.2, 0.001) var deformation_amplitude: float = 0.016
|
||||
@export_range(0.1, 30.0, 0.1) var deformation_period: float = 6.0
|
||||
@export var hover_wiggle_amplitude: Vector2 = Vector2.ZERO
|
||||
@export_range(0.1, 30.0, 0.1) var hover_wiggle_period: float = 2.0
|
||||
|
||||
@export_group("Hover Drawer")
|
||||
@export var hover_drawer_text: String = ""
|
||||
@export_enum("Right", "Left Vertical") var hover_drawer_mode: int = 0
|
||||
@export_range(0.1, 12.0, 0.1) var hover_drawer_speed: float = 4.0
|
||||
|
||||
@export_group("Hit Area")
|
||||
@export var elliptical_hit_area: bool = true
|
||||
|
||||
var neutral_position: Vector2 = Vector2.ZERO
|
||||
var presented_size: Vector2 = Vector2.ZERO
|
||||
var emphasis: float = 0.0
|
||||
var _hovered: bool = false
|
||||
var _drawer_focused: bool = false
|
||||
var _drawer_reveal: float = 0.0
|
||||
var _gradient_background: BubbleGradientBackground
|
||||
var _hover_drawer: BubbleHoverDrawer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_entered.connect(_set_hovered.bind(true))
|
||||
mouse_exited.connect(_set_hovered.bind(false))
|
||||
focus_entered.connect(_set_drawer_focused.bind(true))
|
||||
focus_exited.connect(_set_drawer_focused.bind(false))
|
||||
resized.connect(_update_pivot)
|
||||
_update_pivot()
|
||||
apply_profile()
|
||||
_apply_icon_presentation(neutral_size)
|
||||
_update_hover_drawer()
|
||||
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
|
|
@ -97,6 +124,8 @@ func apply_layout(
|
|||
presented_size = bubble_size
|
||||
_update_pivot()
|
||||
_apply_icon_presentation(bubble_size)
|
||||
if _hover_drawer != null:
|
||||
_hover_drawer.refresh_layout()
|
||||
var label_control: Control = get_label_control()
|
||||
var font_size := clampi(
|
||||
roundi(minf(bubble_size.x, bubble_size.y) * font_size_ratio),
|
||||
|
|
@ -134,17 +163,26 @@ func _uses_icon_only_presentation() -> bool:
|
|||
|
||||
|
||||
func _apply_icon_presentation(bubble_size: Vector2) -> void:
|
||||
if icon == null:
|
||||
return
|
||||
vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
expand_icon = true
|
||||
texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
var fill_ratio: float = (
|
||||
ICON_FILL_RATIO
|
||||
if _uses_icon_only_presentation()
|
||||
else LABELED_ICON_FILL_RATIO
|
||||
)
|
||||
if _uses_icon_only_presentation() and icon_fill_ratio_override > 0.0:
|
||||
fill_ratio = icon_fill_ratio_override
|
||||
add_theme_constant_override(
|
||||
"icon_max_width",
|
||||
maxi(1, roundi(minf(bubble_size.x, bubble_size.y) * fill_ratio)),
|
||||
)
|
||||
if not _uses_icon_only_presentation():
|
||||
return
|
||||
alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
expand_icon = true
|
||||
texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
add_theme_constant_override(
|
||||
"icon_max_width",
|
||||
maxi(1, roundi(minf(bubble_size.x, bubble_size.y) * ICON_FILL_RATIO)),
|
||||
)
|
||||
|
||||
|
||||
func advance_emphasis(delta: float) -> void:
|
||||
|
|
@ -154,6 +192,27 @@ func advance_emphasis(delta: float) -> void:
|
|||
target,
|
||||
profile.emphasis_speed * delta
|
||||
)
|
||||
if _gradient_background != null:
|
||||
_gradient_background.queue_redraw()
|
||||
var drawer_target: float = 1.0 if (_hovered or _drawer_focused) else 0.0
|
||||
_drawer_reveal = move_toward(
|
||||
_drawer_reveal,
|
||||
drawer_target,
|
||||
hover_drawer_speed * delta,
|
||||
)
|
||||
if _hover_drawer != null:
|
||||
_hover_drawer.set_reveal(_drawer_reveal)
|
||||
|
||||
|
||||
func reset_hover_presentation() -> void:
|
||||
_hovered = false
|
||||
_drawer_focused = false
|
||||
emphasis = 0.0
|
||||
_drawer_reveal = 0.0
|
||||
if _gradient_background != null:
|
||||
_gradient_background.queue_redraw()
|
||||
if _hover_drawer != null:
|
||||
_hover_drawer.set_reveal(0.0)
|
||||
|
||||
|
||||
func calculate_target(
|
||||
|
|
@ -169,12 +228,17 @@ func calculate_target(
|
|||
sin(phase * 0.73 + motion_phase) * horizontal_amplitude,
|
||||
sin(phase) * vertical_amplitude
|
||||
) * layout_scale * motion_scale
|
||||
var hover_phase: float = elapsed / hover_wiggle_period * TAU
|
||||
var hover_offset := Vector2(
|
||||
sin(hover_phase),
|
||||
sin(hover_phase * 2.0 + motion_phase) * 0.5,
|
||||
) * hover_wiggle_amplitude * emphasis * layout_scale * motion_scale
|
||||
idle_offset.y -= (
|
||||
profile.hover_focus_lift
|
||||
* emphasis
|
||||
* layout_scale
|
||||
)
|
||||
return neutral_position + idle_offset
|
||||
return neutral_position + idle_offset + hover_offset
|
||||
|
||||
|
||||
func calculate_visual_scale(
|
||||
|
|
@ -219,6 +283,8 @@ func apply_presentation(
|
|||
|
||||
|
||||
func _has_point(point: Vector2) -> bool:
|
||||
if not elliptical_hit_area:
|
||||
return Rect2(Vector2.ZERO, size).has_point(point)
|
||||
var radius: Vector2 = size * 0.5
|
||||
if radius.x <= 0.0 or radius.y <= 0.0:
|
||||
return false
|
||||
|
|
@ -228,6 +294,12 @@ func _has_point(point: Vector2) -> bool:
|
|||
|
||||
func _set_hovered(value: bool) -> void:
|
||||
_hovered = value
|
||||
if _gradient_background != null:
|
||||
_gradient_background.queue_redraw()
|
||||
|
||||
|
||||
func _set_drawer_focused(value: bool) -> void:
|
||||
_drawer_focused = value
|
||||
|
||||
|
||||
func _update_pivot() -> void:
|
||||
|
|
@ -237,6 +309,7 @@ func _update_pivot() -> void:
|
|||
func apply_profile() -> void:
|
||||
if profile == null:
|
||||
return
|
||||
_update_gradient_background()
|
||||
add_theme_stylebox_override("normal", profile.make_normal_style())
|
||||
var hover_style: StyleBoxFlat = profile.make_hover_style()
|
||||
add_theme_stylebox_override("hover", hover_style)
|
||||
|
|
@ -251,3 +324,35 @@ func apply_profile() -> void:
|
|||
var label_control: Control = get_label_control()
|
||||
if label_control != self:
|
||||
label_control.add_theme_color_override("font_color", profile.text_color)
|
||||
|
||||
|
||||
func _update_gradient_background() -> void:
|
||||
if not profile.gradient_enabled:
|
||||
if _gradient_background != null:
|
||||
_gradient_background.queue_free()
|
||||
_gradient_background = null
|
||||
return
|
||||
if _gradient_background == null:
|
||||
_gradient_background = BubbleGradientBackgroundType.new()
|
||||
_gradient_background.name = "GradientBackground"
|
||||
add_child(_gradient_background)
|
||||
move_child(_gradient_background, 0)
|
||||
_gradient_background.configure(self, profile)
|
||||
|
||||
|
||||
func _update_hover_drawer() -> void:
|
||||
if hover_drawer_text.is_empty():
|
||||
if _hover_drawer != null:
|
||||
_hover_drawer.queue_free()
|
||||
_hover_drawer = null
|
||||
return
|
||||
if _hover_drawer == null:
|
||||
_hover_drawer = BubbleHoverDrawerType.new()
|
||||
_hover_drawer.name = "HoverDrawer"
|
||||
add_child(_hover_drawer)
|
||||
move_child(_hover_drawer, 0)
|
||||
_hover_drawer.configure(
|
||||
self,
|
||||
hover_drawer_text,
|
||||
hover_drawer_mode as BubbleHoverDrawer.DrawerMode,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const ControllerFocusNavigationType = preload(
|
|||
@export var desktop_reference_size: Vector2 = Vector2(396.0, 318.0)
|
||||
@export var compact_reference_size: Vector2 = Vector2(294.0, 200.0)
|
||||
@export_range(0.0, 1.0, 0.01) var motion_scale: float = 1.0
|
||||
@export var collision_separation_enabled: bool = true
|
||||
|
||||
var _bubbles: Array[BubbleButton] = []
|
||||
var _elapsed: float = 0.0
|
||||
|
|
@ -70,39 +71,40 @@ func advance_motion(delta: float) -> void:
|
|||
targets.append(target)
|
||||
visual_scales.append(visual_scale)
|
||||
visual_radii.append(bubble.get_visual_radius(visual_scale))
|
||||
for first_index: int in _bubbles.size():
|
||||
for second_index: int in range(first_index + 1, _bubbles.size()):
|
||||
var first_center: Vector2 = (
|
||||
targets[first_index]
|
||||
+ _bubbles[first_index].presented_size * 0.5
|
||||
)
|
||||
var second_center: Vector2 = (
|
||||
targets[second_index]
|
||||
+ _bubbles[second_index].presented_size * 0.5
|
||||
)
|
||||
var center_delta: Vector2 = second_center - first_center
|
||||
var distance: float = center_delta.length()
|
||||
var desired_distance: float = (
|
||||
visual_radii[first_index]
|
||||
+ visual_radii[second_index]
|
||||
+ profile.contact_gap * _layout_scale
|
||||
)
|
||||
if distance >= desired_distance:
|
||||
continue
|
||||
var direction := (
|
||||
center_delta / distance
|
||||
if distance > 0.001
|
||||
else Vector2.RIGHT.rotated(float(first_index + 1))
|
||||
)
|
||||
var correction: Vector2 = (
|
||||
direction
|
||||
* minf(
|
||||
(desired_distance - distance) * 0.5,
|
||||
profile.maximum_separation * _layout_scale
|
||||
if collision_separation_enabled:
|
||||
for first_index: int in _bubbles.size():
|
||||
for second_index: int in range(first_index + 1, _bubbles.size()):
|
||||
var first_center: Vector2 = (
|
||||
targets[first_index]
|
||||
+ _bubbles[first_index].presented_size * 0.5
|
||||
)
|
||||
)
|
||||
targets[first_index] -= correction
|
||||
targets[second_index] += correction
|
||||
var second_center: Vector2 = (
|
||||
targets[second_index]
|
||||
+ _bubbles[second_index].presented_size * 0.5
|
||||
)
|
||||
var center_delta: Vector2 = second_center - first_center
|
||||
var distance: float = center_delta.length()
|
||||
var desired_distance: float = (
|
||||
visual_radii[first_index]
|
||||
+ visual_radii[second_index]
|
||||
+ profile.contact_gap * _layout_scale
|
||||
)
|
||||
if distance >= desired_distance:
|
||||
continue
|
||||
var direction := (
|
||||
center_delta / distance
|
||||
if distance > 0.001
|
||||
else Vector2.RIGHT.rotated(float(first_index + 1))
|
||||
)
|
||||
var correction: Vector2 = (
|
||||
direction
|
||||
* minf(
|
||||
(desired_distance - distance) * 0.5,
|
||||
profile.maximum_separation * _layout_scale
|
||||
)
|
||||
)
|
||||
targets[first_index] -= correction
|
||||
targets[second_index] += correction
|
||||
var position_weight: float = 1.0 - exp(
|
||||
-profile.position_response * delta
|
||||
)
|
||||
|
|
|
|||
79
ui/components/bubble_menu/bubble_gradient_background.gd
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
class_name BubbleGradientBackground
|
||||
extends Control
|
||||
|
||||
const CORNER_SEGMENTS: int = 8
|
||||
|
||||
var host_button: BaseButton
|
||||
var profile: BubbleMenuProfile
|
||||
|
||||
|
||||
func configure(
|
||||
button: BaseButton,
|
||||
menu_profile: BubbleMenuProfile,
|
||||
) -> void:
|
||||
host_button = button
|
||||
profile = menu_profile
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
show_behind_parent = true
|
||||
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if host_button == null or profile == null or size.x <= 0.0 or size.y <= 0.0:
|
||||
return
|
||||
var fill_color: Color = _get_fill_color()
|
||||
var top_color: Color = fill_color.lightened(profile.gradient_top_lift)
|
||||
var points := PackedVector2Array()
|
||||
_append_arc(points, Vector2(profile.corner_radius, profile.corner_radius), PI, PI * 1.5)
|
||||
_append_arc(
|
||||
points,
|
||||
Vector2(size.x - profile.corner_radius, profile.corner_radius),
|
||||
PI * 1.5,
|
||||
TAU,
|
||||
)
|
||||
_append_arc(
|
||||
points,
|
||||
Vector2(size.x - profile.corner_radius, size.y - profile.corner_radius),
|
||||
0.0,
|
||||
PI * 0.5,
|
||||
)
|
||||
_append_arc(
|
||||
points,
|
||||
Vector2(profile.corner_radius, size.y - profile.corner_radius),
|
||||
PI * 0.5,
|
||||
PI,
|
||||
)
|
||||
var colors := PackedColorArray()
|
||||
for point: Vector2 in points:
|
||||
colors.append(top_color.lerp(fill_color, clampf(point.y / size.y, 0.0, 1.0)))
|
||||
draw_polygon(points, colors)
|
||||
|
||||
|
||||
func _append_arc(
|
||||
points: PackedVector2Array,
|
||||
center: Vector2,
|
||||
start_angle: float,
|
||||
end_angle: float,
|
||||
) -> void:
|
||||
var radius: float = minf(
|
||||
float(profile.corner_radius),
|
||||
minf(size.x, size.y) * 0.5,
|
||||
)
|
||||
for index: int in range(CORNER_SEGMENTS + 1):
|
||||
var weight: float = float(index) / float(CORNER_SEGMENTS)
|
||||
var angle: float = lerpf(start_angle, end_angle, weight)
|
||||
points.append(center + Vector2(cos(angle), sin(angle)) * radius)
|
||||
|
||||
|
||||
func _get_fill_color() -> Color:
|
||||
if host_button.disabled:
|
||||
return profile.disabled_fill
|
||||
match host_button.get_draw_mode():
|
||||
BaseButton.DRAW_PRESSED, BaseButton.DRAW_HOVER_PRESSED:
|
||||
return profile.pressed_fill
|
||||
BaseButton.DRAW_HOVER:
|
||||
return profile.hover_fill
|
||||
if host_button.has_focus():
|
||||
return profile.hover_fill
|
||||
return profile.normal_fill
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cckk3lwdqadjn
|
||||
97
ui/components/bubble_menu/bubble_hover_drawer.gd
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
class_name BubbleHoverDrawer
|
||||
extends Control
|
||||
|
||||
enum DrawerMode {
|
||||
RIGHT,
|
||||
LEFT_VERTICAL,
|
||||
}
|
||||
|
||||
const DRAWER_COLOR: Color = Color(0.031, 0.122, 0.169, 1.0)
|
||||
const TEXT_COLOR: Color = Color(0.764706, 0.87451, 0.901961, 1.0)
|
||||
const RIGHT_SIZE: Vector2 = Vector2(132.0, 48.0)
|
||||
const LEFT_VERTICAL_SIZE: Vector2 = Vector2(50.0, 176.0)
|
||||
const OVERLAP: float = 12.0
|
||||
|
||||
var host_button: BaseButton
|
||||
var drawer_mode: DrawerMode = DrawerMode.RIGHT
|
||||
var _panel: Panel
|
||||
var _label: Label
|
||||
|
||||
|
||||
func configure(
|
||||
button: BaseButton,
|
||||
drawer_text: String,
|
||||
mode: DrawerMode,
|
||||
) -> void:
|
||||
host_button = button
|
||||
drawer_mode = mode
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
show_behind_parent = true
|
||||
_build_controls()
|
||||
_label.text = drawer_text
|
||||
_refresh_label_layout()
|
||||
refresh_layout()
|
||||
set_reveal(0.0)
|
||||
|
||||
|
||||
func refresh_layout() -> void:
|
||||
if host_button == null:
|
||||
return
|
||||
if drawer_mode == DrawerMode.RIGHT:
|
||||
size = RIGHT_SIZE
|
||||
position = Vector2(
|
||||
host_button.size.x - OVERLAP,
|
||||
(host_button.size.y - size.y) * 0.5,
|
||||
)
|
||||
pivot_offset = Vector2(0.0, size.y * 0.5)
|
||||
else:
|
||||
size = LEFT_VERTICAL_SIZE
|
||||
position = Vector2(
|
||||
-size.x + OVERLAP,
|
||||
(host_button.size.y - size.y) * 0.5,
|
||||
)
|
||||
pivot_offset = Vector2(size.x, size.y * 0.5)
|
||||
_refresh_label_layout()
|
||||
|
||||
|
||||
func set_reveal(amount: float) -> void:
|
||||
var reveal: float = clampf(amount, 0.0, 1.0)
|
||||
visible = reveal > 0.001
|
||||
scale = Vector2(maxf(reveal, 0.001), 1.0)
|
||||
|
||||
|
||||
func _build_controls() -> void:
|
||||
if _panel != null:
|
||||
return
|
||||
_panel = Panel.new()
|
||||
_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
var panel_style := StyleBoxFlat.new()
|
||||
panel_style.bg_color = DRAWER_COLOR
|
||||
panel_style.corner_radius_top_left = 12
|
||||
panel_style.corner_radius_top_right = 12
|
||||
panel_style.corner_radius_bottom_right = 12
|
||||
panel_style.corner_radius_bottom_left = 12
|
||||
_panel.add_theme_stylebox_override("panel", panel_style)
|
||||
add_child(_panel)
|
||||
|
||||
_label = Label.new()
|
||||
_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_label.add_theme_color_override("font_color", TEXT_COLOR)
|
||||
_label.add_theme_font_size_override("font_size", 20)
|
||||
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
add_child(_label)
|
||||
|
||||
|
||||
func _refresh_label_layout() -> void:
|
||||
if _label == null:
|
||||
return
|
||||
if drawer_mode == DrawerMode.RIGHT:
|
||||
_label.rotation = 0.0
|
||||
_label.position = Vector2.ZERO
|
||||
_label.size = size
|
||||
else:
|
||||
_label.rotation = -PI * 0.5
|
||||
_label.position = Vector2(-OVERLAP * 0.5, size.y)
|
||||
_label.size = Vector2(size.y, size.x)
|
||||
1
ui/components/bubble_menu/bubble_hover_drawer.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://jvw68gltfda0
|
||||
|
|
@ -21,6 +21,10 @@ extends Resource
|
|||
@export_range(0, 12, 1) var normal_border_width: int = 2
|
||||
@export_range(0, 12, 1) var emphasized_border_width: int = 3
|
||||
|
||||
@export_group("Gradient")
|
||||
@export var gradient_enabled: bool = false
|
||||
@export_range(0.0, 0.5, 0.01) var gradient_top_lift: float = 0.12
|
||||
|
||||
@export_group("Colors")
|
||||
@export var normal_fill: Color = Color(0.82, 0.93, 0.96, 0.96)
|
||||
@export var normal_border: Color = Color(0.91, 0.98, 1.0, 0.85)
|
||||
|
|
@ -78,7 +82,11 @@ func _make_style(
|
|||
style.content_margin_top = content_margin
|
||||
style.content_margin_right = content_margin
|
||||
style.content_margin_bottom = content_margin
|
||||
style.bg_color = fill_color
|
||||
style.bg_color = (
|
||||
Color(fill_color.r, fill_color.g, fill_color.b, 0.0)
|
||||
if gradient_enabled
|
||||
else fill_color
|
||||
)
|
||||
style.border_width_left = outline_width
|
||||
style.border_width_top = outline_width
|
||||
style.border_width_right = outline_width
|
||||
|
|
|
|||
22
ui/components/bubble_menu/title_menu_profile.tres
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[gd_resource type="Resource" script_class="BubbleMenuProfile" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_menu_profile.gd" id="1_profile"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_profile")
|
||||
font_size_ratio = 0.14
|
||||
hover_focus_scale = 1.02
|
||||
hover_focus_lift = 0.0
|
||||
emphasis_speed = 7.0
|
||||
emphasized_deformation_scale = 0.0
|
||||
contact_gap = 0.0
|
||||
maximum_separation = 0.0
|
||||
content_margin = 6.0
|
||||
corner_radius = 36
|
||||
normal_border_width = 0
|
||||
emphasized_border_width = 0
|
||||
gradient_enabled = false
|
||||
normal_fill = Color(1, 1, 1, 1)
|
||||
hover_fill = Color(1, 1, 1, 1)
|
||||
pressed_fill = Color(1, 1, 1, 1)
|
||||
disabled_fill = Color(1, 1, 1, 0.78)
|
||||
22
ui/components/bubble_menu/title_secondary_menu_profile.tres
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[gd_resource type="Resource" script_class="BubbleMenuProfile" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_menu_profile.gd" id="1_profile"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_profile")
|
||||
font_size_ratio = 0.14
|
||||
hover_focus_scale = 1.02
|
||||
hover_focus_lift = 0.0
|
||||
emphasis_speed = 7.0
|
||||
emphasized_deformation_scale = 0.0
|
||||
contact_gap = 0.0
|
||||
maximum_separation = 0.0
|
||||
content_margin = 6.0
|
||||
corner_radius = 16
|
||||
normal_border_width = 0
|
||||
emphasized_border_width = 0
|
||||
gradient_enabled = false
|
||||
normal_fill = Color(1, 1, 1, 1)
|
||||
hover_fill = Color(1, 1, 1, 1)
|
||||
pressed_fill = Color(1, 1, 1, 1)
|
||||
disabled_fill = Color(1, 1, 1, 0.78)
|
||||
|
|
@ -245,7 +245,7 @@ func _clear_directional_input_in_flight(generation: int) -> void:
|
|||
func _is_directional_navigation(event: InputEvent) -> bool:
|
||||
if event is InputEventKey and (event as InputEventKey).echo:
|
||||
return false
|
||||
# Tab is both Godot's default ui_focus_next key and NETfishing's default
|
||||
# Tab is both Godot's default ui_focus_next key and straywild's default
|
||||
# player-menu binding. The global focus presenter must leave that gameplay
|
||||
# action alone; otherwise a remembered neutral focus seed consumes the key
|
||||
# before PlayerMenu can open or close.
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ func _build_interface() -> void:
|
|||
|
||||
_instruction_label = Label.new()
|
||||
_instruction_label.text = (
|
||||
"auto-map walks through NETfishing's controller actions. "
|
||||
"auto-map walks through straywild's controller actions. "
|
||||
+ "select any row afterward to override it; the mapped back "
|
||||
+ "control cancels capture."
|
||||
)
|
||||
|
|
|
|||
BIN
ui/icons/new_menu/close.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
42
ui/icons/new_menu/close.png.import
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bq8a7n8grdob3"
|
||||
path.s3tc="res://.godot/imported/close.png-6d4985cc89fb9a07db5c6ce09f05566a.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/close.png-6d4985cc89fb9a07db5c6ce09f05566a.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/icons/new_menu/close.png"
|
||||
dest_files=["res://.godot/imported/close.png-6d4985cc89fb9a07db5c6ce09f05566a.s3tc.ctex", "res://.godot/imported/close.png-6d4985cc89fb9a07db5c6ce09f05566a.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
BIN
ui/icons/new_menu/credits.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
42
ui/icons/new_menu/credits.png.import
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://br1f2ofv4575c"
|
||||
path.s3tc="res://.godot/imported/credits.png-636657da1c8dc4ba52732813af1a703c.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/credits.png-636657da1c8dc4ba52732813af1a703c.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/icons/new_menu/credits.png"
|
||||
dest_files=["res://.godot/imported/credits.png-636657da1c8dc4ba52732813af1a703c.s3tc.ctex", "res://.godot/imported/credits.png-636657da1c8dc4ba52732813af1a703c.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
BIN
ui/icons/new_menu/online.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
42
ui/icons/new_menu/online.png.import
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c8sty10uue6nm"
|
||||
path.s3tc="res://.godot/imported/online.png-3f69c41cde4beb29d8f23e574a61641f.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/online.png-3f69c41cde4beb29d8f23e574a61641f.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/icons/new_menu/online.png"
|
||||
dest_files=["res://.godot/imported/online.png-3f69c41cde4beb29d8f23e574a61641f.s3tc.ctex", "res://.godot/imported/online.png-3f69c41cde4beb29d8f23e574a61641f.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
BIN
ui/icons/new_menu/play.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -2,20 +2,22 @@
|
|||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ckqayis1ckb2v"
|
||||
path="res://.godot/imported/netfishing_logo.png-82ab9fce5851dcc5239eca178e8cde99.ctex"
|
||||
uid="uid://7qe6siny4ru7"
|
||||
path.s3tc="res://.godot/imported/play.png-f35bbfc9549b806b0a83d0c3b4c7dc74.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/play.png-f35bbfc9549b806b0a83d0c3b4c7dc74.etc2.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/assets/title/netfishing_logo.png"
|
||||
dest_files=["res://.godot/imported/netfishing_logo.png-82ab9fce5851dcc5239eca178e8cde99.ctex"]
|
||||
source_file="res://ui/icons/new_menu/play.png"
|
||||
dest_files=["res://.godot/imported/play.png-f35bbfc9549b806b0a83d0c3b4c7dc74.s3tc.ctex", "res://.godot/imported/play.png-f35bbfc9549b806b0a83d0c3b4c7dc74.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
|
|
@ -37,4 +39,4 @@ process/normal_map_invert_y=false
|
|||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
detect_3d/compress_to=0
|
||||
BIN
ui/icons/new_menu/settings.png
Normal file
|
After Width: | Height: | Size: 8 KiB |
42
ui/icons/new_menu/settings.png.import
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cxqwvyg0qryg1"
|
||||
path.s3tc="res://.godot/imported/settings.png-3654f1ee86a2237bbc3c9af7e818343c.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/settings.png-3654f1ee86a2237bbc3c9af7e818343c.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/icons/new_menu/settings.png"
|
||||
dest_files=["res://.godot/imported/settings.png-3654f1ee86a2237bbc3c9af7e818343c.s3tc.ctex", "res://.godot/imported/settings.png-3654f1ee86a2237bbc3c9af7e818343c.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
|
|
@ -439,7 +439,7 @@ func _choose_import_path() -> void:
|
|||
_import_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_import_dialog.use_native_dialog = false
|
||||
_import_dialog.filters = PackedStringArray([
|
||||
"*.nfsave ; NETfishing progression archive",
|
||||
"*.nfsave ; straywild progression archive",
|
||||
])
|
||||
_import_dialog.file_selected.connect(_import_file_selected)
|
||||
if _interface_fonts != null:
|
||||
|
|
@ -479,7 +479,7 @@ func _choose_export_path() -> void:
|
|||
_export_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_export_dialog.use_native_dialog = false
|
||||
_export_dialog.filters = PackedStringArray([
|
||||
"*.nfsave ; NETfishing progression archive",
|
||||
"*.nfsave ; straywild progression archive",
|
||||
])
|
||||
_export_dialog.file_selected.connect(_export_file_selected)
|
||||
if _interface_fonts != null:
|
||||
|
|
@ -716,7 +716,7 @@ func _safe_filename(value: String) -> String:
|
|||
var result: String = value.strip_edges().to_lower().replace(" ", "-")
|
||||
for character: String in ["/", "\\", ":", "*", "?", "\"", "<", ">", "|"]:
|
||||
result = result.replace(character, "")
|
||||
return "netfishing-save" if result.is_empty() else result
|
||||
return "straywild-save" if result.is_empty() else result
|
||||
|
||||
|
||||
func _on_slots_changed() -> void:
|
||||
|
|
|
|||
|
|
@ -697,7 +697,7 @@ func _change_data_folder(path: String) -> void:
|
|||
).to_lower()
|
||||
_refresh_data_page()
|
||||
return
|
||||
_feedback.text = "data folder changed. NETfishing will close safely."
|
||||
_feedback.text = "data folder changed. straywild will close safely."
|
||||
_refresh_data_page()
|
||||
get_tree().call_deferred("quit")
|
||||
else:
|
||||
|
|
@ -708,16 +708,16 @@ func _change_data_folder(path: String) -> void:
|
|||
|
||||
func _show_existing_data_folder_choice(path: String) -> void:
|
||||
var dialog := ConfirmationDialog.new()
|
||||
dialog.title = "existing NETfishing data"
|
||||
dialog.title = "existing straywild data"
|
||||
dialog.ok_button_text = "use selected data"
|
||||
dialog.dialog_text = (
|
||||
"the selected folder contains different NETfishing data.\n\n"
|
||||
"the selected folder contains different straywild data.\n\n"
|
||||
+ "choose one complete data set. data will not be merged."
|
||||
)
|
||||
dialog.add_button("replace selected data", false, "replace")
|
||||
dialog.confirmed.connect(func() -> void:
|
||||
if _data_root.use_existing_root(path):
|
||||
_feedback.text = "data folder changed. NETfishing will close safely."
|
||||
_feedback.text = "data folder changed. straywild will close safely."
|
||||
get_tree().call_deferred("quit")
|
||||
else:
|
||||
_feedback.text = _data_root.error_message
|
||||
|
|
@ -756,7 +756,7 @@ func _choose_identity_export(identity_type: String) -> void:
|
|||
_export_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_export_file_dialog.use_native_dialog = false
|
||||
_export_file_dialog.filters = PackedStringArray([
|
||||
"*.nfidentity ; NETfishing identity backup",
|
||||
"*.nfidentity ; straywild identity backup",
|
||||
])
|
||||
_export_file_dialog.file_selected.connect(
|
||||
_identity_export_file_selected
|
||||
|
|
@ -786,7 +786,7 @@ func _choose_identity_import(identity_type: String) -> void:
|
|||
_backup_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_backup_file_dialog.use_native_dialog = false
|
||||
_backup_file_dialog.filters = PackedStringArray([
|
||||
"*.nfidentity ; NETfishing identity backup",
|
||||
"*.nfidentity ; straywild identity backup",
|
||||
])
|
||||
_backup_file_dialog.file_selected.connect(
|
||||
_identity_import_file_selected
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ horizontal_alignment = 1
|
|||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "NETfishing is created by Woofmeow"
|
||||
text = "straywild is created by Woofmeow"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Columns" type="HBoxContainer" parent="Paper/Margin/Layout"]
|
||||
|
|
|
|||
|
|
@ -31,55 +31,18 @@ const SaveSlotsPageType = preload("res://ui/save_slots_page.gd")
|
|||
const CurrencyPresentationType = preload(
|
||||
"res://ui/currency_presentation.gd"
|
||||
)
|
||||
const DECORATIVE_FISH_TEXTURES: Array[Texture2D] = [
|
||||
preload("res://fish/species/bass/fish_bass_striped.png"),
|
||||
preload("res://fish/species/bluegill/fish_bluegill.png"),
|
||||
preload("res://fish/species/carp/fish_carp_common.png"),
|
||||
preload("res://fish/species/sunfish/fish_sunfish.png"),
|
||||
]
|
||||
const DECORATIVE_BUBBLE_TEXTURES: Array[Texture2D] = [
|
||||
preload("res://ui/assets/title/bubbles/bubble1.png"),
|
||||
preload("res://ui/assets/title/bubbles/bubble2.png"),
|
||||
preload("res://ui/assets/title/bubbles/bubble3.png"),
|
||||
]
|
||||
|
||||
const FIRST_FISH_DELAY_MIN: float = 2.0
|
||||
const FIRST_FISH_DELAY_MAX: float = 5.0
|
||||
const NEXT_FISH_DELAY_MIN: float = 5.0
|
||||
const NEXT_FISH_DELAY_MAX: float = 12.0
|
||||
const CROSSING_DURATION_MIN: float = 8.0
|
||||
const CROSSING_DURATION_MAX: float = 16.0
|
||||
const FISH_LONGEST_SIDE_MIN: float = 120.0
|
||||
const FISH_LONGEST_SIDE_MAX: float = 210.0
|
||||
const FISH_EDGE_MARGIN: float = 24.0
|
||||
const BUBBLE_EVENT_DELAY_MIN: float = 4.0
|
||||
const BUBBLE_EVENT_DELAY_MAX: float = 10.0
|
||||
const BUBBLE_CLUSTER_DELAY_MIN: float = 0.25
|
||||
const BUBBLE_CLUSTER_DELAY_MAX: float = 0.65
|
||||
const BUBBLE_TRAVEL_DURATION_MIN: float = 7.0
|
||||
const BUBBLE_TRAVEL_DURATION_MAX: float = 14.0
|
||||
const BUBBLE_SCALE_MIN: float = 0.65
|
||||
const BUBBLE_SCALE_MAX: float = 1.15
|
||||
const BUBBLE_OPACITY_MIN: float = 0.55
|
||||
const BUBBLE_OPACITY_MAX: float = 0.90
|
||||
const BUBBLE_DRIFT_MIN: float = 10.0
|
||||
const BUBBLE_DRIFT_MAX: float = 45.0
|
||||
const BUBBLE_WOBBLE_MIN: float = 3.0
|
||||
const BUBBLE_WOBBLE_MAX: float = 9.0
|
||||
const BUBBLE_EDGE_MARGIN: float = 16.0
|
||||
const MAX_DECORATIVE_BUBBLES: int = 6
|
||||
const MAX_TRANSITION_BUBBLES: int = 30
|
||||
const LOGO_ASPECT_RATIO: float = 2560.0 / 760.0
|
||||
const LOGO_ASPECT_RATIO: float = 2560.0 / 480.0
|
||||
const LOGO_WIDTH_FACTOR: float = 0.4784
|
||||
const LOGO_MIN_WIDTH: float = 294.0
|
||||
const LOGO_MAX_WIDTH: float = 662.0
|
||||
const TITLE_HORIZONTAL_MARGIN: float = 48.0
|
||||
const TITLE_DESKTOP_REFERENCE_SIZE: Vector2 = Vector2(1280.0, 720.0)
|
||||
const TITLE_COMPACT_REFERENCE_SIZE: Vector2 = Vector2(640.0, 480.0)
|
||||
const BUBBLE_FIELD_MAX_WIDTH: float = 440.0
|
||||
const BUBBLE_FIELD_DESKTOP_HEIGHT: float = 318.0
|
||||
const BUBBLE_FIELD_MAX_WIDTH: float = 500.0
|
||||
const BUBBLE_FIELD_DESKTOP_HEIGHT: float = 360.0
|
||||
const BUBBLE_FIELD_COMPACT_WIDTH: float = 294.0
|
||||
const BUBBLE_FIELD_COMPACT_HEIGHT: float = 200.0
|
||||
const BUBBLE_FIELD_DESKTOP_OFFSET_Y: float = -10.0
|
||||
const BUBBLE_COMPACT_HEIGHT_THRESHOLD: float = 560.0
|
||||
const START_PROMPT_MIN_SCALE: float = 0.985
|
||||
const START_PROMPT_MAX_SCALE: float = 1.015
|
||||
|
|
@ -87,6 +50,11 @@ const START_PROMPT_CYCLE_SECONDS: float = 3.0
|
|||
const QUICK_MENU_ENTER_DURATION: float = 0.14
|
||||
const QUICK_MENU_EXIT_DURATION: float = 0.10
|
||||
const QUICK_MENU_ENTER_SCALE: float = 0.97
|
||||
const INTRO_PROMPT_FADE_DURATION: float = 0.24
|
||||
const INTRO_LOGO_FLOAT_DURATION: float = 0.72
|
||||
const INTRO_MENU_REVEAL_DELAY: float = 0.34
|
||||
const INTRO_MENU_REVEAL_DURATION: float = 0.30
|
||||
const INTRO_LOGO_CENTER_Y_RATIO: float = 0.43
|
||||
|
||||
signal new_game_requested(world_layout: StringName, world_seed: int)
|
||||
signal continue_game_requested
|
||||
|
|
@ -113,6 +81,7 @@ enum ConfirmationAction {
|
|||
@onready var _quit_button: BubbleButtonType = %QuitButton
|
||||
@onready var _join_game_button: BubbleButtonType = %JoinGameButton
|
||||
@onready var _feedback_label: RichTextLabel = %FeedbackLabel
|
||||
@onready var _continue_stats_drawer: RichTextLabel = %ContinueStatsDrawer
|
||||
@onready var _confirmation_page: TitleConfirmationBubblePageType = (
|
||||
%ConfirmationPage
|
||||
)
|
||||
|
|
@ -121,11 +90,6 @@ enum ConfirmationAction {
|
|||
%TitlePresentationScaleRoot
|
||||
)
|
||||
@onready var _background: ColorRect = %Background
|
||||
@onready var _decorative_fish_layer: Control = %DecorativeFishLayer
|
||||
@onready var _decorative_fish_timer: Timer = %DecorativeFishTimer
|
||||
@onready var _decorative_bubble_layer: Control = %DecorativeBubbleLayer
|
||||
@onready var _decorative_bubble_event_timer: Timer = %DecorativeBubbleEventTimer
|
||||
@onready var _decorative_bubble_cluster_timer: Timer = %DecorativeBubbleClusterTimer
|
||||
@onready var _title_logo: TextureRect = %TitleLogo
|
||||
@onready var _playtest_label: Label = %PlaytestLabel
|
||||
@onready var _presentation_center: CenterContainer = %Center
|
||||
|
|
@ -149,17 +113,6 @@ var _settings_manager: SettingsManagerType
|
|||
var _inspection: SaveInspectionType
|
||||
var _confirmation_action: ConfirmationAction = ConfirmationAction.NONE
|
||||
var _action_in_progress: bool = false
|
||||
var _decorative_rng := RandomNumberGenerator.new()
|
||||
var _decorative_fish: TextureRect
|
||||
var _decorative_fish_tween: Tween
|
||||
var _decorative_presentation_ready: bool = false
|
||||
var _decorative_presentation_active: bool = false
|
||||
var _decorative_generation: int = 0
|
||||
var _decorative_bubbles: Array[TextureRect] = []
|
||||
var _decorative_bubble_tweens: Dictionary[int, Tween] = {}
|
||||
var _transition_bubble_ids: Dictionary[int, bool] = {}
|
||||
var _pending_cluster_bubbles: int = 0
|
||||
var _minimal_presentation: bool = false
|
||||
var _awaiting_start_input: bool = false
|
||||
var _start_prompt_elapsed: float = 0.0
|
||||
var _navigation_focus_active: bool = false
|
||||
|
|
@ -219,27 +172,16 @@ func _ready() -> void:
|
|||
_settings_panel.closed.connect(_on_settings_closed)
|
||||
_settings_panel.closing.connect(_on_settings_closing)
|
||||
_settings_panel.opened.connect(_on_settings_opened)
|
||||
_settings_panel.navigation_transition_started.connect(
|
||||
_emit_navigation_bubble_flurry
|
||||
)
|
||||
_credits_page.back_requested.connect(_close_credits)
|
||||
_save_slots_page.back_requested.connect(_close_save_slots)
|
||||
_save_slots_page.play_requested.connect(_on_slot_play_requested)
|
||||
_save_slots_page.create_requested.connect(_on_new_slot_requested)
|
||||
_bubble_field.configure(_get_title_buttons())
|
||||
_bubble_field.motion_scale = 0.0
|
||||
_decorative_fish_timer.timeout.connect(_on_decorative_fish_timer_timeout)
|
||||
_decorative_bubble_event_timer.timeout.connect(
|
||||
_on_decorative_bubble_event_timer_timeout
|
||||
)
|
||||
_decorative_bubble_cluster_timer.timeout.connect(
|
||||
_on_decorative_bubble_cluster_timer_timeout
|
||||
)
|
||||
_bubble_field.motion_scale = 1.0
|
||||
visibility_changed.connect(_on_title_visibility_changed)
|
||||
resized.connect(_update_responsive_title_stage)
|
||||
get_window().size_changed.connect(_update_responsive_title_stage)
|
||||
_start_prompt_label.resized.connect(_update_start_prompt_pivot)
|
||||
_decorative_rng.randomize()
|
||||
set_process(false)
|
||||
call_deferred("_update_responsive_title_stage")
|
||||
call_deferred("_update_start_prompt_pivot")
|
||||
|
|
@ -269,19 +211,9 @@ func setup(
|
|||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
_refresh_save_inspection()
|
||||
show()
|
||||
_decorative_presentation_ready = true
|
||||
_start_decorative_presentation()
|
||||
_begin_title_entry()
|
||||
|
||||
|
||||
func set_minimal_presentation(enabled: bool) -> void:
|
||||
_minimal_presentation = enabled
|
||||
if _minimal_presentation:
|
||||
_stop_decorative_presentation()
|
||||
elif visible:
|
||||
_start_decorative_presentation()
|
||||
|
||||
|
||||
func reopen() -> void:
|
||||
_cancel_title_entry_transition()
|
||||
_cancel_title_settings_transition()
|
||||
|
|
@ -295,7 +227,6 @@ func reopen() -> void:
|
|||
_save_slots_page.close_page()
|
||||
_refresh_save_inspection()
|
||||
show()
|
||||
_start_decorative_presentation()
|
||||
_start_entry_prompt_animation()
|
||||
|
||||
|
||||
|
|
@ -315,6 +246,8 @@ func reopen_to_menu() -> void:
|
|||
func open_join_game_page(endpoint: String = "") -> void:
|
||||
_cancel_title_entry_transition()
|
||||
_awaiting_start_input = false
|
||||
_set_title_bubbles_interactive(false)
|
||||
_release_primary_menu_focus()
|
||||
_start_prompt_center.hide()
|
||||
_presentation_center.hide()
|
||||
_settings_panel.hide()
|
||||
|
|
@ -353,6 +286,7 @@ func _close_join_game() -> void:
|
|||
_presentation_center.show()
|
||||
_button_center.show()
|
||||
_start_prompt_center.hide()
|
||||
_set_title_bubbles_interactive(true)
|
||||
_focus_initial_button()
|
||||
|
||||
|
||||
|
|
@ -395,28 +329,6 @@ func is_awaiting_start_input() -> bool:
|
|||
return _awaiting_start_input
|
||||
|
||||
|
||||
func is_decorative_presentation_active() -> bool:
|
||||
return _decorative_presentation_active
|
||||
|
||||
|
||||
func get_active_decorative_fish_count() -> int:
|
||||
return 1 if is_instance_valid(_decorative_fish) else 0
|
||||
|
||||
|
||||
func get_active_decorative_bubble_count() -> int:
|
||||
return _decorative_bubbles.size()
|
||||
|
||||
|
||||
func is_decorative_bubble_scheduler_active() -> bool:
|
||||
return (
|
||||
_decorative_presentation_active
|
||||
and (
|
||||
not _decorative_bubble_event_timer.is_stopped()
|
||||
or not _decorative_bubble_cluster_timer.is_stopped()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _update_title_layout() -> void:
|
||||
if not is_node_ready():
|
||||
return
|
||||
|
|
@ -464,6 +376,12 @@ func _update_title_layout() -> void:
|
|||
Vector2(field_width, field_height),
|
||||
compact_layout
|
||||
)
|
||||
_bubble_field.position = Vector2(
|
||||
0.0,
|
||||
BUBBLE_FIELD_DESKTOP_OFFSET_Y
|
||||
* field_height
|
||||
/ BUBBLE_FIELD_DESKTOP_HEIGHT,
|
||||
)
|
||||
_configure_title_controller_navigation()
|
||||
if not _title_settings_transition_active:
|
||||
call_deferred("_capture_title_bubble_rest_position")
|
||||
|
|
@ -520,12 +438,6 @@ func _update_world_preview_resolution() -> void:
|
|||
_world_pixel_size,
|
||||
displayed_size
|
||||
)
|
||||
var shader_material := _background.material as ShaderMaterial
|
||||
if shader_material != null:
|
||||
shader_material.set_shader_parameter(
|
||||
"virtual_pixel_density",
|
||||
Vector2(grid_size)
|
||||
)
|
||||
var logo_material := _title_logo.material as ShaderMaterial
|
||||
if logo_material != null:
|
||||
var render_scale: float = (
|
||||
|
|
@ -542,23 +454,6 @@ func _update_world_preview_resolution() -> void:
|
|||
)
|
||||
|
||||
|
||||
func _snap_world_preview(value: Vector2) -> Vector2:
|
||||
var displayed_size := Vector2i(
|
||||
maxi(1, roundi(size.x)),
|
||||
maxi(1, roundi(size.y))
|
||||
)
|
||||
var grid_size: Vector2i = PlayerSettings.get_world_grid_size(
|
||||
_world_pixel_size,
|
||||
displayed_size
|
||||
)
|
||||
var render_scale: float = float(grid_size.y) / float(displayed_size.y)
|
||||
var step: float = 1.0 / render_scale
|
||||
return Vector2(
|
||||
roundf(value.x / step) * step,
|
||||
roundf(value.y / step) * step
|
||||
)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not visible:
|
||||
return
|
||||
|
|
@ -725,6 +620,9 @@ func _prepare_awaiting_start_input() -> void:
|
|||
_continue_stats_hovered = false
|
||||
_continue_stats_focused = false
|
||||
_cancel_continue_stats_fade()
|
||||
_continue_stats_drawer.hide()
|
||||
_continue_stats_drawer.modulate.a = 0.0
|
||||
_continue_stats_drawer.scale = Vector2(1.0, 0.001)
|
||||
_main_content.show()
|
||||
_start_prompt_center.show()
|
||||
_start_prompt_center.modulate.a = 1.0
|
||||
|
|
@ -775,7 +673,6 @@ func _reveal_primary_menu() -> void:
|
|||
_navigation_focus_active = false
|
||||
_release_title_focus()
|
||||
_bubble_motion_root.position = Vector2.ZERO
|
||||
_branding_motion_root.position = Vector2.ZERO
|
||||
_bubble_field.pivot_offset = _bubble_field.size * 0.5
|
||||
_bubble_field.scale = Vector2.ONE * QUICK_MENU_ENTER_SCALE
|
||||
_bubble_field.modulate.a = 0.0
|
||||
|
|
@ -784,20 +681,28 @@ func _reveal_primary_menu() -> void:
|
|||
_start_prompt_center,
|
||||
"modulate:a",
|
||||
0.0,
|
||||
QUICK_MENU_EXIT_DURATION
|
||||
INTRO_PROMPT_FADE_DURATION
|
||||
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
|
||||
_title_entry_transition.tween_property(
|
||||
_branding_motion_root,
|
||||
"position",
|
||||
Vector2.ZERO,
|
||||
INTRO_LOGO_FLOAT_DURATION
|
||||
).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT)
|
||||
_title_entry_transition.tween_property(
|
||||
_bubble_field,
|
||||
"scale",
|
||||
Vector2.ONE,
|
||||
QUICK_MENU_ENTER_DURATION
|
||||
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||||
INTRO_MENU_REVEAL_DURATION
|
||||
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT).set_delay(
|
||||
INTRO_MENU_REVEAL_DELAY
|
||||
)
|
||||
_title_entry_transition.tween_property(
|
||||
_bubble_field,
|
||||
"modulate:a",
|
||||
1.0,
|
||||
QUICK_MENU_ENTER_DURATION
|
||||
)
|
||||
INTRO_MENU_REVEAL_DURATION
|
||||
).set_delay(INTRO_MENU_REVEAL_DELAY)
|
||||
_title_entry_transition.finished.connect(
|
||||
_finish_primary_menu_reveal.bind(generation),
|
||||
CONNECT_ONE_SHOT
|
||||
|
|
@ -814,6 +719,7 @@ func _finish_primary_menu_reveal(generation: int) -> void:
|
|||
_title_entry_transition_active = false
|
||||
_start_prompt_center.hide()
|
||||
_start_prompt_center.modulate.a = 1.0
|
||||
_branding_motion_root.position = Vector2.ZERO
|
||||
_bubble_field.scale = Vector2.ONE
|
||||
_bubble_field.modulate.a = 1.0
|
||||
_feedback_label.modulate.a = 0.0
|
||||
|
|
@ -855,10 +761,18 @@ func _prepare_intro_presentation(generation: int) -> void:
|
|||
return
|
||||
_branding_motion_root.size = _branding_slot.size
|
||||
_bubble_motion_root.size = _bubble_layout_slot.size
|
||||
_branding_motion_root.position = Vector2.ZERO
|
||||
_bubble_motion_root.position = Vector2.ZERO
|
||||
_title_content_rest_position = _presentation_center.position
|
||||
_title_bubble_rest_position = _bubble_field.position
|
||||
var branding_rect: Rect2 = _get_title_stage_rect(_branding_slot)
|
||||
var desired_branding_center_y: float = (
|
||||
_title_presentation_scale_root.size.y
|
||||
* INTRO_LOGO_CENTER_Y_RATIO
|
||||
)
|
||||
_branding_motion_root.position = Vector2(
|
||||
0.0,
|
||||
desired_branding_center_y - branding_rect.get_center().y,
|
||||
)
|
||||
_intro_geometry_ready = true
|
||||
|
||||
|
||||
|
|
@ -908,7 +822,7 @@ func _update_continue_stats_visibility() -> void:
|
|||
and _presentation_center.visible
|
||||
)
|
||||
if requested_visible:
|
||||
_feedback_label.text = _get_continue_stats_text()
|
||||
_continue_stats_drawer.text = _get_continue_stats_text()
|
||||
_fade_continue_stats_to(1.0 if requested_visible else 0.0)
|
||||
|
||||
|
||||
|
|
@ -922,16 +836,47 @@ func _fade_continue_stats_to(target_opacity: float) -> void:
|
|||
if not is_node_ready():
|
||||
return
|
||||
_cancel_continue_stats_fade()
|
||||
if is_equal_approx(_feedback_label.modulate.a, target_opacity):
|
||||
_feedback_label.modulate.a = target_opacity
|
||||
var target_scale := Vector2(
|
||||
1.0,
|
||||
1.0 if target_opacity > 0.0 else 0.001,
|
||||
)
|
||||
if target_opacity > 0.0:
|
||||
_continue_stats_drawer.show()
|
||||
if (
|
||||
is_equal_approx(
|
||||
_continue_stats_drawer.modulate.a,
|
||||
target_opacity,
|
||||
)
|
||||
and _continue_stats_drawer.scale.is_equal_approx(target_scale)
|
||||
):
|
||||
_continue_stats_drawer.modulate.a = target_opacity
|
||||
_continue_stats_drawer.scale = target_scale
|
||||
if target_opacity <= 0.0:
|
||||
_continue_stats_drawer.hide()
|
||||
return
|
||||
_continue_stats_fade = create_tween()
|
||||
_continue_stats_fade = create_tween().set_parallel(true)
|
||||
_continue_stats_fade.tween_property(
|
||||
_feedback_label,
|
||||
_continue_stats_drawer,
|
||||
"modulate:a",
|
||||
target_opacity,
|
||||
QUICK_MENU_ENTER_DURATION
|
||||
).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT)
|
||||
_continue_stats_fade.tween_property(
|
||||
_continue_stats_drawer,
|
||||
"scale",
|
||||
target_scale,
|
||||
QUICK_MENU_ENTER_DURATION
|
||||
).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT)
|
||||
if target_opacity <= 0.0:
|
||||
_continue_stats_fade.chain().tween_callback(
|
||||
_finish_continue_stats_hide
|
||||
)
|
||||
|
||||
|
||||
func _finish_continue_stats_hide() -> void:
|
||||
_continue_stats_fade = null
|
||||
if _continue_stats_drawer.modulate.a <= 0.001:
|
||||
_continue_stats_drawer.hide()
|
||||
|
||||
|
||||
func _cancel_continue_stats_fade() -> void:
|
||||
|
|
@ -1180,7 +1125,6 @@ func _begin_confirmation_open() -> void:
|
|||
_confirmation_transition_generation += 1
|
||||
_cancel_confirmation_transition()
|
||||
_confirmation_transition_active = true
|
||||
_emit_navigation_bubble_flurry()
|
||||
_confirmation_title_content_rest_position = _presentation_center.position
|
||||
_set_confirmation_stage_rect()
|
||||
_confirmation_page.hide_page()
|
||||
|
|
@ -1238,7 +1182,6 @@ func _begin_confirmation_return() -> void:
|
|||
_confirmation_transition_generation += 1
|
||||
_cancel_confirmation_transition()
|
||||
_confirmation_transition_active = true
|
||||
_emit_navigation_bubble_flurry()
|
||||
_confirmation_page.lock_interaction()
|
||||
var generation: int = _confirmation_transition_generation
|
||||
_confirmation_page.transition_out(
|
||||
|
|
@ -1375,7 +1318,6 @@ func _begin_title_cluster_exit() -> void:
|
|||
_title_settings_transition_generation += 1
|
||||
_cancel_title_settings_tween()
|
||||
_title_settings_transition_active = true
|
||||
_emit_navigation_bubble_flurry()
|
||||
_title_content_rest_position = _presentation_center.position
|
||||
_title_bubble_rest_position = _bubble_field.position
|
||||
_set_title_bubbles_interactive(false)
|
||||
|
|
@ -1475,6 +1417,8 @@ func _finish_title_cluster_return(generation: int) -> void:
|
|||
|
||||
func _set_title_bubbles_interactive(interactive: bool) -> void:
|
||||
for bubble: BubbleButton in _get_title_buttons():
|
||||
if not interactive:
|
||||
bubble.reset_hover_presentation()
|
||||
bubble.focus_mode = (
|
||||
Control.FOCUS_ALL if interactive else Control.FOCUS_NONE
|
||||
)
|
||||
|
|
@ -1491,21 +1435,39 @@ func _configure_title_controller_navigation() -> void:
|
|||
ControllerFocusNavigationType.configure_spatial_neighbors(
|
||||
_get_title_buttons()
|
||||
)
|
||||
# The large Play bubble overlaps the inward edge of every surrounding
|
||||
# bubble. Center-only spatial scoring otherwise links the four outside
|
||||
# bubbles into a ring with no route back into Play.
|
||||
_join_game_button.focus_neighbor_right = (
|
||||
_play_button.focus_neighbor_right = (
|
||||
_play_button.get_path_to(_join_game_button)
|
||||
)
|
||||
_join_game_button.focus_neighbor_left = (
|
||||
_join_game_button.get_path_to(_play_button)
|
||||
)
|
||||
_join_game_button.focus_neighbor_bottom = (
|
||||
_join_game_button.get_path_to(_settings_button)
|
||||
)
|
||||
_settings_button.focus_neighbor_left = (
|
||||
_settings_button.get_path_to(_play_button)
|
||||
)
|
||||
_credits_button.focus_neighbor_right = (
|
||||
_settings_button.focus_neighbor_top = (
|
||||
_settings_button.get_path_to(_join_game_button)
|
||||
)
|
||||
_settings_button.focus_neighbor_bottom = (
|
||||
_settings_button.get_path_to(_credits_button)
|
||||
)
|
||||
_credits_button.focus_neighbor_left = (
|
||||
_credits_button.get_path_to(_play_button)
|
||||
)
|
||||
_credits_button.focus_neighbor_top = (
|
||||
_credits_button.get_path_to(_settings_button)
|
||||
)
|
||||
_credits_button.focus_neighbor_bottom = (
|
||||
_credits_button.get_path_to(_quit_button)
|
||||
)
|
||||
_quit_button.focus_neighbor_left = (
|
||||
_quit_button.get_path_to(_play_button)
|
||||
)
|
||||
_quit_button.focus_neighbor_top = (
|
||||
_quit_button.get_path_to(_credits_button)
|
||||
)
|
||||
|
||||
|
||||
func _capture_title_bubble_rest_position() -> void:
|
||||
|
|
@ -1575,7 +1537,7 @@ func _refresh_save_inspection() -> void:
|
|||
_delete_button.disabled = not _inspection.can_delete()
|
||||
_feedback_label.text = _center_feedback_text(_inspection.message)
|
||||
if _inspection.status == SaveInspectionType.Status.VALID_SUPPORTED:
|
||||
_feedback_label.text = _get_continue_stats_text()
|
||||
_continue_stats_drawer.text = _get_continue_stats_text()
|
||||
if not _inspection.can_continue():
|
||||
_hide_continue_stats_context()
|
||||
else:
|
||||
|
|
@ -1609,11 +1571,8 @@ func _on_quit_pressed() -> void:
|
|||
|
||||
|
||||
func _on_title_visibility_changed() -> void:
|
||||
if not _decorative_presentation_ready:
|
||||
return
|
||||
if visible:
|
||||
set_process(true)
|
||||
_start_decorative_presentation()
|
||||
else:
|
||||
_hide_continue_stats_context()
|
||||
_stop_entry_prompt_animation()
|
||||
|
|
@ -1621,482 +1580,3 @@ func _on_title_visibility_changed() -> void:
|
|||
_modal_restore_navigation_focus = false
|
||||
_reset_confirmation()
|
||||
_credits_page.close_page()
|
||||
_stop_decorative_presentation()
|
||||
|
||||
|
||||
func _start_decorative_presentation() -> void:
|
||||
if (
|
||||
not _decorative_presentation_ready
|
||||
or not visible
|
||||
or _decorative_presentation_active
|
||||
or _minimal_presentation
|
||||
):
|
||||
return
|
||||
_decorative_generation += 1
|
||||
_decorative_presentation_active = true
|
||||
_schedule_next_decorative_fish(
|
||||
FIRST_FISH_DELAY_MIN,
|
||||
FIRST_FISH_DELAY_MAX
|
||||
)
|
||||
_schedule_next_decorative_bubble_event(
|
||||
BUBBLE_EVENT_DELAY_MIN,
|
||||
BUBBLE_EVENT_DELAY_MAX
|
||||
)
|
||||
|
||||
|
||||
func _stop_decorative_presentation() -> void:
|
||||
_decorative_generation += 1
|
||||
_decorative_presentation_active = false
|
||||
_decorative_fish_timer.stop()
|
||||
if _decorative_fish_tween != null:
|
||||
_decorative_fish_tween.kill()
|
||||
_decorative_fish_tween = null
|
||||
if is_instance_valid(_decorative_fish):
|
||||
_decorative_fish.queue_free()
|
||||
_decorative_fish = null
|
||||
_decorative_bubble_event_timer.stop()
|
||||
_decorative_bubble_cluster_timer.stop()
|
||||
_pending_cluster_bubbles = 0
|
||||
for bubble_tween: Tween in _decorative_bubble_tweens.values():
|
||||
if bubble_tween != null:
|
||||
bubble_tween.kill()
|
||||
_decorative_bubble_tweens.clear()
|
||||
for bubble: TextureRect in _decorative_bubbles:
|
||||
if is_instance_valid(bubble):
|
||||
bubble.queue_free()
|
||||
_decorative_bubbles.clear()
|
||||
_transition_bubble_ids.clear()
|
||||
|
||||
|
||||
func _schedule_next_decorative_fish(
|
||||
minimum_delay: float,
|
||||
maximum_delay: float,
|
||||
) -> void:
|
||||
if not _decorative_presentation_active or not visible:
|
||||
return
|
||||
_decorative_fish_timer.start(
|
||||
_decorative_rng.randf_range(minimum_delay, maximum_delay)
|
||||
)
|
||||
|
||||
|
||||
func _on_decorative_fish_timer_timeout() -> void:
|
||||
if (
|
||||
not _decorative_presentation_active
|
||||
or not visible
|
||||
or is_instance_valid(_decorative_fish)
|
||||
):
|
||||
return
|
||||
_spawn_decorative_fish(_decorative_generation)
|
||||
|
||||
|
||||
func _spawn_decorative_fish(generation: int) -> void:
|
||||
if (
|
||||
generation != _decorative_generation
|
||||
or not _decorative_presentation_active
|
||||
or not visible
|
||||
or DECORATIVE_FISH_TEXTURES.is_empty()
|
||||
):
|
||||
return
|
||||
var layer_size: Vector2 = _decorative_fish_layer.size
|
||||
if layer_size.x <= 1.0 or layer_size.y <= 1.0:
|
||||
_schedule_next_decorative_fish(0.5, 1.0)
|
||||
return
|
||||
var texture: Texture2D = DECORATIVE_FISH_TEXTURES[
|
||||
_decorative_rng.randi_range(0, DECORATIVE_FISH_TEXTURES.size() - 1)
|
||||
]
|
||||
var source_size: Vector2 = texture.get_size()
|
||||
if source_size.x <= 0.0 or source_size.y <= 0.0:
|
||||
_schedule_next_decorative_fish(
|
||||
NEXT_FISH_DELAY_MIN,
|
||||
NEXT_FISH_DELAY_MAX
|
||||
)
|
||||
return
|
||||
var longest_side: float = _decorative_rng.randf_range(
|
||||
FISH_LONGEST_SIDE_MIN,
|
||||
FISH_LONGEST_SIDE_MAX
|
||||
)
|
||||
var presentation_scale: float = longest_side / maxf(
|
||||
source_size.x,
|
||||
source_size.y
|
||||
)
|
||||
var presentation_size: Vector2 = source_size * presentation_scale
|
||||
var fish_control := TextureRect.new()
|
||||
fish_control.name = "DecorativeFish"
|
||||
fish_control.texture = texture
|
||||
fish_control.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
fish_control.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
fish_control.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
fish_control.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
fish_control.custom_minimum_size = presentation_size
|
||||
fish_control.size = presentation_size
|
||||
fish_control.modulate.a = 0.46
|
||||
|
||||
var direction: float = (
|
||||
1.0
|
||||
if _decorative_rng.randi_range(0, 1) == 1
|
||||
else -1.0
|
||||
)
|
||||
fish_control.flip_h = direction > 0.0
|
||||
var minimum_y: float = maxf(24.0, layer_size.y * 0.08)
|
||||
var maximum_y: float = maxf(
|
||||
minimum_y,
|
||||
layer_size.y - presentation_size.y - maxf(24.0, layer_size.y * 0.08)
|
||||
)
|
||||
var base_y: float = _decorative_rng.randf_range(minimum_y, maximum_y)
|
||||
var bob_amplitude: float = _decorative_rng.randf_range(3.0, 8.0)
|
||||
var bob_speed: float = _decorative_rng.randf_range(0.65, 1.15)
|
||||
var crossing_duration: float = _decorative_rng.randf_range(
|
||||
CROSSING_DURATION_MIN,
|
||||
CROSSING_DURATION_MAX
|
||||
)
|
||||
var horizontal_bounds: Vector2 = get_decorative_fish_crossing_bounds(
|
||||
layer_size.x,
|
||||
presentation_size.x,
|
||||
direction,
|
||||
)
|
||||
fish_control.position = Vector2(horizontal_bounds.x, base_y)
|
||||
_decorative_fish_layer.add_child(fish_control)
|
||||
_decorative_fish = fish_control
|
||||
_decorative_fish_tween = create_tween()
|
||||
_decorative_fish_tween.tween_method(
|
||||
_update_decorative_fish.bind(
|
||||
fish_control,
|
||||
direction,
|
||||
base_y,
|
||||
bob_amplitude,
|
||||
bob_speed,
|
||||
crossing_duration,
|
||||
generation
|
||||
),
|
||||
0.0,
|
||||
1.0,
|
||||
crossing_duration
|
||||
)
|
||||
_decorative_fish_tween.finished.connect(
|
||||
_on_decorative_fish_finished.bind(fish_control, generation),
|
||||
CONNECT_ONE_SHOT
|
||||
)
|
||||
|
||||
|
||||
func _update_decorative_fish(
|
||||
progress: float,
|
||||
fish_control: TextureRect,
|
||||
direction: float,
|
||||
base_y: float,
|
||||
bob_amplitude: float,
|
||||
bob_speed: float,
|
||||
crossing_duration: float,
|
||||
generation: int,
|
||||
) -> void:
|
||||
if (
|
||||
generation != _decorative_generation
|
||||
or not _decorative_presentation_active
|
||||
or not is_instance_valid(fish_control)
|
||||
):
|
||||
return
|
||||
var horizontal_bounds: Vector2 = get_decorative_fish_crossing_bounds(
|
||||
_decorative_fish_layer.size.x,
|
||||
fish_control.size.x,
|
||||
direction,
|
||||
)
|
||||
fish_control.position.x = lerpf(
|
||||
horizontal_bounds.x, horizontal_bounds.y, progress
|
||||
)
|
||||
var bobbed_y: float = (
|
||||
base_y
|
||||
+ sin(progress * crossing_duration * bob_speed) * bob_amplitude
|
||||
)
|
||||
fish_control.position.y = clampf(
|
||||
bobbed_y,
|
||||
8.0,
|
||||
maxf(8.0, _decorative_fish_layer.size.y - fish_control.size.y - 8.0)
|
||||
)
|
||||
fish_control.position = _snap_world_preview(fish_control.position)
|
||||
|
||||
|
||||
static func get_decorative_fish_crossing_bounds(
|
||||
layer_width: float,
|
||||
fish_width: float,
|
||||
direction: float,
|
||||
) -> Vector2:
|
||||
var outside_left: float = -fish_width - FISH_EDGE_MARGIN
|
||||
var outside_right: float = layer_width + FISH_EDGE_MARGIN
|
||||
return (
|
||||
Vector2(outside_left, outside_right)
|
||||
if direction > 0.0
|
||||
else Vector2(outside_right, outside_left)
|
||||
)
|
||||
|
||||
|
||||
func _on_decorative_fish_finished(
|
||||
fish_control: TextureRect,
|
||||
generation: int,
|
||||
) -> void:
|
||||
if generation != _decorative_generation:
|
||||
return
|
||||
_decorative_fish_tween = null
|
||||
if is_instance_valid(fish_control):
|
||||
fish_control.queue_free()
|
||||
if _decorative_fish == fish_control:
|
||||
_decorative_fish = null
|
||||
_schedule_next_decorative_fish(
|
||||
NEXT_FISH_DELAY_MIN,
|
||||
NEXT_FISH_DELAY_MAX
|
||||
)
|
||||
|
||||
|
||||
func _schedule_next_decorative_bubble_event(
|
||||
minimum_delay: float,
|
||||
maximum_delay: float,
|
||||
) -> void:
|
||||
if not _decorative_presentation_active or not visible:
|
||||
return
|
||||
_decorative_bubble_event_timer.start(
|
||||
_decorative_rng.randf_range(minimum_delay, maximum_delay)
|
||||
)
|
||||
|
||||
|
||||
func _on_decorative_bubble_event_timer_timeout() -> void:
|
||||
if not _decorative_presentation_active or not visible:
|
||||
return
|
||||
var available_slots: int = (
|
||||
MAX_DECORATIVE_BUBBLES - _get_idle_decorative_bubble_count()
|
||||
)
|
||||
if available_slots <= 0:
|
||||
_schedule_next_decorative_bubble_event(
|
||||
BUBBLE_EVENT_DELAY_MIN,
|
||||
BUBBLE_EVENT_DELAY_MAX
|
||||
)
|
||||
return
|
||||
var event_size: int = _choose_decorative_bubble_event_size()
|
||||
event_size = mini(event_size, available_slots)
|
||||
if not _spawn_decorative_bubble(_decorative_generation):
|
||||
_schedule_next_decorative_bubble_event(0.5, 1.0)
|
||||
return
|
||||
_pending_cluster_bubbles = event_size - 1
|
||||
if _pending_cluster_bubbles > 0:
|
||||
_start_decorative_bubble_cluster_timer()
|
||||
else:
|
||||
_schedule_next_decorative_bubble_event(
|
||||
BUBBLE_EVENT_DELAY_MIN,
|
||||
BUBBLE_EVENT_DELAY_MAX
|
||||
)
|
||||
|
||||
|
||||
func _choose_decorative_bubble_event_size() -> int:
|
||||
var roll: float = _decorative_rng.randf()
|
||||
if roll < 0.75:
|
||||
return 1
|
||||
if roll < 0.95:
|
||||
return 2
|
||||
return 3
|
||||
|
||||
|
||||
func _start_decorative_bubble_cluster_timer() -> void:
|
||||
_decorative_bubble_cluster_timer.start(
|
||||
_decorative_rng.randf_range(
|
||||
BUBBLE_CLUSTER_DELAY_MIN,
|
||||
BUBBLE_CLUSTER_DELAY_MAX
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _on_decorative_bubble_cluster_timer_timeout() -> void:
|
||||
if (
|
||||
not _decorative_presentation_active
|
||||
or not visible
|
||||
or _pending_cluster_bubbles <= 0
|
||||
):
|
||||
_pending_cluster_bubbles = 0
|
||||
return
|
||||
if _get_idle_decorative_bubble_count() < MAX_DECORATIVE_BUBBLES:
|
||||
_spawn_decorative_bubble(_decorative_generation)
|
||||
_pending_cluster_bubbles -= 1
|
||||
if _pending_cluster_bubbles > 0:
|
||||
_start_decorative_bubble_cluster_timer()
|
||||
else:
|
||||
_schedule_next_decorative_bubble_event(
|
||||
BUBBLE_EVENT_DELAY_MIN,
|
||||
BUBBLE_EVENT_DELAY_MAX
|
||||
)
|
||||
|
||||
|
||||
func _spawn_decorative_bubble(
|
||||
generation: int,
|
||||
start_y_ratio: float = -1.0,
|
||||
normalized_x_override: float = -1.0,
|
||||
is_transition_bubble: bool = false,
|
||||
) -> bool:
|
||||
if (
|
||||
generation != _decorative_generation
|
||||
or not _decorative_presentation_active
|
||||
or not visible
|
||||
or DECORATIVE_BUBBLE_TEXTURES.is_empty()
|
||||
):
|
||||
return false
|
||||
if is_transition_bubble:
|
||||
if _transition_bubble_ids.size() >= MAX_TRANSITION_BUBBLES:
|
||||
return false
|
||||
elif _get_idle_decorative_bubble_count() >= MAX_DECORATIVE_BUBBLES:
|
||||
return false
|
||||
var layer_size: Vector2 = _decorative_bubble_layer.size
|
||||
if layer_size.x <= 1.0 or layer_size.y <= 1.0:
|
||||
return false
|
||||
var texture: Texture2D = DECORATIVE_BUBBLE_TEXTURES[
|
||||
_decorative_rng.randi_range(
|
||||
0,
|
||||
DECORATIVE_BUBBLE_TEXTURES.size() - 1
|
||||
)
|
||||
]
|
||||
var presentation_scale: float = _decorative_rng.randf_range(
|
||||
BUBBLE_SCALE_MIN,
|
||||
BUBBLE_SCALE_MAX
|
||||
)
|
||||
var presentation_size: Vector2 = texture.get_size() * presentation_scale
|
||||
var bubble := TextureRect.new()
|
||||
bubble.name = "DecorativeBubble"
|
||||
bubble.texture = texture
|
||||
bubble.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
bubble.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
bubble.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
bubble.size = presentation_size
|
||||
bubble.modulate.a = _decorative_rng.randf_range(
|
||||
BUBBLE_OPACITY_MIN,
|
||||
BUBBLE_OPACITY_MAX
|
||||
)
|
||||
_decorative_bubble_layer.add_child(bubble)
|
||||
_decorative_bubbles.append(bubble)
|
||||
if is_transition_bubble:
|
||||
_transition_bubble_ids[bubble.get_instance_id()] = true
|
||||
|
||||
var normalized_x: float = normalized_x_override
|
||||
if normalized_x < 0.0:
|
||||
normalized_x = _decorative_rng.randf_range(0.08, 0.92)
|
||||
var drift_direction: float = (
|
||||
1.0 if _decorative_rng.randi_range(0, 1) == 1 else -1.0
|
||||
)
|
||||
var horizontal_drift: float = (
|
||||
_decorative_rng.randf_range(
|
||||
BUBBLE_DRIFT_MIN,
|
||||
BUBBLE_DRIFT_MAX
|
||||
)
|
||||
* drift_direction
|
||||
)
|
||||
var wobble_amplitude: float = _decorative_rng.randf_range(
|
||||
BUBBLE_WOBBLE_MIN,
|
||||
BUBBLE_WOBBLE_MAX
|
||||
)
|
||||
var wobble_cycles: float = _decorative_rng.randf_range(0.8, 1.6)
|
||||
var wobble_phase: float = _decorative_rng.randf_range(0.0, TAU)
|
||||
var travel_duration: float = _decorative_rng.randf_range(
|
||||
BUBBLE_TRAVEL_DURATION_MIN,
|
||||
BUBBLE_TRAVEL_DURATION_MAX
|
||||
)
|
||||
if start_y_ratio >= 0.0:
|
||||
var full_start_y: float = (
|
||||
layer_size.y + presentation_size.y + BUBBLE_EDGE_MARGIN
|
||||
)
|
||||
var end_y: float = -presentation_size.y - BUBBLE_EDGE_MARGIN
|
||||
var burst_start_y: float = (
|
||||
start_y_ratio * layer_size.y - presentation_size.y * 0.5
|
||||
)
|
||||
var remaining_distance: float = maxf(burst_start_y - end_y, 1.0)
|
||||
var full_distance: float = maxf(full_start_y - end_y, 1.0)
|
||||
travel_duration *= remaining_distance / full_distance
|
||||
_update_decorative_bubble(
|
||||
0.0,
|
||||
bubble,
|
||||
normalized_x,
|
||||
horizontal_drift,
|
||||
wobble_amplitude,
|
||||
wobble_cycles,
|
||||
wobble_phase,
|
||||
start_y_ratio,
|
||||
generation
|
||||
)
|
||||
var bubble_tween: Tween = create_tween()
|
||||
_decorative_bubble_tweens[bubble.get_instance_id()] = bubble_tween
|
||||
bubble_tween.tween_method(
|
||||
_update_decorative_bubble.bind(
|
||||
bubble,
|
||||
normalized_x,
|
||||
horizontal_drift,
|
||||
wobble_amplitude,
|
||||
wobble_cycles,
|
||||
wobble_phase,
|
||||
start_y_ratio,
|
||||
generation
|
||||
),
|
||||
0.0,
|
||||
1.0,
|
||||
travel_duration
|
||||
)
|
||||
bubble_tween.finished.connect(
|
||||
_on_decorative_bubble_finished.bind(bubble, generation),
|
||||
CONNECT_ONE_SHOT
|
||||
)
|
||||
return true
|
||||
|
||||
|
||||
func _update_decorative_bubble(
|
||||
progress: float,
|
||||
bubble: TextureRect,
|
||||
normalized_x: float,
|
||||
horizontal_drift: float,
|
||||
wobble_amplitude: float,
|
||||
wobble_cycles: float,
|
||||
wobble_phase: float,
|
||||
start_y_ratio: float,
|
||||
generation: int,
|
||||
) -> void:
|
||||
if (
|
||||
generation != _decorative_generation
|
||||
or not _decorative_presentation_active
|
||||
or not is_instance_valid(bubble)
|
||||
):
|
||||
return
|
||||
var layer_size: Vector2 = _decorative_bubble_layer.size
|
||||
var start_y: float = (
|
||||
layer_size.y + bubble.size.y + BUBBLE_EDGE_MARGIN
|
||||
)
|
||||
if start_y_ratio >= 0.0:
|
||||
start_y = start_y_ratio * layer_size.y - bubble.size.y * 0.5
|
||||
var end_y: float = -bubble.size.y - BUBBLE_EDGE_MARGIN
|
||||
var base_x: float = normalized_x * layer_size.x
|
||||
var wobble: float = sin(
|
||||
wobble_phase + progress * TAU * wobble_cycles
|
||||
) * wobble_amplitude
|
||||
bubble.position = _snap_world_preview(Vector2(
|
||||
base_x
|
||||
+ horizontal_drift * progress
|
||||
+ wobble
|
||||
- bubble.size.x * 0.5,
|
||||
lerpf(start_y, end_y, progress)
|
||||
))
|
||||
|
||||
|
||||
func _on_decorative_bubble_finished(
|
||||
bubble: TextureRect,
|
||||
generation: int,
|
||||
) -> void:
|
||||
if generation != _decorative_generation:
|
||||
return
|
||||
if is_instance_valid(bubble):
|
||||
_decorative_bubble_tweens.erase(bubble.get_instance_id())
|
||||
_transition_bubble_ids.erase(bubble.get_instance_id())
|
||||
_decorative_bubbles.erase(bubble)
|
||||
bubble.queue_free()
|
||||
|
||||
|
||||
func _get_idle_decorative_bubble_count() -> int:
|
||||
return _decorative_bubbles.size() - _transition_bubble_ids.size()
|
||||
|
||||
|
||||
func _emit_navigation_bubble_flurry() -> void:
|
||||
# Page changes now use a quick fade and scale without travel bubbles.
|
||||
pass
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
_stop_decorative_presentation()
|
||||
|
|
|
|||
|
|
@ -1,29 +1,36 @@
|
|||
[gd_scene load_steps=25 format=3]
|
||||
[gd_scene load_steps=28 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/title_screen.gd" id="1_script"]
|
||||
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="2_theme"]
|
||||
[ext_resource type="PackedScene" path="res://ui/settings_panel.tscn" id="3_settings"]
|
||||
[ext_resource type="Shader" path="res://ui/title_water_background.gdshader" id="4_water_shader"]
|
||||
[ext_resource type="Texture2D" path="res://ui/assets/title/netfishing_logo.png" id="5_logo"]
|
||||
[ext_resource type="Shader" path="res://ui/player_menu_pattern.gdshader" id="4_grass_shader"]
|
||||
[ext_resource type="Texture2D" path="res://ui/assets/title/straywild_logo.png" id="5_logo"]
|
||||
[ext_resource type="Shader" path="res://ui/title_logo_underwater.gdshader" id="6_logo_shader"]
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_button.gd" id="7_bubble_button"]
|
||||
[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_cluster.gd" id="8_bubble_cluster"]
|
||||
[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="9_bubble_profile"]
|
||||
[ext_resource type="PackedScene" path="res://ui/title_confirmation_bubble_page.tscn" id="10_confirmation_page"]
|
||||
[ext_resource type="PackedScene" path="res://ui/network/join_game_page.tscn" id="11_join_page"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/pictograms/online_dark.png" id="12_online_dark"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/pictograms/settings_dark.png" id="13_settings_dark"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/pictograms/x_dark.png" id="14_x_dark"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/new_menu/online.png" id="12_online_dark"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/new_menu/settings.png" id="13_settings_dark"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/new_menu/close.png" id="14_x_dark"]
|
||||
[ext_resource type="PackedScene" path="res://ui/title_credits_page.tscn" id="15_credits_page"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/main_menu/continue.png" id="16_continue"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/new_menu/play.png" id="16_continue"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/main_menu/new_game.png" id="17_new_game"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/main_menu/credits.png" id="18_credits"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/new_menu/credits.png" id="18_credits"]
|
||||
[ext_resource type="Texture2D" path="res://ui/icons/main_menu/delete_save.png" id="19_delete_save"]
|
||||
[ext_resource type="PackedScene" path="res://ui/new_game_setup_page.tscn" id="20_new_game_setup"]
|
||||
[ext_resource type="PackedScene" path="res://ui/save_slots_page.tscn" id="21_save_slots"]
|
||||
[ext_resource type="Texture2D" path="res://world/generation/chunks/assets/chunk_0000_grass_lite.png" id="22_grass_pattern"]
|
||||
[ext_resource type="Resource" path="res://ui/components/bubble_menu/title_menu_profile.tres" id="23_title_menu_profile"]
|
||||
[ext_resource type="Resource" path="res://ui/components/bubble_menu/title_secondary_menu_profile.tres" id="24_title_secondary_menu_profile"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water"]
|
||||
shader = ExtResource("4_water_shader")
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_grass"]
|
||||
shader = ExtResource("4_grass_shader")
|
||||
shader_parameter/pattern_texture = ExtResource("22_grass_pattern")
|
||||
shader_parameter/source_tile_size = Vector2(128, 128)
|
||||
shader_parameter/display_scale = 1.0
|
||||
shader_parameter/scroll_velocity_pixels = Vector2(-7.5, -7.5)
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_logo"]
|
||||
shader = ExtResource("6_logo_shader")
|
||||
|
|
@ -39,6 +46,17 @@ corner_radius_top_right = 14
|
|||
corner_radius_bottom_right = 14
|
||||
corner_radius_bottom_left = 14
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_continue_stats_drawer"]
|
||||
content_margin_left = 10.0
|
||||
content_margin_top = 18.0
|
||||
content_margin_right = 10.0
|
||||
content_margin_bottom = 2.0
|
||||
bg_color = Color(0.031, 0.122, 0.169, 1)
|
||||
corner_radius_top_left = 14
|
||||
corner_radius_top_right = 14
|
||||
corner_radius_bottom_right = 14
|
||||
corner_radius_bottom_left = 14
|
||||
|
||||
[node name="TitleScreen" type="Control"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 200
|
||||
|
|
@ -55,7 +73,7 @@ script = ExtResource("1_script")
|
|||
[node name="Background" type="ColorRect" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
material = SubResource("ShaderMaterial_title_water")
|
||||
material = SubResource("ShaderMaterial_title_grass")
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
|
@ -64,42 +82,6 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="DecorativeFishLayer" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
z_index = 1
|
||||
clip_contents = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="DecorativeFishTimer" type="Timer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
one_shot = true
|
||||
|
||||
[node name="DecorativeBubbleLayer" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
z_index = 2
|
||||
clip_contents = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="DecorativeBubbleEventTimer" type="Timer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
one_shot = true
|
||||
|
||||
[node name="DecorativeBubbleClusterTimer" type="Timer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
one_shot = true
|
||||
|
||||
[node name="ResponsiveTitleStage" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
z_index = 10
|
||||
|
|
@ -122,13 +104,13 @@ mouse_filter = 1
|
|||
unique_name_in_owner = true
|
||||
z_index = 12
|
||||
layout_mode = 1
|
||||
anchor_top = 1.0
|
||||
anchor_top = 0.5
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -104.0
|
||||
offset_bottom = -48.0
|
||||
anchor_bottom = 0.5
|
||||
offset_top = 45.0
|
||||
offset_bottom = 101.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="StartPromptLabel" type="Label" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/StartPromptCenter"]
|
||||
|
|
@ -136,8 +118,6 @@ unique_name_in_owner = true
|
|||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||
theme_override_colors/font_outline_color = Color(0.02, 0.075, 0.11, 0.9)
|
||||
theme_override_constants/outline_size = 3
|
||||
theme_override_font_sizes/font_size = 39
|
||||
text = "press any key to start"
|
||||
horizontal_alignment = 1
|
||||
|
|
@ -202,27 +182,33 @@ texture = ExtResource("5_logo")
|
|||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="VersionRow" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/BrandingSlot/BrandingMotionRoot/BrandingContent"]
|
||||
[node name="VersionRow" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(0, 18)
|
||||
layout_mode = 2
|
||||
z_index = 12
|
||||
custom_minimum_size = Vector2(280, 28)
|
||||
layout_mode = 1
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -140.0
|
||||
offset_top = -38.0
|
||||
offset_right = 140.0
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="VersionAnchor" type="CenterContainer" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/BrandingSlot/BrandingMotionRoot/BrandingContent/VersionRow"]
|
||||
[node name="VersionAnchor" type="CenterContainer" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/VersionRow"]
|
||||
layout_mode = 1
|
||||
anchor_left = 0.7
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.7
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -140.0
|
||||
offset_top = -17.0
|
||||
offset_right = 140.0
|
||||
offset_bottom = 11.0
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="PlaytestLabel" type="Label" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/BrandingSlot/BrandingMotionRoot/BrandingContent/VersionRow/VersionAnchor"]
|
||||
[node name="PlaytestLabel" type="Label" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/VersionRow/VersionAnchor"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.682, 0.733, 0.761, 1)
|
||||
|
|
@ -242,47 +228,75 @@ layout_mode = 2
|
|||
|
||||
[node name="BubbleLayoutSlot" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(440, 318)
|
||||
custom_minimum_size = Vector2(500, 360)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="BubbleMotionRoot" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 0
|
||||
offset_right = 440.0
|
||||
offset_bottom = 318.0
|
||||
offset_right = 500.0
|
||||
offset_bottom = 360.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="BubbleField" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(440, 318)
|
||||
custom_minimum_size = Vector2(500, 360)
|
||||
layout_mode = 0
|
||||
offset_right = 440.0
|
||||
offset_bottom = 318.0
|
||||
offset_right = 500.0
|
||||
offset_top = -10.0
|
||||
offset_bottom = 350.0
|
||||
script = ExtResource("8_bubble_cluster")
|
||||
profile = ExtResource("9_bubble_profile")
|
||||
profile = ExtResource("23_title_menu_profile")
|
||||
desktop_reference_size = Vector2(500, 360)
|
||||
collision_separation_enabled = false
|
||||
|
||||
[node name="PlayButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
offset_left = 106.0
|
||||
offset_top = 71.0
|
||||
offset_right = 290.0
|
||||
offset_bottom = 249.0
|
||||
offset_left = 36.0
|
||||
offset_top = 30.0
|
||||
offset_right = 366.0
|
||||
offset_bottom = 360.0
|
||||
texture_filter = 1
|
||||
icon = ExtResource("16_continue")
|
||||
tooltip_text = "play"
|
||||
accessibility_name = "play"
|
||||
accessibility_name = "play straywild"
|
||||
script = ExtResource("7_bubble_button")
|
||||
profile = ExtResource("9_bubble_profile")
|
||||
neutral_size = Vector2(184, 178)
|
||||
desktop_anchor = Vector2(198, 160)
|
||||
compact_anchor = Vector2(198, 164)
|
||||
minimum_font_size = 19
|
||||
maximum_font_size = 30
|
||||
horizontal_amplitude = 1.8
|
||||
vertical_amplitude = 4.6
|
||||
motion_period = 5.8
|
||||
deformation_amplitude = 0.01
|
||||
deformation_period = 6.7
|
||||
profile = ExtResource("23_title_menu_profile")
|
||||
neutral_size = Vector2(330, 330)
|
||||
desktop_anchor = Vector2(201, 195)
|
||||
compact_anchor = Vector2(201, 195)
|
||||
minimum_font_size = 28
|
||||
maximum_font_size = 36
|
||||
icon_fill_ratio_override = 0.9
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
hover_wiggle_amplitude = Vector2(7, 6)
|
||||
hover_wiggle_period = 3.8
|
||||
hover_drawer_text = "play straywild"
|
||||
hover_drawer_mode = 1
|
||||
elliptical_hit_area = false
|
||||
|
||||
[node name="ContinueStatsDrawer" type="RichTextLabel" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField/PlayButton"]
|
||||
unique_name_in_owner = true
|
||||
show_behind_parent = true
|
||||
z_index = -1
|
||||
visible = false
|
||||
layout_mode = 0
|
||||
offset_left = 22.0
|
||||
offset_top = 314.0
|
||||
offset_right = 308.0
|
||||
offset_bottom = 360.0
|
||||
pivot_offset = Vector2(143, 0)
|
||||
scale = Vector2(1, 0.001)
|
||||
mouse_filter = 2
|
||||
theme_override_font_sizes/normal_font_size = 15
|
||||
text = ""
|
||||
bbcode_enabled = true
|
||||
scroll_active = false
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
theme_override_styles/normal = SubResource("StyleBoxFlat_continue_stats_drawer")
|
||||
|
||||
[node name="NewGameButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
|
|
@ -313,75 +327,75 @@ deformation_period = 5.9
|
|||
|
||||
[node name="SettingsButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
offset_left = 254.0
|
||||
offset_top = 12.0
|
||||
offset_right = 374.0
|
||||
offset_bottom = 128.0
|
||||
offset_left = 384.0
|
||||
offset_top = 116.0
|
||||
offset_right = 456.0
|
||||
offset_bottom = 188.0
|
||||
texture_filter = 1
|
||||
icon = ExtResource("13_settings_dark")
|
||||
tooltip_text = "settings"
|
||||
accessibility_name = "settings"
|
||||
script = ExtResource("7_bubble_button")
|
||||
profile = ExtResource("9_bubble_profile")
|
||||
desktop_anchor = Vector2(314, 70)
|
||||
compact_anchor = Vector2(333, 75)
|
||||
compact_minimum_size = Vector2(94, 90)
|
||||
profile = ExtResource("24_title_secondary_menu_profile")
|
||||
neutral_size = Vector2(72, 72)
|
||||
desktop_anchor = Vector2(420, 152)
|
||||
compact_anchor = Vector2(420, 152)
|
||||
minimum_font_size = 15
|
||||
maximum_font_size = 22
|
||||
vertical_amplitude = 3.7
|
||||
motion_period = 4.9
|
||||
motion_phase = 2.5
|
||||
deformation_period = 6.3
|
||||
maximum_font_size = 20
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
hover_wiggle_amplitude = Vector2(2.4, 1.2)
|
||||
hover_wiggle_period = 1.9
|
||||
hover_drawer_text = "settings"
|
||||
elliptical_hit_area = false
|
||||
|
||||
[node name="CreditsButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
offset_left = 54.0
|
||||
offset_top = 209.0
|
||||
offset_right = 138.0
|
||||
offset_bottom = 291.0
|
||||
offset_left = 384.0
|
||||
offset_top = 202.0
|
||||
offset_right = 456.0
|
||||
offset_bottom = 274.0
|
||||
texture_filter = 1
|
||||
icon = ExtResource("18_credits")
|
||||
tooltip_text = "credits"
|
||||
accessibility_name = "credits"
|
||||
script = ExtResource("7_bubble_button")
|
||||
profile = ExtResource("9_bubble_profile")
|
||||
neutral_size = Vector2(84, 82)
|
||||
desktop_anchor = Vector2(96, 250)
|
||||
compact_anchor = Vector2(82, 258)
|
||||
compact_minimum_size = Vector2(62, 62)
|
||||
minimum_font_size = 12
|
||||
maximum_font_size = 17
|
||||
horizontal_amplitude = 1.4
|
||||
vertical_amplitude = 3.0
|
||||
motion_period = 5.0
|
||||
motion_phase = 1.8
|
||||
deformation_amplitude = 0.015
|
||||
deformation_period = 5.6
|
||||
profile = ExtResource("24_title_secondary_menu_profile")
|
||||
neutral_size = Vector2(72, 72)
|
||||
desktop_anchor = Vector2(420, 238)
|
||||
compact_anchor = Vector2(420, 238)
|
||||
minimum_font_size = 15
|
||||
maximum_font_size = 20
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
hover_wiggle_amplitude = Vector2(2.4, 1.2)
|
||||
hover_wiggle_period = 1.9
|
||||
hover_drawer_text = "credits"
|
||||
elliptical_hit_area = false
|
||||
|
||||
[node name="JoinGameButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
offset_left = 21.0
|
||||
offset_top = 11.0
|
||||
offset_right = 143.0
|
||||
offset_bottom = 129.0
|
||||
offset_left = 384.0
|
||||
offset_top = 30.0
|
||||
offset_right = 456.0
|
||||
offset_bottom = 102.0
|
||||
texture_filter = 1
|
||||
icon = ExtResource("12_online_dark")
|
||||
tooltip_text = "join game"
|
||||
accessibility_name = "join game"
|
||||
accessibility_name = "online"
|
||||
script = ExtResource("7_bubble_button")
|
||||
profile = ExtResource("9_bubble_profile")
|
||||
neutral_size = Vector2(122, 118)
|
||||
desktop_anchor = Vector2(82, 70)
|
||||
compact_anchor = Vector2(63, 75)
|
||||
compact_minimum_size = Vector2(82, 80)
|
||||
profile = ExtResource("24_title_secondary_menu_profile")
|
||||
neutral_size = Vector2(72, 72)
|
||||
desktop_anchor = Vector2(420, 66)
|
||||
compact_anchor = Vector2(420, 66)
|
||||
minimum_font_size = 15
|
||||
maximum_font_size = 22
|
||||
horizontal_amplitude = 1.7
|
||||
vertical_amplitude = 3.8
|
||||
motion_period = 5.2
|
||||
motion_phase = 3.1
|
||||
deformation_amplitude = 0.015
|
||||
deformation_period = 5.7
|
||||
maximum_font_size = 20
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
hover_wiggle_amplitude = Vector2(2.4, 1.2)
|
||||
hover_wiggle_period = 1.9
|
||||
hover_drawer_text = "online"
|
||||
elliptical_hit_area = false
|
||||
|
||||
[node name="DeleteSaveButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
|
|
@ -411,35 +425,41 @@ deformation_period = 5.4
|
|||
|
||||
[node name="QuitButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
|
||||
unique_name_in_owner = true
|
||||
offset_left = 255.0
|
||||
offset_top = 204.0
|
||||
offset_right = 349.0
|
||||
offset_bottom = 296.0
|
||||
offset_left = 384.0
|
||||
offset_top = 288.0
|
||||
offset_right = 456.0
|
||||
offset_bottom = 360.0
|
||||
texture_filter = 1
|
||||
icon = ExtResource("14_x_dark")
|
||||
tooltip_text = "quit"
|
||||
accessibility_name = "quit"
|
||||
accessibility_name = "close"
|
||||
script = ExtResource("7_bubble_button")
|
||||
profile = ExtResource("9_bubble_profile")
|
||||
neutral_size = Vector2(94, 92)
|
||||
desktop_anchor = Vector2(302, 250)
|
||||
compact_anchor = Vector2(317, 254)
|
||||
compact_minimum_size = Vector2(68, 68)
|
||||
profile = ExtResource("24_title_secondary_menu_profile")
|
||||
neutral_size = Vector2(72, 72)
|
||||
desktop_anchor = Vector2(420, 324)
|
||||
compact_anchor = Vector2(420, 324)
|
||||
minimum_font_size = 14
|
||||
maximum_font_size = 18
|
||||
horizontal_amplitude = 1.4
|
||||
vertical_amplitude = 3.2
|
||||
motion_period = 4.2
|
||||
motion_phase = 4.8
|
||||
deformation_amplitude = 0.02
|
||||
deformation_period = 4.8
|
||||
maximum_font_size = 20
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
hover_wiggle_amplitude = Vector2(2.4, 1.2)
|
||||
hover_wiggle_period = 1.9
|
||||
hover_drawer_text = "close"
|
||||
elliptical_hit_area = false
|
||||
|
||||
[node name="FeedbackLabel" type="RichTextLabel" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent"]
|
||||
[node name="FeedbackLabel" type="RichTextLabel" parent="ResponsiveTitleStage/TitlePresentationScaleRoot"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 12
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(430, 44)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
custom_minimum_size = Vector2(500, 44)
|
||||
layout_mode = 1
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = 224.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 268.0
|
||||
grow_horizontal = 2
|
||||
text = ""
|
||||
bbcode_enabled = true
|
||||
scroll_active = false
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
shader_type canvas_item;
|
||||
|
||||
uniform vec4 surface_color : source_color = vec4(0.10, 0.45, 0.62, 1.0);
|
||||
uniform vec4 middle_color : source_color = vec4(0.055, 0.285, 0.40, 1.0);
|
||||
uniform vec4 depth_color : source_color = vec4(0.02, 0.16, 0.27, 1.0);
|
||||
uniform vec2 virtual_pixel_density = vec2(320.0, 180.0);
|
||||
uniform float color_step_count : hint_range(2.0, 16.0, 1.0) = 14.0;
|
||||
uniform float continuous_depth_blend : hint_range(0.0, 0.25, 0.01) = 0.12;
|
||||
uniform float wave_speed : hint_range(0.0, 0.5, 0.01) = 0.10;
|
||||
uniform float wave_scale : hint_range(0.5, 8.0, 0.1) = 2.4;
|
||||
uniform float wave_strength : hint_range(0.0, 0.05, 0.001) = 0.012;
|
||||
uniform float caustic_strength : hint_range(0.0, 0.08, 0.001) = 0.018;
|
||||
uniform bool animation_enabled = true;
|
||||
|
||||
void fragment() {
|
||||
vec2 grid_size = max(virtual_pixel_density, vec2(1.0));
|
||||
vec2 pixel_uv = (floor(UV * grid_size) + vec2(0.5)) / grid_size;
|
||||
float continuous_depth = pixel_uv.y;
|
||||
float caustic_level = 0.0;
|
||||
if (animation_enabled) {
|
||||
float motion = TIME * wave_speed;
|
||||
float broad_wave = sin(
|
||||
pixel_uv.x * wave_scale + motion
|
||||
);
|
||||
float secondary_wave = sin(
|
||||
pixel_uv.x * 1.1 + pixel_uv.y * 1.6 - motion * 0.65
|
||||
);
|
||||
float movement_falloff = 1.0 - pixel_uv.y * 0.75;
|
||||
float depth_displacement = (
|
||||
(broad_wave * 0.65 + secondary_wave * 0.35)
|
||||
* wave_strength
|
||||
* movement_falloff
|
||||
);
|
||||
continuous_depth = clamp(
|
||||
pixel_uv.y
|
||||
+ depth_displacement,
|
||||
0.0,
|
||||
1.0
|
||||
);
|
||||
float caustic_wave = clamp(
|
||||
(
|
||||
sin(
|
||||
pixel_uv.x * 4.0
|
||||
+ pixel_uv.y * 1.2
|
||||
+ motion * 0.7
|
||||
)
|
||||
* sin(
|
||||
pixel_uv.x * 1.7
|
||||
- pixel_uv.y * 2.2
|
||||
- motion * 0.55
|
||||
)
|
||||
- 0.25
|
||||
) / 0.75,
|
||||
0.0,
|
||||
1.0
|
||||
);
|
||||
caustic_level = floor(caustic_wave * 3.0) / 3.0;
|
||||
}
|
||||
float depth_steps = max(2.0, floor(color_step_count));
|
||||
float band_index = floor(
|
||||
continuous_depth * (depth_steps - 1.0) + 0.5
|
||||
);
|
||||
float band_depth = band_index / (depth_steps - 1.0);
|
||||
float display_depth = mix(
|
||||
band_depth,
|
||||
continuous_depth,
|
||||
clamp(continuous_depth_blend, 0.0, 0.25)
|
||||
);
|
||||
|
||||
vec3 water_color;
|
||||
if (display_depth < 0.5) {
|
||||
water_color = mix(
|
||||
surface_color.rgb,
|
||||
middle_color.rgb,
|
||||
display_depth * 2.0
|
||||
);
|
||||
} else {
|
||||
water_color = mix(
|
||||
middle_color.rgb,
|
||||
depth_color.rgb,
|
||||
(display_depth - 0.5) * 2.0
|
||||
);
|
||||
}
|
||||
|
||||
float upper_water_mask = 1.0 - smoothstep(
|
||||
0.18,
|
||||
0.34,
|
||||
pixel_uv.y
|
||||
);
|
||||
water_color += (
|
||||
vec3(0.05, 0.12, 0.14)
|
||||
* caustic_level
|
||||
* upper_water_mask
|
||||
* caustic_strength
|
||||
);
|
||||
COLOR = vec4(clamp(water_color, vec3(0.0), vec3(1.0)), 1.0);
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
uid://c8s1g7tn771du
|
||||