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)



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
