class_name WallDetector extends Node2D @onready var up_r: RayCast2D = $UpRayCast2D @onready var mid_r: RayCast2D = $MidRayCast2D @onready var down_r: RayCast2D = $DownRayCast2D var flip_h: bool = false: set(value): if flip_h == value: return else: flip_h = value flip(flip_h) return signal wall_state_changed(enter_wall: bool) signal up_ray_state_changed(enter_wall: bool) signal mid_ray_state_changed(enter_wall: bool) signal down_ray_state_changed(enter_wall: bool) var is_on_wall: bool = false : set = _change_wall_state var up_ray_on_wall: bool = false: set(value): if up_ray_on_wall == value: return else: up_ray_on_wall = value up_ray_state_changed.emit(value) var mid_ray_on_wall: bool = false: set(value): if mid_ray_on_wall == value: return else: mid_ray_on_wall = value mid_ray_state_changed.emit(value) var down_ray_on_wall: bool = false: set(value): if down_ray_on_wall == value: return else: down_ray_on_wall = value down_ray_state_changed.emit(value) var wall_direction : Vector2: get(): return Vector2(-1,0) if flip_h else Vector2(1,0) func _physics_process(delta: float) -> void: var n1 = up_r.get_collision_normal() as Vector2 var n2 = mid_r.get_collision_normal() as Vector2 var n3 = down_r.get_collision_normal() as Vector2 ##更新其他的射线的OnWall状态 up_ray_on_wall = up_r.is_colliding() and is_nearly_vertical_plane(n1) mid_ray_on_wall = mid_r.is_colliding() and is_nearly_vertical_plane(n2) down_ray_on_wall = down_r.is_colliding() and is_nearly_vertical_plane(n3) var all_collid = up_r.is_colliding() and mid_r.is_colliding() and down_r.is_colliding() as bool var vertical_plane = is_nearly_vertical_plane(n1) and is_nearly_vertical_plane(n2) and is_nearly_vertical_plane(n3) as bool is_on_wall = all_collid and vertical_plane ##修改wall state的函数,如果需要改就在这里改 func _change_wall_state(inis_on_wall: bool) -> void: if inis_on_wall: #如果在wall上的状态为真,则检测现在的状态是不是在wall上,如果不是,则发送状态改变 if is_on_wall: return else: wall_state_changed.emit(true) is_on_wall = true else: #如果在wall上的状态为false,则检测现在的状态是不是不在wall上,如果不是,则发送状态改变 if not is_on_wall: return else: wall_state_changed.emit(false) is_on_wall = false ##修改ray state的函数,如果需要改就在这里改 func _change_ray_state(inis_on_wall: bool,field_name: StringName,signal_name:StringName) -> void: var current_state = get(field_name) if inis_on_wall: if current_state: return else: emit_signal(signal_name,true) set(field_name,true) else: if not current_state: return else: emit_signal(signal_name,false) set(field_name,false) func flip(flip: bool) -> void: var r = Vector2(-1,1) if flip else Vector2(1,1) up_r.scale = r mid_r.scale = r down_r.scale = r ##Helper函数,判断是否是几乎垂直的面 func is_nearly_vertical_plane(normal: Vector2) -> bool: # 定义一个容忍度/阈值,例如 0.1 (表示角度偏离 90 度最多约 5.7 度) # 90 度的法线夹角意味着点积为 0。 # 我们要找的是法线接近水平的情况,即法线与 Y 轴(垂直)的点积接近 0。 # 垂直向量 (Y 轴) var world_up = Vector2.UP # (0, -1) 或 Vector2.DOWN (0, 1),取决于你的坐标系 # 为了代码健壮性,我们检查法线与垂直方向的点积的绝对值是否小于一个很小的阈值。 # 点积接近 0 => 向量(法线)和垂直向量接近正交(即法线接近水平)。 var dot_product_with_vertical = abs(normal.dot(world_up)) # 设定一个阈值 (epsilon),例如 0.1 # 如果点积的绝对值很小(接近 0),说明法线与世界Y轴接近垂直,即平面接近水平 # **更正:如果点积接近 0,说明法线与Y轴垂直,即平面是水平的。** # 我们要找的是“几乎垂直的平面”,这意味着法线接近水平方向 (X 轴) var world_right = Vector2.RIGHT # (1, 0) var dot_product_with_horizontal = abs(normal.dot(world_right)) const VERTICAL_PLANE_THRESHOLD = 0.9 # 阈值设为接近 1 # 如果法线与水平向量的点积绝对值很大(接近 1),则平面接近垂直 return dot_product_with_horizontal >= VERTICAL_PLANE_THRESHOLD