176 lines
5.8 KiB
GDScript
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()
|