Compare commits

...

3 Commits

Author SHA1 Message Date
09a5c40994 animation pro 增加 mov x 范围移动与预览功能 2025-06-17 17:10:48 +08:00
e2ca7f48c4 使用官方 git 插件 2025-06-17 15:45:24 +08:00
dbbe306556 鱼眼镜头 shader 验证 2025-06-17 15:18:56 +08:00
29 changed files with 1780 additions and 221 deletions

1
.gitattributes vendored
View File

@ -1,2 +1,3 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
*.tscn merge=union

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016-2023 The Godot Engine community
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
[configuration]
entry_symbol = "git_plugin_init"
compatibility_minimum = "4.2.0"
[libraries]
linux.editor.x86_64 = "linux/libgit_plugin.linux.editor.x86_64.so"
macos.editor = "macos/libgit_plugin.macos.editor.universal.dylib"
windows.editor.x86_64 = "windows/libgit_plugin.windows.editor.x86_64.dll"

View File

@ -0,0 +1 @@
uid://c84g73p4ucply

View File

@ -14,12 +14,20 @@ class_name ProAnimatedSprite2D extends AnimatedSprite2D
else:
light2d.blend_mode = Light2D.BLEND_MODE_SUB
light_energy = val * modulate.a
@export var debug_mov_animation := ""
@export_tool_button("debug 刷新 mov 目标") var debug_mov_projection := _debug_mov_projection
const ACTION_CONFIG = {
"animation_intro": "", "intro_loop": 1, "animation_wait_time": 0.0, "animation_next": ""
}
# 参数 {duration} 目前无需求,暂且保留
const MOVE_CONFIG = {"animation": "", "velocity": Vector2.ZERO, "duration": 10000000.0}
const MOVE_CONFIG = {
"animation": "",
"velocity": Vector2.ZERO,
"duration": 10000000.0,
"movement_x": 0.0,
"animation_next": ""
}
static func new_move_config() -> Dictionary:
@ -30,13 +38,15 @@ static func new_action_config() -> Dictionary:
return ACTION_CONFIG.duplicate()
@onready var debug_mov_onion_sprite2d = $DebugMovOnionSkinSprite2D as Sprite2D
# 从 intro 到 next 的配置信息
var auto_checkout_dict = {
# intro -> {state_config instance}
}
# 播放 animation 的同时,进行移动
var animation_velocity = {
# animation -> velocity
var animation_mov_dict = {
# animation -> {velocity, ...}
}
var light2d := PointLight2D.new()
@ -47,16 +57,29 @@ func _ready() -> void:
add_child(light2d)
frame_changed.connect(_on_frame_changed)
if Engine.is_editor_hint():
_debug_mov_projection()
return
_load_config()
debug_mov_onion_sprite2d.queue_free()
if autostart and animation:
# 制造一点错差
frame = randi() % sprite_frames.get_frame_count(animation)
play()
animation_finished.connect(_on_animation_finished)
animation_looped.connect(_on_animation_finished)
animation_changed.connect(_on_animation_start)
animation_looped.connect(_on_animation_start)
animation_finished.connect(_on_animation_finished)
animation_looped.connect(_on_animation_finished)
func _debug_mov_projection():
_load_config()
if debug_mov_animation and animation_mov_dict.has(debug_mov_animation):
var mov_config = animation_mov_dict[debug_mov_animation]
# 展示 accumulated animation 的目标位置
debug_mov_onion_sprite2d.position.x = mov_config.movement_x
debug_mov_onion_sprite2d.texture = sprite_frames.get_frame_texture(debug_mov_animation, 0)
elif debug_mov_animation:
printerr("Debug move config not found:", debug_mov_animation)
func _load_config():
@ -74,7 +97,7 @@ func _load_config():
move_configs[i].merge(MOVE_CONFIG)
var move_config = move_configs[i]
if sprite_frames and sprite_frames.has_animation(move_config.animation):
animation_velocity[move_config.animation] = move_config.velocity
animation_mov_dict[move_config.animation] = move_config
func _on_frame_changed():
@ -110,24 +133,46 @@ func _on_animation_finished() -> void:
var velocity := Vector2.ZERO
var mov_x := 0.0
var mov_x_next_animation := ""
var accumulated_mov_x := 0.0
var prev_animation := ""
func _on_animation_start():
if not animation or not animation_velocity.has(animation):
velocity = Vector2.ZERO
if prev_animation != animation:
accumulated_mov_x = 0.0
prev_animation = animation
velocity = Vector2.ZERO
mov_x = 0.0
mov_x_next_animation = ""
if not animation or not animation_mov_dict.has(animation):
return
velocity = animation_velocity[animation] * speed_scale
# if GlobalConfig.DEBUG:
# print("animation ", animation, " velocity=", velocity)
# velocity = animation_mov_dict[animation] * speed_scale
velocity = animation_mov_dict[animation].velocity
mov_x_next_animation = animation_mov_dict[animation].animation_next
if mov_x_next_animation:
# 只有在 next animation 存在时mov_x 才有意义
mov_x = animation_mov_dict[animation].movement_x
func _physics_process(delta: float) -> void:
if Engine.is_editor_hint() or not velocity or not is_playing():
return
var diff_x = velocity.x * delta
if flip_h:
position.x -= velocity.x * delta
position.x -= diff_x
else:
position.x += velocity.x * delta
position.x += diff_x
# 检查是否切换 animation
if mov_x != 0.0 and mov_x_next_animation:
accumulated_mov_x += diff_x
if absf(accumulated_mov_x) >= absf(mov_x):
if GlobalConfig.DEBUG:
print(
"切换 animation:", mov_x_next_animation, " accumulated_mov_x=", accumulated_mov_x
)
play(mov_x_next_animation)
if not velocity.y:
return
if flip_v:
@ -138,7 +183,9 @@ func _physics_process(delta: float) -> void:
# temporary set velocity
func set_animation_velocity(anim: String, v: Vector2) -> void:
animation_velocity[anim] = v
if not animation_mov_dict.has(anim):
animation_mov_dict[anim] = new_move_config()
animation_mov_dict[anim].velocity = v
if GlobalConfig.DEBUG:
print("set_animation_velocity:", anim, v)

View File

@ -3,5 +3,7 @@
[ext_resource type="Script" uid="uid://cphfob11f7atx" path="res://addons/property-inspector/pro_animation_sprite2d/pro_animated_sprite.gd" id="1_21eda"]
[node name="AutoplayAnimatedSprite" type="AnimatedSprite2D"]
position = Vector2(-1, -1)
script = ExtResource("1_21eda")
[node name="DebugMovOnionSkinSprite2D" type="Sprite2D" parent="."]
modulate = Color(1, 1, 1, 0.501961)

View File

@ -72,11 +72,41 @@ func _add_line(check_updating := false):
h_box.add_child(line_edit)
line_edit.focus_exited.connect(_on_line_edit_text_submitted.bind(line_edit, id, "velocity:y"))
line_edit.text_submitted.connect(_on_line_edit_text_submitted.bind(id, "velocity:y"))
# next row
line_box.add_child(h_box)
h_box = HBoxContainer.new()
# add label
label = Label.new()
label.text = "mov_x:"
h_box.add_child(label)
# add movement_x edit
line_edit = LineEdit.new()
line_edit.text = str(prop.movement_x)
h_box.add_child(line_edit)
line_edit.expand_to_text_length = true
line_edit.focus_exited.connect(
_on_line_edit_text_submitted.bind(line_edit, id, "movement_x")
)
line_edit.text_submitted.connect(_on_line_edit_text_submitted.bind(id, "movement_x"))
# add label
label = Label.new()
label.text = "next:"
h_box.add_child(label)
# add animation next edit
line_edit = LineEdit.new()
line_edit.text = str(prop.animation_next)
h_box.add_child(line_edit)
line_edit.expand_to_text_length = true
line_edit.focus_exited.connect(
_on_line_edit_text_submitted.bind(line_edit, id, "animation_next")
)
line_edit.text_submitted.connect(_on_line_edit_text_submitted.bind(id, "animation_next"))
# add delete button
var button = Button.new()
button.icon = EditorInterface.get_editor_theme().get_icon("Remove", "EditorIcons")
button.pressed.connect(_on_delete_button_pressed.bind(id))
h_box.add_child(button)
# finish
line_box.add_child(h_box)
v_box.add_child(line_box)
line_nodes.append(line_box)
@ -126,6 +156,10 @@ func _on_line_edit_text_submitted(text, id, property):
_get_property()[id]["velocity"].y = float(text)
elif property == "duration":
_get_property()[id]["duration"] = float(text)
elif property == "movement_x":
_get_property()[id]["movement_x"] = float(text)
elif property == "animation_next":
_get_property()[id]["animation_next"] = text
_update_change()

View File

@ -1,4 +1,7 @@
class_name StateMoveConfigResource extends Resource
@export var animation := ""
@export var velocity := Vector2(0, 0)
@export var velocity := Vector2(0, 0)
# 如果 movement_x != 0 (可正可负), 移动 movement_x 后播放 animation_next
@export var movement_x := 0.0
@export var animation_next := ""

View File

@ -83,6 +83,11 @@ window/subwindows/embed_subwindows=false
window/stretch/mode="canvas_items"
window/per_pixel_transparency/allowed=true
[editor]
version_control/plugin_name="GitPlugin"
version_control/autoload_on_startup=true
[editor_plugins]
enabled=PackedStringArray("res://addons/debug_menu/plugin.cfg", "res://addons/dialogue_manager/plugin.cfg", "res://addons/gif-importer/plugin.cfg", "res://addons/project-statistics/plugin.cfg", "res://addons/property-inspector/plugin.cfg")

View File

@ -3,80 +3,16 @@ class_name Sfx2D extends AudioStreamPlayer2D
@export var loop := false
const sfx_root_path = "res://asset/audio/sfx/"
@export_enum("child", "ghost", "lvping", "ui", "c01", "c02") var dir := "ui":
set(value):
dir = value
if Engine.is_editor_hint():
_update_files()
var file: String
var current_files := PackedStringArray()
func _ready() -> void:
bus = &"game_sfx"
finished.connect(_on_finished)
# TODO 暂时停用其额外效果
# # 仅在编辑器模式下加载音频 stream
# if Engine.is_editor_hint():
# _update_files()
# _reload_sfx()
# notify_property_list_changed()
func _on_finished() -> void:
if loop:
play()
func _reload_sfx():
var path = sfx_root_path + dir + "/" + file
if file and dir and FileAccess.file_exists(path):
stream = load(sfx_root_path + dir + "/" + file) as AudioStream
if stream:
print("sfx2d [", name, "] stream=", stream.resource_path)
else:
print("sfx2d [", name, "] stream is null")
func _update_files():
current_files.clear()
if not dir:
return
var dir_access := DirAccess.open(sfx_root_path + dir) as DirAccess
if not dir_access:
push_warning("sfx2d dir_access is null for ", sfx_root_path + dir)
return
for f in dir_access.get_files():
if f.ends_with(".wav") or f.ends_with(".ogg") or f.ends_with(".mp3"):
current_files.push_back(f)
func _get_property_list():
return [
{
"name": &"file",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
"hint_string": ",".join(current_files),
}
]
func _get(property: StringName) -> Variant:
if property == &"file":
return file
return null
func _set(property: StringName, value: Variant) -> bool:
if property == &"file":
file = value
_reload_sfx()
# notify_property_list_changed()
return true
return false
# queue free 导致 sfx 无法播放,使用全局声源
func global_play() -> void:
if stream:

View File

@ -189,7 +189,8 @@ func _unhandled_input(event: InputEvent) -> void:
return
# if lock_on_player_freezed and SceneManager.is_palyer_freezed_or_locked():
# return
if SceneManager.get_player().action_locked:
var player = SceneManager.get_player()
if not player or player.action_locked:
return
if activated:
if event.is_action_pressed("interact"):

View File

@ -638,6 +638,7 @@ animation = &"小婵_被霸凌"
autoplay = "小婵_被霸凌"
frame = 5
frame_progress = 0.248369
debug_mov_animation = null
[node name="f1" parent="Ground/DeployLayer/霸凌" instance=ExtResource("33_ycojw")]
z_index = 10
@ -645,6 +646,7 @@ position = Vector2(-11, 1)
sprite_frames = ExtResource("34_1tart")
animation = &"霸凌1"
autoplay = "霸凌1"
debug_mov_animation = null
[node name="f2" parent="Ground/DeployLayer/霸凌" instance=ExtResource("33_ycojw")]
z_index = 10
@ -652,6 +654,7 @@ position = Vector2(23, 11)
sprite_frames = ExtResource("34_1tart")
animation = &"霸凌2"
autoplay = "霸凌2"
debug_mov_animation = null
[node name="f3" parent="Ground/DeployLayer/霸凌" instance=ExtResource("33_ycojw")]
z_index = 10
@ -659,6 +662,7 @@ position = Vector2(57, 7)
sprite_frames = ExtResource("34_1tart")
animation = &"霸凌3"
autoplay = "霸凌3"
debug_mov_animation = null
[node name="Ambush点火游戏阻挡右移" parent="Ground/DeployLayer/霸凌" instance=ExtResource("25_iyaiw")]
position = Vector2(-116, -13)

View File

@ -118,7 +118,8 @@ func _c02_final_show():
var player = SceneManager.get_player()
player.set_facing_direction(Vector2(-1, 0))
SceneManager.freeze_player(0)
play("c02_final_show")
play("c02_final_show_join")
play("c02_final_show_quit")
# WARN: 如果不延时,开场直接显示 dialog 可能会显示失败(无报错提示)
await get_tree().create_timer(0.1).timeout
player.global_position.x = 650
@ -127,8 +128,9 @@ func _c02_final_show():
await DialogueManager.dialogue_ended
# 瞎子打断
DialogueManager.show_dialogue_balloon(dialogue_c02, "c02_s11_谢幕交谈2")
_final_show_end()
func _c02_final_show_end():
func _final_show_end():
SceneManager.release_player()
ArchiveManager.set_global_entry("c02_burning_end", true)

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=30 format=3 uid="uid://cootarwb44vvh"]
[gd_scene load_steps=31 format=3 uid="uid://cootarwb44vvh"]
[ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_qkymk"]
[ext_resource type="Script" uid="uid://cbt0ubygchxvv" path="res://scene/ground/scene/c02/s06_animation.gd" id="2_4dg6u"]
@ -41,31 +41,31 @@ tracks/0/keys = {
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("DeployLayer/c02_final/瞎子:position")
tracks/1/path = NodePath("DeployLayer/煤油灯:gaslight_energy")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(475, 41.5)]
"values": [2.0]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("DeployLayer/c02_final/胖子:position")
tracks/2/path = NodePath("DeployLayer/煤油灯:gaslight_ground_energy")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(501, 33.5)]
"values": [2.0]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("DeployLayer/c02_final:visible")
tracks/3/path = NodePath("DeployLayer/疯子撞墙:visible")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
@ -77,31 +77,31 @@ tracks/3/keys = {
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("DeployLayer/煤油灯:gaslight_energy")
tracks/4/path = NodePath("DeployLayer/疯子撞墙:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [2.0]
"values": [Vector2(221, 4)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("DeployLayer/煤油灯:gaslight_ground_energy")
tracks/5/path = NodePath("DeployLayer/疯子撞墙:animation")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [2.0]
"update": 1,
"values": [&"疯子跑动"]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("DeployLayer/疯子撞墙:visible")
tracks/6/path = NodePath("DeployLayer/疯子撞墙/疯子撞墙Sfx2D:playing")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
@ -110,133 +110,62 @@ tracks/6/keys = {
"update": 1,
"values": [false]
}
tracks/7/type = "value"
tracks/7/imported = false
tracks/7/enabled = true
tracks/7/path = NodePath("DeployLayer/疯子撞墙:position")
tracks/7/interp = 1
tracks/7/loop_wrap = true
tracks/7/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(221, 4)]
}
tracks/8/type = "value"
tracks/8/imported = false
tracks/8/enabled = true
tracks/8/path = NodePath("DeployLayer/疯子撞墙:animation")
tracks/8/interp = 1
tracks/8/loop_wrap = true
tracks/8/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [&"疯子跑动"]
}
tracks/9/type = "value"
tracks/9/imported = false
tracks/9/enabled = true
tracks/9/path = NodePath("DeployLayer/疯子撞墙/疯子撞墙Sfx2D:playing")
tracks/9/interp = 1
tracks/9/loop_wrap = true
tracks/9/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="Animation" id="Animation_ciatp"]
resource_name = "c02_final_show"
resource_name = "c02_final_show_join"
length = 22.0
tracks/0/type = "method"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("AnimationPlayer")
tracks/0/path = NodePath("DeployLayer/c02_final/PointLight2D:energy")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(20.8333),
"transitions": PackedFloat32Array(1),
"values": [{
"args": [],
"method": &"_c02_final_show_end"
}]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("DeployLayer/c02_final/PointLight2D:energy")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(1.13333, 2.53333, 14.8333, 16.6333),
"transitions": PackedFloat32Array(1, 1, 1, 1),
"update": 0,
"values": [0.0, 2.0, 2.0, 0.0]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("DeployLayer/c02_final/瞎子:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 2.7, 9.1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector2(0, 41.5), Vector2(0, 41.5), Vector2(557, 34)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("DeployLayer/c02_final/胖子:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 2.7, 9.1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector2(0, 41.5), Vector2(0, 41.5), Vector2(580, 25)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("DeployLayer/c02_final:visible")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("DeployLayer/c02_final:visible")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0.0333333, 18.8),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [true, false]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("DeployLayer/煤油灯:gaslight_energy")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("DeployLayer/煤油灯:gaslight_energy")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 1.33333),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 2.0]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("DeployLayer/煤油灯:gaslight_ground_energy")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("DeployLayer/煤油灯:gaslight_ground_energy")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 1.33333),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 2.0]
}
[sub_resource type="Animation" id="Animation_yolsv"]
resource_name = "c02_final_show_quit"
[sub_resource type="Animation" id="Animation_p6da7"]
resource_name = "疯子撞墙"
length = 6.0
@ -292,7 +221,8 @@ tracks/3/keys = {
[sub_resource type="AnimationLibrary" id="AnimationLibrary_k01ve"]
_data = {
&"RESET": SubResource("Animation_k01ve"),
&"c02_final_show": SubResource("Animation_ciatp"),
&"c02_final_show_join": SubResource("Animation_ciatp"),
&"c02_final_show_quit": SubResource("Animation_yolsv"),
&"疯子撞墙": SubResource("Animation_p6da7")
}
@ -313,7 +243,6 @@ fill_to = Vector2(1, 1)
[node name="Ground" parent="." instance=ExtResource("1_qkymk")]
scene_name = "c02_s06"
player_y = 60
main_scene = null
[node name="AnimationPlayer" parent="Ground" index="0"]
libraries = {
@ -337,6 +266,16 @@ mode = "场景背景音"
"感应玩家操作" = false
metadata/_custom_type_script = "uid://rq6w1vuhuq1m"
[node name="Sfx翻找东西" type="AudioStreamPlayer" parent="Ground/AnimationPlayer" index="1"]
bus = &"game_sfx"
script = ExtResource("4_2e08x")
metadata/_custom_type_script = "uid://rq6w1vuhuq1m"
[node name="Sfx擦亮火柴" type="AudioStreamPlayer" parent="Ground/AnimationPlayer" index="2"]
bus = &"game_sfx"
script = ExtResource("4_2e08x")
metadata/_custom_type_script = "uid://rq6w1vuhuq1m"
[node name="BGSprite2D" parent="Ground" index="1"]
light_mask = 5
position = Vector2(0, -2)
@ -413,7 +352,7 @@ max_distance = 600.0
attenuation = 3.0
bus = &"game_sfx"
script = ExtResource("14_7x2h6")
file = ""
loop = true
metadata/_custom_type_script = "uid://wapo47a1oddf"
[node name="Ambush三男孩" parent="Ground/DeployLayer" index="9" instance=ExtResource("14_k01ve")]
@ -442,19 +381,33 @@ position = Vector2(289, 16)
packed_scene = ExtResource("16_p6da7")
[node name="c02_final" type="Node2D" parent="Ground/DeployLayer" index="12"]
visible = false
[node name="胖子" type="AnimatedSprite2D" parent="Ground/DeployLayer/c02_final"]
position = Vector2(501, 33.5)
[node name="瞎子" parent="Ground/DeployLayer/c02_final" instance=ExtResource("10_p6da7")]
position = Vector2(277, 29)
sprite_frames = ExtResource("15_k01ve")
animation = &"小婵走路"
autoplay = "胖子"
animation = &"方瞎子走路-右"
move_configs = Array[Dictionary]([{
"animation": "方瞎子走路-右",
"animation_next": "方瞎子呼吸-右",
"duration": 1e+07,
"movement_x": 300.0,
"velocity": Vector2(50, 0)
}])
debug_mov_animation = "方瞎子走路-右"
[node name="瞎子" type="AnimatedSprite2D" parent="Ground/DeployLayer/c02_final"]
position = Vector2(475, 41.5)
[node name="胖子" parent="Ground/DeployLayer/c02_final" instance=ExtResource("10_p6da7")]
position = Vector2(233, 33)
sprite_frames = ExtResource("15_k01ve")
animation = &"瞎子"
autoplay = "瞎子"
animation = &"胖子走路"
autostart = false
move_configs = Array[Dictionary]([{
"animation": "胖子走路",
"animation_next": "胖子呼吸",
"duration": 1e+07,
"movement_x": 300.0,
"velocity": Vector2(60, 0)
}])
debug_mov_animation = "胖子走路"
[node name="小蝉" type="AnimatedSprite2D" parent="Ground/DeployLayer/c02_final"]
position = Vector2(585, 82)
@ -485,6 +438,4 @@ visible = false
energy = 0.9
blend_mode = 1
[connection signal="finished" from="Ground/DeployLayer/疯子撞墙/疯子撞墙Sfx2D" to="Ground/DeployLayer/疯子撞墙/疯子撞墙Sfx2D" method="play"]
[editable path="Ground"]

View File

@ -54,12 +54,11 @@ func _ready() -> void:
point_light_ground.position.y = ground_height_offset
place_sprite2d.visible = not hide_texture
point_light.texture = gaslight_texture
point_light.energy = gaslight_energy
point_light_ground.texture = ground_light_texture
point_light_ground.energy = gaslight_ground_energy
if Engine.is_editor_hint():
point_light.texture = gaslight_texture
point_light.energy = gaslight_energy
point_light_ground.texture = ground_light_texture
point_light_ground.energy = gaslight_ground_energy
_switch_gaslight(debug_light_switch)
return

View File

@ -1,6 +1,6 @@
extends CanvasLayer
signal exit
signal exit()
func _ready() -> void:
layer = GlobalConfig.CANVAS_LAYER_LITTLE_GAME

View File

@ -11,17 +11,23 @@ signal exit(success: bool)
var image: Image
var show_childhood := false
func _ready() -> void:
# 第三章设置为启用 c03_meta_enabled
show_childhood = ArchiveManager.get_global_value("c03_meta_enabled", false)
layer = GlobalConfig.CANVAS_LAYER_LITTLE_GAME
image = ripple.texture.get_image()
shader.gui_input.connect(_shader_input)
timer.timeout.connect(_try_ripple)
shader.material.set("shader_parameter/amplitude", 0.0)
# 幼年 -> 成年
var tween = create_tween() as Tween
tween.tween_interval(1.5)
tween.tween_property(child_sprite, "modulate:a", 0.0, 0.5)
if show_childhood:
var tween = create_tween() as Tween
tween.tween_interval(1.5)
tween.tween_property(child_sprite, "modulate:a", 0.0, 0.5)
else:
child_sprite.modulate.a = 0
await get_tree().create_timer(1.5).timeout
_try_ripple()
func _try_ripple():
@ -59,10 +65,12 @@ func _make_ripple(pos:Vector2) -> bool:
ripple_tween.kill()
ripple_tween = create_tween()
ripple_tween.tween_property(shader.material, "shader_parameter/amplitude", 2.0, 0.3)
ripple_tween.parallel().tween_property(child_sprite, "modulate:a", 1.0, 0.2)
ripple_tween.parallel().tween_property(grownup_sprite, "modulate:a", 0.5, 0.2)
if show_childhood:
ripple_tween.parallel().tween_property(child_sprite, "modulate:a", 1.0, 0.2)
ripple_tween.parallel().tween_property(grownup_sprite, "modulate:a", 0.5, 0.2)
ripple_tween.tween_property(shader.material, "shader_parameter/amplitude", 0.0, 2.0)
ripple_tween.parallel().tween_property(child_sprite, "modulate:a", 0.0, 1.0)
ripple_tween.parallel().tween_property(grownup_sprite, "modulate:a", 1.0, 1.5)
if show_childhood:
ripple_tween.parallel().tween_property(child_sprite, "modulate:a", 0.0, 1.0)
ripple_tween.parallel().tween_property(grownup_sprite, "modulate:a", 1.0, 1.5)
return true
return false

View File

@ -0,0 +1,23 @@
extends Node2D
@export var camera_rect: Rect2
@onready var camera = %Camera2D as Camera2D
var speed := 150
var current_speed := Vector2.ZERO
func _process(delta: float) -> void:
# move camera according to current_speed
var direction = Vector2(Input.get_axis("left", "right"), Input.get_axis("up", "down"))
current_speed = direction * speed
camera.position += current_speed * delta
# clamp inside camera_rect
if camera_rect:
camera.position.x = clamp(
camera.position.x, camera_rect.position.x, camera_rect.position.x + camera_rect.size.x
)
camera.position.y = clamp(
camera.position.y, camera_rect.position.y, camera_rect.position.y + camera_rect.size.y
)

View File

@ -0,0 +1 @@
uid://c17bw2w6a8na6

View File

@ -0,0 +1,39 @@
[gd_scene load_steps=5 format=3 uid="uid://deniapgcn3bv7"]
[ext_resource type="Script" uid="uid://c17bw2w6a8na6" path="res://scene/ground/script/c03/鱼眼景深镜头.gd" id="1_56a8k"]
[ext_resource type="Texture2D" uid="uid://jnnm4gb8tsp5" path="res://asset/art/scene/c01/s01_旧版序章/bg_夜晚有墙.png" id="1_pns71"]
[ext_resource type="Material" uid="uid://dp4uwpm8jlic2" path="res://scene/ground/script/c03/鱼眼镜头material.tres" id="2_v28hk"]
[ext_resource type="Texture2D" uid="uid://dxcn4gha8l5ce" path="res://asset/art/scene/c01/s01_旧版序章/e_老奶奶喂老鼠.png" id="3_q5xjx"]
[node name="鱼眼景深镜头" type="Node2D"]
script = ExtResource("1_56a8k")
camera_rect = Rect2(-550, -150, 1100, 300)
metadata/_edit_horizontal_guides_ = [-121.0]
[node name="ParallaxBackground" type="ParallaxBackground" parent="."]
[node name="BGLayer" type="ParallaxLayer" parent="ParallaxBackground"]
[node name="Sprite2D" type="Sprite2D" parent="ParallaxBackground/BGLayer"]
texture = ExtResource("1_pns71")
[node name="Layer1" type="ParallaxLayer" parent="ParallaxBackground"]
position = Vector2(1, 17)
motion_scale = Vector2(1.05, 1.01)
[node name="Sprite2D" type="Sprite2D" parent="ParallaxBackground/Layer1"]
position = Vector2(-2, 55)
texture = ExtResource("3_q5xjx")
[node name="Camera2D" type="Camera2D" parent="ParallaxBackground"]
unique_name_in_owner = true
position_smoothing_enabled = true
position_smoothing_speed = 7.0
[node name="ColorRect" type="ColorRect" parent="ParallaxBackground"]
material = ExtResource("2_v28hk")
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View File

@ -0,0 +1,46 @@
//https://godotshaders.com/shader/fisheye-shader/
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE:hint_screen_texture,filter_linear;
// 鱼眼效果强度控制
uniform float fish_intensity : hint_range(0.0, 2.0) = 1.0;
void fragment() {
// 获取屏幕分辨率
vec2 iResolution = vec2(textureSize(SCREEN_TEXTURE, 0));
// 基础UV坐标适配Godot坐标系
vec2 uv = UV;
uv.y = 1.0 - uv.y; // 翻转Y轴
// 宽高比计算
float aspectRatio = iResolution.x / iResolution.y;
// 计算强度参数
float strength = fish_intensity * 0.03;
vec2 intensity = vec2(
strength * aspectRatio,
strength * aspectRatio
);
// 坐标转换到[-1, 1]范围
vec2 coords = uv;
coords = (coords - 0.5) * 2.0;
// 计算坐标偏移量
vec2 realCoordOffs;
realCoordOffs.x = (1.0 - coords.y * coords.y) * intensity.y * coords.x;
realCoordOffs.y = (1.0 - coords.x * coords.x) * intensity.x * coords.y;
// 应用偏移
vec2 fuv = uv - realCoordOffs;
// 边界检查
if(fuv.x < 0.0 || fuv.x > 1.0 || fuv.y < 0.0 || fuv.y > 1.0) {
COLOR = vec4(0.0); // 超出范围显示黑
vec4 color = texture(SCREEN_TEXTURE,fuv);
COLOR.rgb=mix(color.rgb,color.bgr,length(fuv-0.5));
} else {
// 采样时再次翻转Y轴适配Godot坐标系
fuv.y = 1.0 - fuv.y;
COLOR = texture(SCREEN_TEXTURE, fuv);
vec4 color = texture(SCREEN_TEXTURE,fuv);
COLOR.rgb=mix(color.rgb,color.bgr,length(fuv-0.5));
}
}

View File

@ -0,0 +1 @@
uid://8q6t3vnuqc5e

View File

@ -0,0 +1,70 @@
//based on https://godotshaders.com/shader/crt-shader-2/
shader_type canvas_item;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
uniform float fisheye_strength = 1.0; // Adjust this to control the fisheye effect strength
vec2 fisheye(vec2 uv) {
vec2 d = uv - 0.5;
float r = length(d);
float theta = atan(d.y, d.x);
float rf = pow(r, fisheye_strength) / pow(0.5, fisheye_strength - 1.0);
return vec2(0.5) + rf * normalize(d);
}
vec2 curve(vec2 uv)
{
uv = (uv - 0.5) * 2.0;
uv *= 1.1;
uv.x *= 1.0 + pow((abs(uv.y) / 5.0), 2.0);
uv.y *= 1.0 + pow((abs(uv.x) / 4.0), 2.0);
uv = (uv / 2.0) + 0.5;
uv = uv *0.92 + 0.04;
return uv;
}
void fragment() {
vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
vec2 q = FRAGCOORD.xy / iResolution.xy;
// Apply fisheye distortion
q = fisheye(q);
vec2 uv = curve(q);
uv = curve( uv );
vec3 oricol = texture( screen_texture, vec2(q.x,q.y) ).xyz;
vec3 col;
float x = sin(0.3*TIME+uv.y*21.0)*sin(0.7*TIME+uv.y*29.0)*sin(0.3+0.33*TIME+uv.y*31.0)*0.0017;
col.r = texture(screen_texture,vec2(x+uv.x+0.001,uv.y+0.001)).x+0.05;
col.g = texture(screen_texture,vec2(x+uv.x+0.000,uv.y-0.002)).y+0.05;
col.b = texture(screen_texture,vec2(x+uv.x-0.002,uv.y+0.000)).z+0.05;
col.r += 0.08*texture(screen_texture,0.75*vec2(x+0.025, -0.027)+vec2(uv.x+0.001,uv.y+0.001)).x;
col.g += 0.05*texture(screen_texture,0.75*vec2(x+-0.022, -0.02)+vec2(uv.x+0.000,uv.y-0.002)).y;
col.b += 0.08*texture(screen_texture,0.75*vec2(x+-0.02, -0.018)+vec2(uv.x-0.002,uv.y+0.000)).z;
col = clamp(col*0.6+0.4*col*col*1.0,0.0,1.0);
float vig = (0.0 + 1.0*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y));
col *= vec3(pow(vig,0.3));
col *= vec3(0.95,1.05,0.95);
col *= 2.8;
float scans = clamp( 0.35+0.35*sin(3.5*TIME+uv.y*iResolution.y*1.5), 0.0, 1.0);
float s = pow(scans,1.7);
col = col*vec3( 0.4+0.7*s) ;
col *= 1.0+0.01*sin(110.0*TIME);
if (uv.x < 0.0 || uv.x > 1.0)
col *= 0.0;
if (uv.y < 0.0 || uv.y > 1.0)
col *= 0.0;
col*=1.0-0.65*vec3(clamp((mod(FRAGCOORD.x, 2.0)-1.0)*2.0,0.0,1.0));
float comp = smoothstep( 0.1, 0.9, sin(TIME) );
COLOR = vec4(col,1.0);
}

View File

@ -0,0 +1 @@
uid://df554t3pmm2i3

View File

@ -0,0 +1,7 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://dp4uwpm8jlic2"]
[ext_resource type="Shader" uid="uid://8q6t3vnuqc5e" path="res://scene/ground/script/c03/鱼眼镜头.gdshader" id="1_yexoo"]
[resource]
shader = ExtResource("1_yexoo")
shader_parameter/fish_intensity = 1.454