284 lines
9.8 KiB
GDScript
284 lines
9.8 KiB
GDScript
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
|