D3/Char/Char_Components/Blood/blood_stain.gd
2025-05-10 23:19:52 +08:00

148 lines
4.3 KiB
GDScript

extends Sprite2D
@onready var tile_group = get_tree().get_first_node_in_group("Tile_Group")
var mask_viewport: SubViewport
var mask_texture: ViewportTexture
var is_queued_for_update := false
var camera: Camera2D
var last_camera_position := Vector2.ZERO
var last_camera_offset := Vector2.ZERO # 新增:跟踪相机偏移量
class MaskRenderer extends Node2D:
var is_queued_for_update := false
func _draw():
var tile_group = get_tree().get_first_node_in_group("Tile_Group")
if not tile_group or tile_group.tilemaplayers.is_empty():
return
var reference_layer = tile_group.tilemaplayers[0]
for info in tile_group.mask_tile_info:
var base_pos = reference_layer.map_to_local(info.position)
for shape in info.shapes:
match shape.type:
"polygon":
var transformed_points = PackedVector2Array()
for point in shape.points:
transformed_points.append(base_pos + point)
draw_colored_polygon(transformed_points, Color.WHITE)
"rect":
var pos = base_pos - shape.size/2
var rect = Rect2(pos, shape.size)
draw_rect(rect, Color.WHITE, true)
func queue_update():
if not is_queued_for_update:
is_queued_for_update = true
RenderingServer.frame_post_draw.connect(_on_frame_post_draw, CONNECT_ONE_SHOT)
func _on_frame_post_draw():
is_queued_for_update = false
queue_redraw()
func _ready():
# 设置 SubViewport
_setup_viewport()
# 设置着色器
_setup_shader()
# 订阅信号
tile_group.mask_tiles_updated.connect(_on_mask_tiles_updated)
# 寻找并跟踪相机
_find_and_track_camera()
await RenderingServer.frame_post_draw
_update_viewport_for_camera()
material.set_shader_parameter("mask_texture", mask_viewport.get_texture())
func _setup_viewport():
mask_viewport = SubViewport.new()
mask_viewport.transparent_bg = true
mask_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
add_child(mask_viewport)
var mask_renderer = MaskRenderer.new()
mask_viewport.add_child(mask_renderer)
func _setup_shader():
var shader_material = ShaderMaterial.new()
shader_material.shader = preload("res://Char/Char_Components/Blood/blood_mask.gdshader")
material = shader_material
func _find_and_track_camera():
# 寻找场景中的相机
var level = get_tree().get_first_node_in_group("Level")
if level:
camera = level.get_node_or_null("Player/Camera2D")
if camera:
last_camera_position = camera.get_screen_center_position()
func _process(_delta):
if not camera:
return
var current_pos = camera.get_screen_center_position()
var current_offset = camera.offset
# 检查相机位置或偏移量是否发生变化
if current_pos != last_camera_position or current_offset != last_camera_offset:
last_camera_position = current_pos
last_camera_offset = current_offset
_update_viewport_for_camera()
func _update_viewport_for_camera():
if not camera:
return
# 获取相机的视口大小和缩放
var viewport_rect = get_viewport_rect()
var zoom = camera.zoom
var screen_size = viewport_rect.size
# 计算实际需要的视口大小(考虑缩放)
var actual_size = screen_size / zoom
# 更新 SubViewport 大小
mask_viewport.size = actual_size
# 获取相机的全局位置和偏移量
var camera_global_pos = camera.get_screen_center_position()
var camera_offset = camera.offset
# 计算实际的相机中心位置(考虑偏移量)
var effective_camera_center = camera_global_pos + camera_offset * zoom
# 计算视口的左上角位置
var top_left = effective_camera_center - (actual_size / 2)
# 更新 MaskRenderer 的位置以对齐相机
if mask_viewport.get_child(0) is MaskRenderer:
var mask_renderer = mask_viewport.get_child(0)
mask_renderer.position = -top_left
# 触发一次更新
_update_mask()
func _update_mask():
if mask_viewport and mask_viewport.get_child(0) is MaskRenderer:
var mask_renderer = mask_viewport.get_child(0) as MaskRenderer
mask_renderer.queue_update()
func _on_mask_tiles_updated():
if not is_queued_for_update:
is_queued_for_update = true
RenderingServer.frame_post_draw.connect(_update_mask_deferred, CONNECT_ONE_SHOT)
func _update_mask_deferred():
is_queued_for_update = false
_update_mask()
func cleanup():
if tile_group and tile_group.mask_tiles_updated.is_connected(_on_mask_tiles_updated):
tile_group.mask_tiles_updated.disconnect(_on_mask_tiles_updated)
func _exit_tree():
cleanup()