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

176 lines
5.8 KiB
GDScript

extends Node
var can_spawn = true
var spawn_frequency = 0.01
var base_scale = 0.9
var min_velocity = 5.0
var is_active = false
var after_image_material: ShaderMaterial
var after_image_scene = preload("res://Char/Char_Components/After_Image/after_image.tscn")
@onready var player = get_parent()
@onready var owner_sprite = player.get_node("Body_Animation/Sprite2D")
@onready var owner_anim = player.get_node("Body_Animation/AnimationPlayer")
func _ready():
if !after_image_material:
var new_material = ShaderMaterial.new()
new_material.shader = load("res://Char/Char_Components/After_Image/player_dash.gdshader")
after_image_material = new_material
after_image_material.set_shader_parameter("effect_mixture", 0.0)
after_image_material.set_shader_parameter("alpha_multiplier", 1.0)
after_image_material.set_shader_parameter("color_offset", 0.0)
after_image_material.set_shader_parameter("glow_intensity", 1.2)
reset_spawn_timer()
func _physics_process(_delta):
if is_active and can_spawn:
var velocity = owner.velocity if owner.has_method("get_velocity") else Vector2.ZERO
if velocity.length() >= min_velocity:
spawn_after_image()
func clear_shader():
after_image_material = null
func init_shader(shader_path: String, params: Dictionary = {}):
after_image_material = ShaderMaterial.new()
after_image_material.shader = load(shader_path)
for param_name in params:
after_image_material.set_shader_parameter(param_name, params[param_name])
func reset_spawn_timer():
can_spawn = false
await get_tree().create_timer(spawn_frequency).timeout
can_spawn = true
func spawn_after_image():
var level = get_tree().get_first_node_in_group("Level")
if !level:
return
var effect_group = level.get_node("Effect_Group")
if !effect_group:
return
var after_image = after_image_scene.instantiate()
after_image.position = owner_sprite.global_position
after_image.scale = owner_sprite.scale * base_scale
var after_image_sprite:Sprite2D = after_image.get_node("Sprite2D")
after_image_sprite.texture = owner_sprite.texture
after_image_sprite.region_enabled = true
after_image_sprite.region_rect = owner_sprite.region_rect
after_image.scale.x *= owner.get_node("Body_Animation").scale.x
if after_image_material:
var current_material = ShaderMaterial.new()
current_material.shader = after_image_material.shader
current_material.set_shader_parameter("rainbow_width",
after_image_material.get_shader_parameter("rainbow_width"))
current_material.set_shader_parameter("rainbow_speed",
after_image_material.get_shader_parameter("rainbow_speed"))
after_image_sprite.material = current_material
after_image.z_index = 5
effect_group.add_child(after_image)
reset_spawn_timer()
func start():
is_active = true
can_spawn = true
func stop():
is_active = false
can_spawn = false
clear_shader()
func set_shader_parameter(param_name: String, value):
if after_image_material:
after_image_material.set_shader_parameter(param_name, value)
func configure(config: Dictionary):
if config.has("spawn_frequency"):
spawn_frequency = config.spawn_frequency
if config.has("base_scale"):
base_scale = config.base_scale
if config.has("min_velocity"):
min_velocity = config.min_velocity
clear_shader()
func spawn_trail_between_points(start_pos: Vector2, end_pos: Vector2, num_images: int = 16, shader:bool = true, after_image_texture: Texture = null, after_image_rect: Rect2 = Rect2()):
var level = get_tree().get_first_node_in_group("Level")
if !level:
return
var effect_group = level.get_node("Effect_Group")
if !effect_group:
return
var total_distance = start_pos.distance_to(end_pos)
var direction = (end_pos - start_pos).normalized()
# 定义透明度范围
var alpha_start = 0.1 # 起始透明度
var alpha_end = 0.8 # 结束透明度
if shader and !after_image_material:
var new_material = ShaderMaterial.new()
new_material.shader = load("res://Char/Char_Components/After_Image/player_dash.gdshader")
after_image_material = new_material
after_image_material.set_shader_parameter("effect_mixture", 1.0)
after_image_material.set_shader_parameter("alpha_multiplier", 1.0)
after_image_material.set_shader_parameter("color_offset", 0.0)
after_image_material.set_shader_parameter("glow_intensity", 1.2)
for i in range(num_images):
var progress = float(i) / float(num_images - 1)
var adjusted_progress = 1.0 - pow(1.0 - progress, 1.5)
var current_pos = start_pos + direction * (total_distance * adjusted_progress)
var after_image = after_image_scene.instantiate()
var after_image_sprite = after_image.get_node("Sprite2D")
after_image_sprite.texture = after_image_texture
if after_image_rect != Rect2():
after_image_sprite.region_enabled = true
after_image_sprite.region_rect = after_image_rect
if end_pos.x < start_pos.x:
after_image_sprite.set_flip_h(true)
else:
after_image_sprite.set_flip_h(false)
after_image.position = current_pos + owner_sprite.position
after_image.scale = owner_sprite.scale * base_scale
# 计算当前的透明度
var current_alpha = lerp(alpha_start, alpha_end, progress)
if shader and after_image_material:
var current_material = after_image_material.duplicate()
current_material.set_shader_parameter("effect_mixture", 1.0)
# 使用统一的透明度计算
current_material.set_shader_parameter("alpha_multiplier", current_alpha)
current_material.set_shader_parameter("color_offset", 1.0 - progress)
after_image_sprite.material = current_material
# 如果需要同时使用modulate和shader效果
after_image_sprite.modulate = Color(1, 1, 1, current_alpha)
else:
# 非shader情况下的透明度处理
after_image_sprite.modulate = Color(1, 1, 1, current_alpha)
after_image.z_index = 5
effect_group.add_child(after_image)
if shader:
clear_shader()