From 8e938469dfb5146bf26bb53ea2141b28930ad455 Mon Sep 17 00:00:00 2001 From: Es Date: Wed, 14 Jan 2026 21:18:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=90=BD=E7=9F=B3=EF=BC=8C=E7=9F=BF=E8=BD=A6?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E5=92=8C=E6=95=B0=E6=8D=AE=E8=B0=83=E6=95=B4?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=B6=9F=E6=BC=AAshader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + _game/GameMain.tscn | 34 +++- _game/game.gd | 4 +- _game/water_warp_controller.gd | 46 ++++++ _game/water_warp_controller.gd.uid | 1 + _player/Avatar.tscn | 3 +- .../PathDriveMovePlateform.tscn | 2 + .../trigger_fall_rock_climb.tscn | 4 +- .../trigger_fall_rock_hazard.tscn | 5 +- _scene/level1/l1_s10.tscn | 13 +- _scene/level1/l1_s5.tscn | 1 + _scene/level1/l1_s8.tscn | 52 ++++-- _shader/ripple.gdshader | 141 +++++++++++++++++ _shader/ripple.gdshader.uid | 1 + _shader/ripple.tscn | 17 ++ _shader/ripple2.gdshader | 149 ++++++++++++++++++ _shader/ripple2.gdshader.uid | 1 + 17 files changed, 451 insertions(+), 24 deletions(-) create mode 100644 _game/water_warp_controller.gd create mode 100644 _game/water_warp_controller.gd.uid create mode 100644 _shader/ripple.gdshader create mode 100644 _shader/ripple.gdshader.uid create mode 100644 _shader/ripple.tscn create mode 100644 _shader/ripple2.gdshader create mode 100644 _shader/ripple2.gdshader.uid diff --git a/.gitignore b/.gitignore index 0af181c..2a4bc0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # Godot 4+ specific ignores .godot/ /android/ +addons/limboai/bin/~liblimboai.windows.editor.x86_64.dll diff --git a/_game/GameMain.tscn b/_game/GameMain.tscn index 40966c3..d8b8793 100644 --- a/_game/GameMain.tscn +++ b/_game/GameMain.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=3 uid="uid://3vc8ojbiyy5w"] +[gd_scene load_steps=18 format=3 uid="uid://3vc8ojbiyy5w"] [ext_resource type="Script" uid="uid://crgac4manhoud" path="res://_game/game.gd" id="1_yksyv"] [ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_x2i0j"] @@ -14,6 +14,26 @@ [ext_resource type="PackedScene" uid="uid://2d457ndb7toe" path="res://_scene/level1/l1_s8.tscn" id="11_ktxjv"] [ext_resource type="PackedScene" uid="uid://dcoq4q3brnkw6" path="res://_scene/level1/l1_s9.tscn" id="12_enubi"] [ext_resource type="PackedScene" uid="uid://dsw3o2bhc8bve" path="res://_scene/level1/l1_s10.tscn" id="13_53pmm"] +[ext_resource type="Script" uid="uid://c5in610cunjn2" path="res://_game/water_warp_controller.gd" id="15_jibn5"] +[ext_resource type="Shader" uid="uid://ccpo4346to8ka" path="res://_shader/ripple2.gdshader" id="16_ef7py"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_5vsgs"] +shader = ExtResource("16_ef7py") +shader_parameter/debug_show = false +shader_parameter/obj_uv = Vector2(0.5, 0.5) +shader_parameter/obj_dir = Vector2(1, 0) +shader_parameter/obj_speed = 1.0 +shader_parameter/lane_half_width = 0.085 +shader_parameter/edge_width = 0.04 +shader_parameter/trail_length = 0.55 +shader_parameter/push_strength = 0.075 +shader_parameter/drag_strength = 0.045 +shader_parameter/suck_strength = 0.03 +shader_parameter/curl_strength = 0.07 +shader_parameter/foam_strength = 0.45 +shader_parameter/noise_scale = 3.5 +shader_parameter/noise_advect = 0.5 +shader_parameter/chroma_shift = 0.6 [node name="Game" type="Node2D" groups=["PLAYER_RESPAWN"]] script = ExtResource("1_yksyv") @@ -43,3 +63,15 @@ script = ExtResource("1_yksyv") [node name="L1_S9" parent="." instance=ExtResource("12_enubi")] [node name="L1_S10" parent="." instance=ExtResource("13_53pmm")] + +[node name="WaterWarp" type="CanvasLayer" parent="." node_paths=PackedStringArray("target")] +script = ExtResource("15_jibn5") +target = NodePath("../PlayerController") + +[node name="ColorRect" type="ColorRect" parent="WaterWarp"] +material = SubResource("ShaderMaterial_5vsgs") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 diff --git a/_game/game.gd b/_game/game.gd index 31f5fa9..e8d6c2d 100644 --- a/_game/game.gd +++ b/_game/game.gd @@ -2,14 +2,14 @@ extends Node2D func _ready() -> void: #$L0_S0.switch_act_by_id(1) - $L1_S1.switch_act_by_id(1) + #$L1_S1.switch_act_by_id(1) #$L1_S2.switch_act_by_id(1) #$L1_S3.switch_act_by_id(1) #$L1_S4.switch_act_by_id(1) #$L1_S5.switch_act_by_id(1) #$L1_S6.switch_act_by_id(1) #$L1_S7.switch_act_by_id(1) - #$L1_S8.switch_act_by_id(1) + $L1_S8.switch_act_by_id(1) #$L1_S9.switch_act_by_id(1) await get_tree().process_frame get_tree().call_group(&"PLAYER_RESPAWN",&"respawn_avatar") diff --git a/_game/water_warp_controller.gd b/_game/water_warp_controller.gd new file mode 100644 index 0000000..f8b03b6 --- /dev/null +++ b/_game/water_warp_controller.gd @@ -0,0 +1,46 @@ +extends CanvasLayer + +@export var target: Node2D +@onready var rect = $ColorRect + +var mat: ShaderMaterial +var last_pos: Vector2 + +func _ready(): + mat = rect.material as ShaderMaterial + if target != null: + last_pos = target.global_position + +func _process(delta: float) -> void: + if target == null: + return + + if mat == null: + return + + var vp_size: Vector2 = get_viewport().get_visible_rect().size + + # 玩家世界坐标 + var world_pos: Vector2 = target.global_position + + # ✅ 世界 -> 屏幕像素坐标(包含相机影响) + var screen_pos: Vector2 = get_viewport().get_canvas_transform() * world_pos + + # 速度方向(世界空间) + var vel: Vector2 = (world_pos - last_pos) / max(delta, 0.0001) + last_pos = world_pos + + var speed: float = vel.length() + var dir: Vector2 = Vector2.RIGHT + if speed > 0.001: + dir = vel / speed + + # ✅ 船头前移(拨水发生在玩家前面) + var front_offset_px: Vector2 = dir * 30.0 + var uv_front: Vector2 = (screen_pos + front_offset_px) / vp_size + uv_front = uv_front.clamp(Vector2(0, 0), Vector2(1, 1)) + + + mat.set_shader_parameter("obj_uv", uv_front) + mat.set_shader_parameter("obj_dir", dir) + mat.set_shader_parameter("obj_speed", clamp(speed / 600.0, 0.0, 2.0)) diff --git a/_game/water_warp_controller.gd.uid b/_game/water_warp_controller.gd.uid new file mode 100644 index 0000000..c06d1dc --- /dev/null +++ b/_game/water_warp_controller.gd.uid @@ -0,0 +1 @@ +uid://c5in610cunjn2 diff --git a/_player/Avatar.tscn b/_player/Avatar.tscn index 70061d0..8e8b1b5 100644 --- a/_player/Avatar.tscn +++ b/_player/Avatar.tscn @@ -9,7 +9,7 @@ [ext_resource type="Resource" uid="uid://bs3cqsp23047i" path="res://_camera/camera_shake/CSP_VerticalOnly.tres" id="4_01uoa"] [ext_resource type="Script" uid="uid://b5hkfpjbye70" path="res://_player/states/idle.gd" id="4_30i7g"] [ext_resource type="BlackboardPlan" uid="uid://nlw7rxugv5uh" path="res://_player/bbp_player.tres" id="4_mwufa"] -[ext_resource type="Resource" uid="uid://cs50mkt830f8r" path="res://_shared/camera/camera_shake/CSP_XY.tres" id="5_ciuu3"] +[ext_resource type="Resource" uid="uid://cs50mkt830f8r" path="res://_camera/camera_shake/CSP_XY.tres" id="5_ciuu3"] [ext_resource type="Texture2D" uid="uid://dted7geb331y2" path="res://_asset/ksw/character.png" id="6_01uoa"] [ext_resource type="Script" uid="uid://bpd54nf8oxwsb" path="res://_player/states/player_hsm.gd" id="6_8q4ov"] [ext_resource type="Script" uid="uid://po21boe8iqcc" path="res://_player/states/move.gd" id="7_rrwxs"] @@ -75,7 +75,6 @@ position = Vector2(0, 5.75) shape = SubResource("RectangleShape2D_qnulu") [node name="Sprite2D" type="Sprite2D" parent="."] -visible = false texture_filter = 1 position = Vector2(0, 3.9999998) scale = Vector2(0.1, 0.1) diff --git a/_props/move_plateform/path_drive_move_plateform/PathDriveMovePlateform.tscn b/_props/move_plateform/path_drive_move_plateform/PathDriveMovePlateform.tscn index 0fd1958..c071731 100644 --- a/_props/move_plateform/path_drive_move_plateform/PathDriveMovePlateform.tscn +++ b/_props/move_plateform/path_drive_move_plateform/PathDriveMovePlateform.tscn @@ -4,3 +4,5 @@ [node name="PathDriveMovePlateform" type="Node2D"] script = ExtResource("1_ouylf") +move_speed = 600.0 +returning_speed = 300.0 diff --git a/_props/trigger_fall_rock_climb/trigger_fall_rock_climb.tscn b/_props/trigger_fall_rock_climb/trigger_fall_rock_climb.tscn index 473c654..15fb00a 100644 --- a/_props/trigger_fall_rock_climb/trigger_fall_rock_climb.tscn +++ b/_props/trigger_fall_rock_climb/trigger_fall_rock_climb.tscn @@ -6,7 +6,7 @@ [ext_resource type="PackedScene" uid="uid://bonrls3iuhdqb" path="res://_props/_prefabs/player/player_trigger_volumn.tscn" id="4_txegh"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_vv0hj"] -size = Vector2(52, 51) +size = Vector2(52, 52) [sub_resource type="RectangleShape2D" id="RectangleShape2D_mvp6g"] size = Vector2(54, 52.5) @@ -21,7 +21,7 @@ max_fall_speed = 1500.0 [node name="Sprite2D" type="Sprite2D" parent="rock"] position = Vector2(0, 73.99999) -scale = Vector2(0.4, 0.4) +scale = Vector2(0.405, 0.405) texture = ExtResource("3_mb81t") [node name="CollisionShape2D" type="CollisionShape2D" parent="rock"] diff --git a/_props/trigger_fall_rock_hazard/trigger_fall_rock_hazard.tscn b/_props/trigger_fall_rock_hazard/trigger_fall_rock_hazard.tscn index 3d51a53..28d4387 100644 --- a/_props/trigger_fall_rock_hazard/trigger_fall_rock_hazard.tscn +++ b/_props/trigger_fall_rock_hazard/trigger_fall_rock_hazard.tscn @@ -6,7 +6,7 @@ [ext_resource type="PackedScene" uid="uid://bonrls3iuhdqb" path="res://_props/_prefabs/player/player_trigger_volumn.tscn" id="4_s77mb"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_vv0hj"] -size = Vector2(52, 51) +size = Vector2(52, 52) [sub_resource type="RectangleShape2D" id="RectangleShape2D_mvp6g"] size = Vector2(52, 108.5) @@ -20,11 +20,10 @@ falling_gravity = 600.0 max_fall_speed = 1000.0 [node name="Sprite2D" type="Sprite2D" parent="rock"] -scale = Vector2(0.4, 0.4) +scale = Vector2(0.405, 0.405) texture = ExtResource("3_f8vfu") [node name="CollisionShape2D" type="CollisionShape2D" parent="rock"] -position = Vector2(0, -0.5) shape = SubResource("RectangleShape2D_vv0hj") debug_color = Color(0.99629647, 0, 0.19810504, 0.41960785) diff --git a/_scene/level1/l1_s10.tscn b/_scene/level1/l1_s10.tscn index d10f842..ebe3de0 100644 --- a/_scene/level1/l1_s10.tscn +++ b/_scene/level1/l1_s10.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=46 format=4 uid="uid://dsw3o2bhc8bve"] +[gd_scene load_steps=47 format=4 uid="uid://dsw3o2bhc8bve"] [ext_resource type="Script" uid="uid://5e157vdk6175" path="res://addons/reedscene/scene/ReedScene.gd" id="1_7cppx"] [ext_resource type="Script" uid="uid://bh066o84byplh" path="res://addons/reedscene/scene/ReedSceneID.gd" id="2_4mxpo"] @@ -9,7 +9,7 @@ [ext_resource type="Script" uid="uid://fxpk2ot6otfh" path="res://addons/reedscene/act/Act.gd" id="7_vbsqb"] [ext_resource type="Script" uid="uid://baqgorvlumyju" path="res://addons/reedscene/act/SingleAct.gd" id="8_p2ywg"] [ext_resource type="Script" uid="uid://pxjf5vst08eo" path="res://addons/reedscene/prop/PropManager.gd" id="9_1hywn"] -[ext_resource type="PackedScene" uid="uid://bflwr7cryd2l0" path="res://_shared/camera/CameraAnchor.tscn" id="10_1pax7"] +[ext_resource type="PackedScene" uid="uid://bflwr7cryd2l0" path="res://_camera/CameraAnchor.tscn" id="10_1pax7"] [ext_resource type="Script" uid="uid://b4menkyub4ce7" path="res://addons/reedscene/prop/PropComponent.gd" id="11_q0s1n"] [ext_resource type="Script" uid="uid://di41kt2tj34c2" path="res://addons/reedscene/prop/StateManager.gd" id="12_crx1v"] [ext_resource type="Script" uid="uid://7lml6d1t5xtq" path="res://addons/reedscene/prop/PropState.gd" id="13_hgqvd"] @@ -27,6 +27,7 @@ [ext_resource type="PackedScene" uid="uid://cpbaoqfc2kq80" path="res://_props/move_plateform/path_drive_move_plateform/PathDriveMovePlateform.tscn" id="25_ldp4y"] [ext_resource type="PackedScene" uid="uid://csdxpv8gefpec" path="res://_props/_prefabs/plateform/movable_plateform.tscn" id="26_k1jrx"] [ext_resource type="Texture2D" uid="uid://c673bap4b12fx" path="res://icon.svg" id="27_lte3x"] +[ext_resource type="PackedScene" uid="uid://b5nx4dntm0gyn" path="res://_props/door_manager/event_trigger_door.tscn" id="28_4mxpo"] [sub_resource type="Resource" id="Resource_6bhoi"] script = ExtResource("8_p2ywg") @@ -144,7 +145,6 @@ limit_top = -185 limit_bottom = 185 limit_left = -320 limit_right = 290 -follow_player = true [node name="[Prop_0000]" type="Node" parent="Props/CameraAnchor"] script = ExtResource("11_q0s1n") @@ -191,7 +191,7 @@ state_id = 1 effects = Array[ExtResource("14_as4ql")]([ExtResource("19_7kvrg")]) [node name="PlayerRespawnPoint" parent="Props" instance=ExtResource("20_a7psa")] -position = Vector2(528, -1472) +position = Vector2(1107, -1504) [node name="[Prop_0002]" type="Node" parent="Props/PlayerRespawnPoint"] script = ExtResource("11_q0s1n") @@ -265,4 +265,9 @@ shape = SubResource("RectangleShape2D_bhcjt") scale = Vector2(1, 0.8) curve = SubResource("Curve2D_fvh1v") +[node name="EventTriggerDoor" parent="." instance=ExtResource("28_4mxpo")] +position = Vector2(1367, -2553) +rotation = -1.5707964 +scale = Vector2(0.64, 0.64) + [connection signal="player_entered" from="Props/PlayerTriggerVolumn" to="SceneManager" method="_on_player_trigger_volumn_player_entered"] diff --git a/_scene/level1/l1_s5.tscn b/_scene/level1/l1_s5.tscn index e36160e..1ebd093 100644 --- a/_scene/level1/l1_s5.tscn +++ b/_scene/level1/l1_s5.tscn @@ -212,6 +212,7 @@ path2d = NodePath("Path2D") plateform = NodePath("MovablePlateform") player_trigger = NodePath("MovablePlateform/PlayerTriggerVolumn") move_speed = 300.0 +returning_speed = 100.0 acceleration = 1000.0 [node name="MovablePlateform" parent="PathDriveMovePlateform" node_paths=PackedStringArray("shaking_target") instance=ExtResource("25_ug4by")] diff --git a/_scene/level1/l1_s8.tscn b/_scene/level1/l1_s8.tscn index acdb5ae..89c4f33 100644 --- a/_scene/level1/l1_s8.tscn +++ b/_scene/level1/l1_s8.tscn @@ -1,13 +1,16 @@ -[gd_scene load_steps=42 format=4 uid="uid://2d457ndb7toe"] +[gd_scene load_steps=48 format=4 uid="uid://2d457ndb7toe"] [ext_resource type="Script" uid="uid://5e157vdk6175" path="res://addons/reedscene/scene/ReedScene.gd" id="1_h5hd7"] [ext_resource type="Script" uid="uid://bh066o84byplh" path="res://addons/reedscene/scene/ReedSceneID.gd" id="2_s1dia"] [ext_resource type="Script" uid="uid://dn0ksjoswquf5" path="res://addons/reedscene/scene/SceneManager.gd" id="3_v2x74"] [ext_resource type="Script" uid="uid://ons77en82uls" path="res://addons/reedscene/scene/scene_trigger/base/SceneTrigger.gd" id="4_8ob7b"] [ext_resource type="Resource" uid="uid://bym4pb0ellj7b" path="res://_scene/scene_trigger_resource/default_switch.tres" id="5_v3u1d"] +[ext_resource type="Script" uid="uid://baamspwt4rm4r" path="res://addons/reedscene/scene/guard.gd" id="6_5nchj"] [ext_resource type="Script" uid="uid://dsgl7lbyjsiif" path="res://addons/reedscene/act/ActManager.gd" id="6_lwjpo"] +[ext_resource type="Script" uid="uid://dxj5vimigc651" path="res://addons/reedscene/scene/scene_trigger/base/SceneTriggerEffectPair.gd" id="7_3ly86"] [ext_resource type="Script" uid="uid://fxpk2ot6otfh" path="res://addons/reedscene/act/Act.gd" id="7_o10qt"] [ext_resource type="Script" uid="uid://baqgorvlumyju" path="res://addons/reedscene/act/SingleAct.gd" id="8_nkrpp"] +[ext_resource type="Script" uid="uid://cdprpen0jyr6d" path="res://addons/reedscene/scene/scene_trigger/STR_NodePath.gd" id="8_nrwgi"] [ext_resource type="Script" uid="uid://pxjf5vst08eo" path="res://addons/reedscene/prop/PropManager.gd" id="9_ru3iu"] [ext_resource type="PackedScene" uid="uid://bflwr7cryd2l0" path="res://_camera/CameraAnchor.tscn" id="10_8v4hu"] [ext_resource type="Script" uid="uid://b4menkyub4ce7" path="res://addons/reedscene/prop/PropComponent.gd" id="11_nkttg"] @@ -26,6 +29,16 @@ [ext_resource type="PackedScene" uid="uid://knrcnoedxvm6" path="res://_props/trigger_fall_rock_hazard/trigger_fall_rock_hazard.tscn" id="23_drx4a"] [ext_resource type="PackedScene" uid="uid://bju8jr1w4d60m" path="res://_props/spring/spring.tscn" id="25_v3u1d"] [ext_resource type="PackedScene" uid="uid://badmoya3nd161" path="res://_props/trigger_fall_rock_climb/trigger_fall_rock_climb.tscn" id="26_wsgut"] +[ext_resource type="PackedScene" uid="uid://rrlq7ucvgbsv" path="res://_shader/ripple.tscn" id="30_3ly86"] + +[sub_resource type="Resource" id="Resource_xevr6"] +script = ExtResource("8_nrwgi") +metadata/_custom_type_script = "uid://cdprpen0jyr6d" + +[sub_resource type="Resource" id="Resource_bhcjt"] +script = ExtResource("4_8ob7b") +trigger_register_conifg = SubResource("Resource_xevr6") +metadata/_custom_type_script = "uid://ons77en82uls" [sub_resource type="Resource" id="Resource_6bhoi"] script = ExtResource("8_nkrpp") @@ -112,7 +125,7 @@ script = ExtResource("2_s1dia") [node name="SceneManager" type="Node" parent="."] script = ExtResource("3_v2x74") -quick_trigger = Array[ExtResource("4_8ob7b")]([ExtResource("5_v3u1d")]) +quick_trigger = Array[ExtResource("4_8ob7b")]([ExtResource("5_v3u1d"), SubResource("Resource_bhcjt")]) [node name="ActManager" type="Node" parent="."] script = ExtResource("6_lwjpo") @@ -131,7 +144,6 @@ limit_top = -185 limit_bottom = 185 limit_left = -320 limit_right = 245 -follow_player = true [node name="[Prop_0000]" type="Node" parent="Props/CameraAnchor"] script = ExtResource("11_nkttg") @@ -195,6 +207,27 @@ script = ExtResource("13_ot6uu") state_id = 1 effects = Array[ExtResource("14_wesyl")]([SubResource("Resource_ubvm0")]) +[node name="TriggerFallRock_Climb_1" parent="Props" instance=ExtResource("26_wsgut")] +position = Vector2(55.2, -1688) +scale = Vector2(0.95, 0.95) + +[node name="[Prop_0003]" type="Node" parent="Props/TriggerFallRock_Climb_1"] +script = ExtResource("11_nkttg") +prop_id = 3 + +[node name="States" type="Node" parent="Props/TriggerFallRock_Climb_1/[Prop_0003]"] +script = ExtResource("12_7fah6") + +[node name="[ID_0] Disable" type="Node" parent="Props/TriggerFallRock_Climb_1/[Prop_0003]/States"] +script = ExtResource("13_ot6uu") +state_id = 0 +effects = Array[ExtResource("14_wesyl")]([SubResource("Resource_r0e2c")]) + +[node name="[ID_1] Enable" type="Node" parent="Props/TriggerFallRock_Climb_1/[Prop_0003]/States"] +script = ExtResource("13_ot6uu") +state_id = 1 +effects = Array[ExtResource("14_wesyl")]([SubResource("Resource_ubvm0")]) + [node name="TileMapLayer" type="TileMapLayer" parent="." groups=["GRAPABLE"]] tile_map_data = PackedByteArray("AAD5/6X/AAAAAAAAAAD5/6T/AAAAAAAAAAD5/6P/AAAAAAAAAAD5/6L/AAAAAAAAAAD5/53/AAAAAAAAAAD5/5z/AAAAAAAAAAD5/5v/AAAAAAAAAAD5/5r/AAAAAAAAAAD5/5n/AAAAAAAAAAD5/5j/AAAAAAAAAAD5/5f/AAAAAAAAAAD5/5b/AAAAAAAAAAD5/5X/AAAAAAAAAAD5/5T/AAAAAAAAAAD5/5P/AAAAAAAAAAD5/5L/AAAAAAAAAAD5/5H/AAAAAAAAAAD5/5D/AAAAAAAAAAD5/6b/AAAAAAAAAAD6/6b/AAAAAAAAAAD7/6b/AAAAAAAAAAD8/6b/AAAAAAAAAAD9/6b/AAAAAAAAAAD+/6b/AAAAAAAAAAD//6b/AAAAAAAAAAAAAKb/AAAAAAAAAAABAKb/AAAAAAAAAAACAKb/AAAAAAAAAAADAKb/AAAAAAAAAAAEAKb/AAAAAAAAAAAFAKb/AAAAAAAAAAAGAKb/AAAAAAAAAAAHAKb/AAAAAAAAAAAIAKb/AAAAAAAAAAAJAKb/AAAAAAAAAAAKAKb/AAAAAAAAAAALAKb/AAAAAAAAAAAMAKb/AAAAAAAAAAANAKb/AAAAAAAAAAAOAKb/AAAAAAAAAAAPAKb/AAAAAAAAAAAQAKb/AAAAAAAAAAARAKb/AAAAAAAAAAASAKb/AAAAAAAAAAATAKb/AAAAAAAAAAD6/5D/AAAAAAAAAAD7/5D/AAAAAAAAAAD8/5D/AAAAAAAAAAD9/5D/AAAAAAAAAAD+/5D/AAAAAAAAAAD//5D/AAAAAAAAAAAAAJD/AAAAAAAAAAABAJD/AAAAAAAAAAACAJD/AAAAAAAAAAADAJD/AAAAAAAAAAAEAJD/AAAAAAAAAAAFAJD/AAAAAAAAAAAGAJD/AAAAAAAAAAAHAJD/AAAAAAAAAAAIAJD/AAAAAAAAAAAJAJD/AAAAAAAAAAAKAJD/AAAAAAAAAAALAJD/AAAAAAAAAAAMAJD/AAAAAAAAAAANAJD/AAAAAAAAAAAOAJD/AAAAAAAAAAAPAJD/AAAAAAAAAAAQAJD/AAAAAAAAAAARAJD/AAAAAAAAAAASAJD/AAAAAAAAAAATAJD/AAAAAAAAAAD6/6L/AAAAAAAAAAD7/6L/AAAAAAAAAAD8/6L/AAAAAAAAAAD7/6P/AAAAAAAAAAD6/6P/AAAAAAAAAAD6/6T/AAAAAAAAAAD6/6X/AAAAAAAAAAD7/6X/AAAAAAAAAAD9/6L/AAAAAAAAAAD8/6P/AAAAAAAAAAD6/5X/AAAAAAAAAAD+/5L/AAAAAAAAAAD9/5L/AAAAAAAAAAD9/5H/AAAAAAAAAAD8/5H/AAAAAAAAAAD7/5H/AAAAAAAAAAD6/5H/AAAAAAAAAAD6/5L/AAAAAAAAAAD6/5P/AAAAAAAAAAD6/5T/AAAAAAAAAAD7/5P/AAAAAAAAAAD7/5L/AAAAAAAAAAD8/5L/AAAAAAAAAAD+/5H/AAAAAAAAAAAAAJH/AAAAAAAAAAABAJH/AAAAAAAAAAACAJH/AAAAAAAAAAADAJH/AAAAAAAAAAAEAJH/AAAAAAAAAAD//5H/AAAAAAAAAAD//5L/AAAAAAAAAAAAAJL/AAAAAAAAAAAAAJP/AAAAAAAAAAAAAJT/AAAAAAAAAAAAAJX/AAAAAAAAAAABAJX/AAAAAAAAAAABAJL/AAAAAAAAAAABAJP/AAAAAAAAAAABAJT/AAAAAAAAAAAAAJb/AAAAAAAAAAAAAJf/AAAAAAAAAAAAAJj/AAAAAAAAAAACAJL/AAAAAAAAAAADAJL/AAAAAAAAAAAEAJL/AAAAAAAAAAAHAKL/AAAAAAAAAAAIAKL/AAAAAAAAAAAIAKT/AAAAAAAAAAAIAKX/AAAAAAAAAAD8/6X/AAABAAAAAAD9/6X/AAABAAAAAAD+/6X/AAABAAAAAAD//6X/AAABAAAAAAAAAKX/AAABAAAAAAABAKX/AAABAAAAAAACAKX/AAABAAAAAAADAKX/AAABAAAAAAAEAKX/AAABAAAAAAAFAKX/AAABAAAAAAAGAKX/AAAAAAAAAAAGAKT/AAAAAAAAAAAGAKL/AAAAAAAAAAAJAKL/AAABAAAAAAAJAKP/AAABAAAAAAAJAKT/AAABAAAAAAAJAKX/AAABAAAAAAAKAJf/AAAAAAAAAAAKAJj/AAAAAAAAAAAKAJn/AAAAAAAAAAAKAJr/AAAAAAAAAAAKAJv/AAAAAAAAAAALAJf/AAAAAAAAAAALAJj/AAAAAAAAAAALAJn/AAAAAAAAAAAKAJz/AAAAAAAAAAAMAJf/AAAAAAAAAAAMAJj/AAAAAAAAAAAMAJn/AAAAAAAAAAABAJb/AAAAAAAAAAABAJf/AAAAAAAAAAACAJP/AAAAAAAAAAAEAJP/AAAAAAAAAAADAJP/AAAAAAAAAAACAJT/AAAAAAAAAAADAJT/AAAAAAAAAAAEAJT/AAAAAAAAAAAKAKX/AAABAAAAAAAOAKX/AAABAAAAAAAPAKX/AAABAAAAAAAQAKX/AAABAAAAAAARAKX/AAABAAAAAAASAKX/AAABAAAAAAATAKX/AAABAAAAAAALAJ7/AAAAAAAAAAANAJn/AAAAAAAAAAAOAJn/AAAAAAAAAAALAJr/AAAAAAAAAAALAJv/AAAAAAAAAAAKAJ3/AAAAAAAAAAALAJz/AAAAAAAAAAALAJ3/AAAAAAAAAAARAJ7/AAAAAAAAAAARAJ3/AAAAAAAAAAARAJz/AAAAAAAAAAARAJv/AAAAAAAAAAARAJr/AAAAAAAAAAARAJn/AAAAAAAAAAARAJj/AAAAAAAAAAARAJf/AAAAAAAAAAARAJb/AAAAAAAAAAARAJX/AAAAAAAAAAARAJT/AAAAAAAAAAARAJP/AAAAAAAAAAARAJH/AAAAAAAAAAARAJL/AAAAAAAAAAAQAJP/AAAAAAAAAAAQAJT/AAAAAAAAAAAQAJX/AAAAAAAAAAAQAJb/AAABAAAAAAAQAJf/AAABAAAAAAAQAJj/AAABAAAAAAAQAJn/AAABAAAAAAAQAJr/AAABAAAAAAAQAJv/AAABAAAAAAAQAJz/AAABAAAAAAAQAJ3/AAABAAAAAAAQAJ7/AAABAAAAAAANAJj/AAAAAAAAAAAOAJj/AAAAAAAAAAASAJ7/AAAAAAAAAAATAJ7/AAAAAAAAAAAUAJ7/AAAAAAAAAAAVAJ7/AAAAAAAAAAAWAJ7/AAAAAAAAAAAXAJ7/AAAAAAAAAAAYAJ7/AAAAAAAAAAAUAKb/AAAAAAAAAAAVAKb/AAAAAAAAAAAVAKX/AAAAAAAAAAAWAKX/AAAAAAAAAAAXAKT/AAAAAAAAAAAYAKT/AAAAAAAAAAAYAKP/AAAAAAAAAAAXAKP/AAAAAAAAAAAUAKX/AAABAAAAAAAVAKT/AAABAAAAAAAWAKP/AAABAAAAAAAWAKT/AAAAAAAAAAAYAKL/AAAAAAAAAAAXAKL/AAABAAAAAAAZAKL/AAAAAAAAAAAaAKL/AAAAAAAAAAAbAKL/AAAAAAAAAAAaAJ3/AAAAAAAAAAAbAJ3/AAAAAAAAAAAZAJ3/AAAAAAAAAAAYAJ3/AAAAAAAAAAAQAJL/AAAAAAAAAAAPAJL/AAAAAAAAAAAOAJL/AAAAAAAAAAANAJH/AAAAAAAAAAAOAJH/AAAAAAAAAAAPAJH/AAAAAAAAAAAQAJH/AAAAAAAAAAAPAJP/AAAAAAAAAAAFAJH/AAAAAAAAAAAGAJH/AAAAAAAAAAAHAJH/AAAAAAAAAAAIAJH/AAAAAAAAAAAJAJH/AAAAAAAAAAAGAJL/AAAAAAAAAAAFAJL/AAAAAAAAAAAFAJP/AAAAAAAAAAAIAJL/AAAAAAAAAAASAJ3/AAAAAAAAAAASAJz/AAAAAAAAAAASAJv/AAAAAAAAAAASAJr/AAAAAAAAAAASAJn/AAAAAAAAAAASAJj/AAAAAAAAAAASAJf/AAAAAAAAAAASAJb/AAAAAAAAAAASAJX/AAAAAAAAAAASAJT/AAAAAAAAAAATAJ3/AAAAAAAAAAAUAJ3/AAAAAAAAAAAVAJ3/AAAAAAAAAAAWAJ3/AAAAAAAAAAAXAJ3/AAAAAAAAAAAXAJz/AAAAAAAAAAAYAJz/AAAAAAAAAAAZAJz/AAAAAAAAAAAbAJz/AAAAAAAAAAAaAKP/AAAAAAAAAAAbAKP/AAAAAAAAAAAZAKT/AAAAAAAAAAD6/5v/AAAAAAAAAAD6/5r/AAAAAAAAAAAFAKL/AAABAAAAAAAFAKP/AAABAAAAAAAFAKT/AAABAAAAAAAHAKT/AAAAAAAAAAAIAKP/AAAAAAAAAAAGAKP/AAAAAAAAAAALAKX/AAABAAAAAAAMAKX/AAABAAAAAAANAKX/AAABAAAAAAA=") tile_set = ExtResource("23_70cor") @@ -204,15 +237,14 @@ position = Vector2(184, -1679) scale = Vector2(0.9, 0.9) metadata/_edit_group_ = true -[node name="TriggerFallRock_Climb_1" parent="." instance=ExtResource("26_wsgut")] -position = Vector2(56.000004, -1688) -scale = Vector2(0.95, 0.95) - -[node name="TriggerFallRock_Climb" parent="." instance=ExtResource("26_wsgut")] -position = Vector2(216.00002, -1608) -scale = Vector2(0.95, 0.95) +[node name="TriggerFallRock_Climb_2" parent="." instance=ExtResource("26_wsgut")] +position = Vector2(215.5, -1608) +scale = Vector2(0.94, 0.94) [node name="spring" parent="." instance=ExtResource("25_v3u1d")] position = Vector2(-40, -1512) +[node name="Ripple" parent="." instance=ExtResource("30_3ly86")] +position = Vector2(-9, -1598) + [connection signal="player_entered" from="Props/PlayerTriggerVolumn" to="SceneManager" method="_on_player_trigger_volumn_player_entered"] diff --git a/_shader/ripple.gdshader b/_shader/ripple.gdshader new file mode 100644 index 0000000..b02a1a9 --- /dev/null +++ b/_shader/ripple.gdshader @@ -0,0 +1,141 @@ +shader_type canvas_item; + +// ============================= +// original: https://www.shadertoy.com/view/wtcSzN +// adaptation: GerardoLCDF +// ============================= + +uniform bool u_debug_mode = false; +uniform sampler2D noise_texture : filter_nearest; +uniform sampler2D logo_texture : filter_linear; +uniform vec2 logo_aspect_ratio = vec2(2.0, 0.85); + + + +#define PI 3.14159265359 +float vmin(vec2 v) { return min(v.x, v.y); } +float vmax(vec2 v) { return max(v.x, v.y); } +float ellip(vec2 p, vec2 s) { float m = vmin(s); return (length(p / s) * m) - m; } +float halfEllip(vec2 p, vec2 s) { p.x = max(0.0, p.x); float m = vmin(s); return (length(p / s) * m) - m; } +float fBox(vec2 p, vec2 b) { return vmax(abs(p) - b); } +float dvd_d(vec2 p) { float d = halfEllip(p, vec2(.8, .5)); d = max(d, -p.x - .5); float d2 = halfEllip(p, vec2(.45, .3)); d2 = max(d2, min(-p.y + .2, -p.x - .15)); d = max(d, -d2); return d; } +float dvd_v(vec2 p) { vec2 pp = p; p.y += .7; p.x = abs(p.x); vec2 a = normalize(vec2(1.0, -.55)); float d = dot(p, a); float d2 = d + .3; p = pp; d = min(d, -p.y + .3); d2 = min(d2, -p.y + .5); d = max(d, -d2); d = max(d, abs(p.x + .3) - 1.1); return d; } +float dvd_c(vec2 p) { p.y += .95; float d = ellip(p, vec2(1.8, .25)); float d2 = ellip(p, vec2(.45, .09)); d = max(d, -d2); return d; } +float dvd(vec2 p) { p.y -= .345; p.x -= .035; p *= mat2(vec2(1.0, 0.0), vec2(-0.2, 1.0)); float d = dvd_v(p); d = min(d, dvd_c(p)); p.x += 1.3; d = min(d, dvd_d(p)); p.x -= 2.4; d = min(d, dvd_d(p)); return d; } +float range(float vmin, float vmax, float value) { return (value - vmin) / (vmax - vmin); } +float rangec(float a, float b, float t) { return clamp(range(a, b, t), 0.0, 1.0); } +vec3 pal( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ) { return a + b*cos( 6.28318*(c*t+d) ); } +vec3 spectrum(float n) { return pal( n, vec3(0.5, 0.5, 0.5), vec3(0.5, 0.5, 0.5), vec3(1.0, 1.0, 1.0), vec3(0.0, 0.33, 0.67) ); } +void drawHit(inout vec4 col, vec2 p, vec2 hitPos, float hitDist) { float d = length(p - hitPos); if (u_debug_mode) { col = mix(col, vec4(0.0, 1.0, 1.0, 0.0), step(d, .1)); return; } float wavefront = d - hitDist * 1.5; float freq = 2.0; vec3 spec = (1.0 - spectrum(-wavefront * freq + hitDist * freq)); float ripple = sin((wavefront * freq) * PI*2.0 - PI/2.0); float blend = smoothstep(3.0, 0.0, hitDist); blend *= smoothstep(.2, -.5, wavefront); blend *= rangec(-4.0, .0, wavefront); col.rgb *= mix(vec3(1.0), spec, pow(blend, 4.0)); float height = (ripple * blend); col.a -= height * 1.9 / freq; } +vec2 ref(vec2 p, vec2 planeNormal, float offset) { float t = dot(p, planeNormal) + offset; p -= (2.0 * t) * planeNormal; return p; } +void drawReflectedHit(inout vec4 col, vec2 p, vec2 hitPos, float hitDist, vec2 screenSize) { col.a += length(p) * .0001; drawHit(col, p, hitPos, hitDist); } +void flip(inout vec2 pos) { vec2 flip_val = mod(floor(pos), 2.0); pos = abs(flip_val - mod(pos, 1.0)); } +float stepSign(float a) { return step(0.0, a) * 2.0 - 1.0; } +vec2 compassDir(vec2 p) { vec2 a = vec2(stepSign(p.x), 0.0); vec2 b = vec2(0.0, stepSign(p.y)); float s = stepSign(p.x - p.y) * stepSign(-p.x - p.y); return mix(a, b, s * .5 + .5); } +vec2 calcHitPos(vec2 move, vec2 dir, vec2 size) { vec2 hitPos = mod(move, 1.0); vec2 xCross = hitPos - hitPos.x / (size / size.x) * (dir / dir.x); vec2 yCross = hitPos - hitPos.y / (size / size.y) * (dir / dir.y); hitPos = max(xCross, yCross); hitPos += floor(move); return hitPos; } + + +void fragment() +{ + // 取 sprite 像素尺寸(用 TEXTURE_SIZE 是最标准的) + vec2 screenSize = vec2(textureSize(TEXTURE, 0)); + + // 把 UV(0~1) 映射到类似你原来 p 的坐标系: + // 中心为 0,按高度归一化 + vec2 p = (-screenSize + 2.0 * (UV * screenSize)) / screenSize.y; + + + if (u_debug_mode) { p *= 2.0; } + + vec2 screen_aspect = vec2(screenSize.x/screenSize.y, 1.0) * 2.0; + + float t = TIME; + vec2 dir = normalize(vec2(9.0, 16.0) * screen_aspect); + vec2 move = dir * t / 1.5; + + float logoScale = .1; + vec2 logoSize = logo_aspect_ratio * logoScale; + + vec2 size = screen_aspect - logoSize * 2.0; + + move = move / size + .5; + + // 单点发射:固定在中间(你也可以改成其他位置) + vec2 hitPos = vec2(0.0, 0.0); + + // col / colFx / colFy 保留,用来算法线高光 + vec4 col = vec4(1.0, 1.0, 1.0, 0.0); + vec4 colFx = vec4(1.0, 1.0, 1.0, 0.0); + vec4 colFy = vec4(1.0, 1.0, 1.0, 0.0); + vec2 e = vec2(.8, 0.0) / screenSize.y; + + float period = 2.0; // 每次发射间隔(秒) + float hitDist = mod(TIME, period); // 循环计时:0~period + + + // 直接画一次,不要反射链 + drawReflectedHit(col, p, hitPos, hitDist, screen_aspect); + drawReflectedHit(colFx, p + e, hitPos, hitDist, screen_aspect); + drawReflectedHit(colFy, p + e.yx, hitPos, hitDist, screen_aspect); + + + flip(move); + move = (move - .5) * size; + + float bf = .1; + float fx = (col.a - colFx.a) * 2.0; + float fy = (col.a - colFy.a) * 2.0; + vec3 nor = normalize(vec3(fx, fy, e.x/bf)); + + float ff = length(vec2(fx, fy)); + float ee = rangec(0.0, 10.0/screenSize.y, ff); + nor = normalize(vec3(vec2(fx, fy)*ee, ff)); + + col.rgb = clamp(1.0 - col.rgb, vec3(0.0), vec3(1.0)); + col.rgb /= 3.0; + + if (!u_debug_mode) { + vec3 lig = normalize(vec3(1.0, 2.0, 2.0)); + vec3 rd = normalize(vec3(p, -10.0)); + vec3 hal = normalize( lig - rd ); + + float dif = clamp(dot(lig, nor), 0.0, 1.0); + float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ), 16.0) * dif * (0.04 + 0.96 * pow( clamp(1.0 + dot(hal, rd), 0.0, 1.0), 5.0 )); + + vec3 lin = vec3(0.0); + lin += 5.0 * dif; + lin += .2; + col.rgb = col.rgb * lin; + col.rgb += 5.0 * spe; + } + + if (u_debug_mode) { + float b = vmin(abs(fract(p / screen_aspect) - .5) * 2.0); + b /= fwidth(b) * 2.0; + b = clamp(b, 0.0, 1.0); + b = 1.0 - b; + col.rgb = mix(col.rgb, vec3(0.0), b); + } + + vec2 logo_size = logo_aspect_ratio * logoScale; + + vec2 local_pos = p - move; + + vec2 logo_uv = (local_pos / logo_size) + 0.5; + + vec4 logo_sample = texture(logo_texture, logo_uv); + + float uv_valid = step(0.0, logo_uv.x) * step(logo_uv.x, 1.0) * step(0.0, logo_uv.y) * step(logo_uv.y, 1.0); + float logo_mask = logo_sample.a * uv_valid; + + //col.rgb = mix(col.rgb, logo_sample.rgb, logo_mask); + + vec4 noise_sample = texture(noise_texture, FRAGCOORD.xy / screenSize); + col.rgb += (noise_sample.rgb * 2.0 - 1.0) * .005; + + col.rgb = pow(col.rgb, vec3(1.0/1.5)); + + col.a = col.a * .5 + .5; + col.a *= .3; + COLOR = col; +} \ No newline at end of file diff --git a/_shader/ripple.gdshader.uid b/_shader/ripple.gdshader.uid new file mode 100644 index 0000000..1be54b5 --- /dev/null +++ b/_shader/ripple.gdshader.uid @@ -0,0 +1 @@ +uid://j1tsgesxgt8e diff --git a/_shader/ripple.tscn b/_shader/ripple.tscn new file mode 100644 index 0000000..e6e61df --- /dev/null +++ b/_shader/ripple.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=4 format=3 uid="uid://rrlq7ucvgbsv"] + +[ext_resource type="Shader" uid="uid://b14j7g5tolgq" path="res://_shader/new_shader.gdshader" id="1_kkjpc"] +[ext_resource type="Texture2D" uid="uid://cfjprjiin3dnk" path="res://_asset/ksw/normal.png" id="2_kkjpc"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_iixbh"] +shader = ExtResource("1_kkjpc") +shader_parameter/amount = 20.0 +shader_parameter/move = 1.0 +shader_parameter/bandsize = 0.1 +shader_parameter/speed = 1.0 + +[node name="Ripple" type="Node2D"] + +[node name="Sprite2D" type="Sprite2D" parent="."] +material = SubResource("ShaderMaterial_iixbh") +texture = ExtResource("2_kkjpc") diff --git a/_shader/ripple2.gdshader b/_shader/ripple2.gdshader new file mode 100644 index 0000000..007c991 --- /dev/null +++ b/_shader/ripple2.gdshader @@ -0,0 +1,149 @@ +shader_type canvas_item; + +// ✅ Godot 4:必须这样拿屏幕纹理(不能用 SCREEN_TEXTURE) +uniform sampler2D screen_tex : hint_screen_texture, filter_linear_mipmap; + +// 可视化调试:R=通道,G=边缘脊,B=尾迹 +uniform bool debug_show = false; + +// 由脚本每帧传入(屏幕UV 0~1) +uniform vec2 obj_uv = vec2(0.5, 0.5); +uniform vec2 obj_dir = vec2(1.0, 0.0); +uniform float obj_speed = 1.0; + +// 可选噪声:建议给一张灰度噪声(Perlin/BlueNoise) +// 没有也能跑,只是边缘会更规整 +uniform sampler2D noise_tex : filter_linear, repeat_enable; + +// -------- 形状(开槽+水脊)-------- +uniform float lane_half_width = 0.085; // 通道半宽(越大拨开越宽) +uniform float edge_width = 0.040; // 水脊宽度(卷起那条边) +uniform float trail_length = 0.55; // 尾迹长度 + +// -------- 位移强度(核心)-------- +uniform float push_strength = 0.075; // 两侧推开(主要折射) +uniform float drag_strength = 0.045; // 沿方向拖拽(带走水) +uniform float suck_strength = 0.030; // 中心下陷(通道更像被挖开) +uniform float curl_strength = 0.070; // 卷边强度(更像拨水卷起) + +// -------- 泡沫/细节 -------- +uniform float foam_strength = 0.45; // 水脊亮边强度 +uniform float noise_scale = 3.5; // 噪声缩放 +uniform float noise_advect = 0.50; // 噪声随时间沿方向流动速度 +uniform float chroma_shift = 0.60; // 色散强度(0=无) + +float sat(float x) { return clamp(x, 0.0, 1.0); } + +vec2 safe_norm(vec2 v) { + float l = length(v); + return (l > 1e-5) ? (v / l) : vec2(1.0, 0.0); +} + +float n2(vec2 uv) { + // 如果你没设置 noise_tex,这里通常会是 0(效果依旧能跑) + return texture(noise_tex, uv).r; +} + +// 用噪声梯度构造“卷动方向”(让边缘像被拨起来) +vec2 curl_dir(vec2 uv) { + float e = 0.002; + float nL = n2(uv - vec2(e, 0.0)); + float nR = n2(uv + vec2(e, 0.0)); + float nD = n2(uv - vec2(0.0, e)); + float nU = n2(uv + vec2(0.0, e)); + vec2 g = vec2(nR - nL, nU - nD); + return safe_norm(vec2(-g.y, g.x)); +} + +void fragment() { + vec2 uv = SCREEN_UV; + + vec2 dir = safe_norm(obj_dir); + vec2 perp = vec2(-dir.y, dir.x); + + // 局部坐标(相对玩家) + vec2 v = uv - obj_uv; + + float forward = dot(v, dir); // 沿前进方向(身后为正) + float side = dot(v, perp); // 左右偏移 + + // 只在“身后”生效(像船头拨水/尾迹) + float behind = step(0.0, forward); + + // 更像粘稠的尾迹衰减(指数衰减) + float trail = exp(-forward / max(trail_length, 1e-4)) * behind; + + // 通道(中间被拨开的区域) + float lane = 1.0 - smoothstep(lane_half_width, lane_half_width * 1.35, abs(side)); + + // 水脊(在通道边缘一圈) + float edge = 1.0 - smoothstep(edge_width, 0.0, abs(abs(side) - lane_half_width)); + + // 噪声坐标:沿运动方向流动 + vec2 flow_uv = uv * noise_scale + dir * (TIME * noise_advect); + + float nn = n2(flow_uv); + float wobble = (nn * 2.0 - 1.0); + + // 速度缩放(慢就弱) + float spd = sat(obj_speed); + + // 推开方向(左右分开) + float sgn = sign(side + 1e-6); + vec2 push = perp * sgn; + + // “抽走”方向(让中间更凹/更干净) + vec2 suck = -push; + + // 卷边:用 curl_dir + push 混合,让边缘有翻卷感 + vec2 cdir = curl_dir(flow_uv); + vec2 curl = (cdir + push * 0.6) * (edge * trail); + + // 组装位移场(折射偏移) + vec2 offset = vec2(0.0); + + // 1) 中央通道推开 + offset += push * (lane * trail) * (push_strength * spd); + + // 2) 沿方向拖拽(把水带走) + offset += dir * (lane * trail) * (drag_strength * spd); + + // 3) 中心下陷/抽走(更像被拨开挖出槽) + offset += suck * (lane * trail) * (suck_strength * spd); + + // 4) 边缘卷动(水脊翻起) + offset += curl * (curl_strength * spd); + + // 5) 边缘破碎(泡沫感) + offset += push * wobble * (edge * trail) * (0.02 * spd); + + // 先准备输出颜色变量(避免 return) + vec3 col; + + if (debug_show) { + // debug:R=通道,G=边缘,B=尾迹 + col = vec3(lane, edge, trail); + } else { + // ===== 折射采样(带一点色散)===== + vec2 o = offset; + + if (chroma_shift > 0.001) { + float cs = chroma_shift * 0.002; // 色散很容易过头,保持小 + float r = texture(screen_tex, uv + o * (1.0 + cs)).r; + float g = texture(screen_tex, uv + o).g; + float b = texture(screen_tex, uv + o * (1.0 - cs)).b; + col = vec3(r, g, b); + } else { + col = texture(screen_tex, uv + o).rgb; + } + + // ===== 泡沫亮边 ===== + float foam = edge * trail * spd; + foam *= (0.55 + 0.45 * wobble); // 破碎感 + foam = sat(foam); + + col += foam * foam_strength; + } + + COLOR = vec4(col, 1.0); +} diff --git a/_shader/ripple2.gdshader.uid b/_shader/ripple2.gdshader.uid new file mode 100644 index 0000000..f19d748 --- /dev/null +++ b/_shader/ripple2.gdshader.uid @@ -0,0 +1 @@ +uid://ccpo4346to8ka