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

284 lines
9.8 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node2D
@export var min_rays := 5
@export var max_rays := 12
@export var min_length := 60.0
@export var max_length := 160.0
var spread_angle := randf_range(20,30)
var _last_sprite_index: int = -1 # 记录上一次使用的精灵索引
var blood_part_2_enabled = false
#func _ready() -> void:
#create_part1_blood(Vector2(1,0))
func _physics_process(_delta: float) -> void:
if blood_part_2_enabled and randf() > 0.5:
var pos = global_position
var dir = get_parent().velocity.normalized()
spawn_blood_part_2(pos,dir)
#region 初始涂墙
func create_part1_blood(direction):
var current_rays = generate_rays(direction)
for each_ray in current_rays:
create_two_segment_sprite_line(each_ray["start"], each_ray["middle_point"], each_ray["end"], randi_range(10,30),randi_range(1,3))
func generate_rays(direction: Vector2) -> Array:
var current_rays: Array = []
direction = direction.normalized()
var ray_count = randi_range(min_rays, max_rays)
# 1. 计算角度范围
var base_angle = direction.angle()
var max_deviation = deg_to_rad(spread_angle)
var section_size = (max_deviation * 2) / (ray_count + 1)
var start_angle = base_angle - max_deviation
# 2. 创建所有射线
var raycasts: Array[RayCast2D] = []
for i in ray_count:
var section_start = start_angle + section_size * i
var section_end = section_start + section_size
var final_angle = randf_range(section_start, section_end)
var raycast = RayCast2D.new()
add_child(raycast)
raycasts.append(raycast)
raycast.position = Vector2.ZERO
var ray_direction = Vector2(cos(final_angle), sin(final_angle))
var ray_length = randf_range(min_length, max_length)
raycast.target_position = ray_direction * ray_length
raycast.collision_mask = 0
for layer in [20,22,23,24,25]:
raycast.set_collision_mask_value(layer, true)
raycast.enabled = true
raycast.force_raycast_update()
# 3. 处理射线结果
for i in ray_count:
var raycast = raycasts[i]
var ray_direction = raycast.target_position.normalized()
var intended_length = raycast.target_position.length()
# 生成60%-80%之间的随机比例
var middle_ratio = randf_range(0.5, 0.8)
if raycast.is_colliding():
var global_collision_point = raycast.get_collision_point()
var distance_to_collision = global_position.distance_to(global_collision_point)
if distance_to_collision <= intended_length:
# 计算中间点(在实际碰撞点之前)
var middle_point = global_position.lerp(global_collision_point, middle_ratio)
current_rays.append({
"start": global_position,
"end": global_collision_point,
"middle_point": middle_point,
"collision": true,
"out_of_range_collision": false,
"intended_length": intended_length
})
else:
var global_clamped_end = global_position + (ray_direction * intended_length)
var middle_point = global_position.lerp(global_clamped_end, middle_ratio)
current_rays.append({
"start": global_position,
"end": global_clamped_end,
"middle_point": middle_point,
"collision": false,
"out_of_range_collision": true,
"intended_length": intended_length
})
else:
var global_intended_end = global_position + (ray_direction * intended_length)
var middle_point = global_position.lerp(global_intended_end, middle_ratio)
current_rays.append({
"start": global_position,
"end": global_intended_end,
"middle_point": middle_point,
"collision": false,
"out_of_range_collision": false,
"intended_length": intended_length
})
raycast.queue_free()
return current_rays
# 主函数:生成三点两段的精灵线
func create_two_segment_sprite_line(
start_pos: Vector2,
middle_pos: Vector2,
end_pos: Vector2,
first_segment_count: int,
second_segment_count: int,
) -> void:
var sprite_scene_group_1: Array[PackedScene] = [
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_01.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_02.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_03.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_04.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_05.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_06.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_1_07.tscn")
]
var sprite_scene_group_2: Array[PackedScene] = [
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_01.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_02.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_03.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_04.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_05.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_06.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_07.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_08.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_09.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_10.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_12.tscn"),
preload("res://Char/Char_Components/Blood/Art/blood_stain_2_11.tscn")
]
_last_sprite_index = -1 # 重置上一次的索引
# 生成两段
create_sprite_line_segment(start_pos, middle_pos, first_segment_count, 1.1, 1.0, sprite_scene_group_1)
_last_sprite_index = -1 # 两段之间重置,让两段独立
create_sprite_line_segment(middle_pos, end_pos, second_segment_count, 0.8, 0.6, sprite_scene_group_2)
# 生成单段精灵线
func create_sprite_line_segment(
start_pos: Vector2,
end_pos: Vector2,
sprite_count: int,
start_scale: float,
end_scale: float,
_sprite_scene_group: Array[PackedScene]
) -> void:
var parent = get_tree().get_first_node_in_group("Effect_Group")
if not parent:
push_warning("未找到Effect_Group组的节点")
return
sprite_count = maxi(1, sprite_count)
var direction = end_pos - start_pos
for i in range(sprite_count):
var progress = float(i) / (sprite_count - 1) if sprite_count > 1 else 0.0
var _current_pos = start_pos.lerp(end_pos, progress)
var _scale_value = lerp(start_scale, end_scale, progress)
var _rotation = direction.angle()
# 随机选择一个场景(避免重复)
#var selected_scene = _get_random_sprite_scene(sprite_scene_group)
#_create_single_sprite(current_pos, _rotation, scale_value, parent, selected_scene)
var blood_impulse_percent = randf()
if blood_impulse_percent > 0.9:
spawn_blood_part_1(start_pos,end_pos)
blood_part_2_enabled = true
# 随机选择场景(避免与上次重复)
func _get_random_sprite_scene(sprite_scene_group: Array[PackedScene]) -> PackedScene:
var group_size = sprite_scene_group.size()
if group_size == 1:
return sprite_scene_group[0]
# 生成可用索引列表(排除上次使用的索引)
var available_indices: Array[int] = []
for i in range(group_size):
if i != _last_sprite_index:
available_indices.append(i)
# 随机选择一个新索引
var random_index = available_indices[randi() % available_indices.size()]
_last_sprite_index = random_index # 更新上次使用的索引
return sprite_scene_group[random_index]
# 创建单个精灵
func _create_single_sprite(pos: Vector2, _rotation: float, scale_value: float, parent: Node, sprite_scene: PackedScene) -> void:
var sprite = sprite_scene.instantiate() as Sprite2D
if not sprite:
push_warning("场景实例化失败!")
return
sprite.position = pos
sprite.rotation = _rotation
sprite.scale = Vector2(scale_value, scale_value)
sprite.self_modulate = Color.from_string("959595ca", Color.WHITE)
parent.add_child(sprite)
#region End
func spawn_blood_part_1(start_pos: Vector2, end_pos: Vector2) -> void:
var effect_scene = preload("res://Char/Char_Components/Blood/blood_part.tscn")
# 计算方向向量(标准化)
var dir = (end_pos - start_pos).normalized()
# 随机选择生成位置
var spawn_pos = start_pos if randi() % 2 == 0 else end_pos
# 实例化场景
var effect_instance = effect_scene.instantiate()
# 设置位置和旋转
effect_instance.global_position = spawn_pos
effect_instance.rotation = dir.angle()
effect_instance.can_stain = true
effect_instance.z_index = 2
# 设置速度 (假设effect_instance继承自CharacterBody2D)
effect_instance.velocity = dir * randf_range(100,200)
# 添加到效果组的第一个节点下
var effect_parent = get_tree().get_first_node_in_group("Effect_Group")
if effect_parent:
effect_parent.add_child(effect_instance)
func spawn_blood_part_2(pos: Vector2, dir: Vector2) -> void:
var PROJECTILE_SPEED = 80.0
var scene = preload("res://Char/Char_Components/Blood/blood_part.tscn")
# 确保方向向量有效
if dir.length_squared() == 0:
dir = Vector2(0,1)
# 获取特定组的父节点
var parent = get_tree().get_first_node_in_group("Effect_Group")
if not parent:
push_error("Cannot find Effect_Group node")
return
# 标准化方向向量
var normalized_dir = dir.normalized()
# 实例化场景
var instance = scene.instantiate() as CharacterBody2D
if not instance:
push_error("Failed to instantiate scene or invalid type")
return
# 添加到场景树
parent.add_child(instance)
# 计算基础角度和随机偏移
var base_angle = (-normalized_dir).angle()
var random_offset = deg_to_rad(randf_range(-3.0, 3.0)) # 转换度数为弧度
var final_angle = base_angle + random_offset
# 设置位置和朝向
instance.global_position = pos
instance.rotation = final_angle
instance.scale.y *= 1 if randf() < 0.5 else -1 #血液喷出动画左右镜像
instance.can_stain = true
instance.z_index = 2
# 根据最终角度计算速度方向
var final_dir = Vector2.from_angle(final_angle + PI) # 加PI是因为我们要反方向
# 设置初始速度
instance.velocity = final_dir * PROJECTILE_SPEED