Godot 敌人生成半径和围墙不匹配,导致敌人错误的生成在围墙外的解决代码

一、原视频

  1. Preventing Invalid Spawning

二、原代码

python 复制代码
func get_spawn_position():
	var player = get_tree().get_first_node_in_group("player") as Node2D
	if player == null:
		return Vector2.ZERO
	
	var spawn_position = Vector2.ZERO
	var random_direction = Vector2.RIGHT.rotated(randf_range(0, TAU))
	for i in 4:
		spawn_position = player.global_position + ( random_direction * SPAWN_RADIUS )
		
		var query_parameters = PhysicsRayQueryParameters2D.create(player.global_position, spawn_position, 1)
		var result: Dictionary = get_tree().root.world_2d.direct_space_state.intersect_ray(query_parameters)
		
		if result.is_empty():
			# 射线检测结果中没有碰撞
			break
		else:
			# 射线检测结果中有碰撞
			random_direction = random_direction.rotated(deg_to_rad(90))
	
	return spawn_position
	

三、原视频未修复证据

https://www.bilibili.com/video/BV1s8411v7nE/?p=35&t=479

老鼠穿越岔劈了,给镶进墙里了,哈哈哈哈哈

四、修复代码

注:解决方法有很多,但是这个只会修改get_spawn_position本身,以免把项目改得乱糟糟

python 复制代码
const ENEMY_SPAWN_WALL_CLEARANCE = 36 # 这是墙的厚度,让敌人生成时不要卡墙里面,直角边32和直角边16的斜边向上取整就是36
func get_spawn_position_v2():
	var player = get_tree().get_first_node_in_group("player") as Node2D
	if player == null:
		return Vector2.ZERO
	var player_pos = player.global_position
	var RayQueryParams2D = PhysicsRayQueryParameters2D
	
	var spawn_position = Vector2.ZERO
	var original_direction = Vector2.RIGHT.rotated(randf_range(0, TAU))
	
	spawn_position = player_pos + (original_direction * SPAWN_RADIUS)
	var original_query_parameters = RayQueryParams2D.create(player_pos, spawn_position, 1)
	var original_raycast_result: Dictionary = get_tree().root.world_2d.direct_space_state.intersect_ray(original_query_parameters)
	var direction_to_player_pos = (player_pos - spawn_position).normalized()
	spawn_position = spawn_position + (direction_to_player_pos * ENEMY_SPAWN_WALL_CLEARANCE)
	if not original_raycast_result.is_empty():
		# 射线检测结果中有碰撞
		# 遇到这种情况,说明SPAWN_RADIUS不适配你的围墙尺寸,(偏移90°, 180°, 270°)全都算完一起做比对
		var wall_positions: Array[Vector2] = []
		wall_positions.append(original_raycast_result["position"])
		# 准备3个可能的方向(原始方向 + 90°, 180°, 270°)
		var directions = [
			original_direction.rotated(deg_to_rad(90)),
			original_direction.rotated(deg_to_rad(180)),
			original_direction.rotated(deg_to_rad(270))
		]
		# 对每个方向进行射线检测
		for dir in directions:
			var test_position = player_pos + (dir * SPAWN_RADIUS)
			var query_parameters = RayQueryParams2D.create(player_pos, test_position, 1)
			var raycast_result = get_tree().root.world_2d.direct_space_state.intersect_ray(query_parameters)
			
			if raycast_result.is_empty():
				wall_positions.append(test_position)
			else:
				wall_positions.append(raycast_result["position"])
		
		# 找到距离玩家最远的点
		var farthest_pos = wall_positions[0]
		for pos in wall_positions:
			if pos.distance_squared_to(player_pos) > farthest_pos.distance_squared_to(player_pos):
				farthest_pos = pos
		
		# 将这个点向玩家附近的重心点的方向移动36
		# (该重心点受地图碰撞影响,不会紧贴地图边缘)
		# (36是墙厚度,避免卡墙里)
		var centroid_pos = calculate_centroid(player_pos, 1)
		var direction_to_centroid_pos = (centroid_pos - farthest_pos).normalized()
		spawn_position = farthest_pos + (direction_to_centroid_pos * ENEMY_SPAWN_WALL_CLEARANCE)
	
	return spawn_position


# 给定坐标为中心,均匀向四周发出 9 条射线,计算这 9 个碰撞点的质心
func calculate_centroid(position: Vector2, mask: int) -> Vector2:
	var points = []
	var ray_length = 300
	var angle_step = 2 * PI / 8  # 将 360 度(即 2π 弧度)均分为 8 份,得到每份的角度
	for i in range(9):
		var angle = i * angle_step
		var ray_direction = Vector2.RIGHT.rotated(angle)  # 生成射线方向
		var ray_end = position + ray_direction * ray_length  # 计算射线终点

		var query_parameters = PhysicsRayQueryParameters2D.create(position, ray_end, mask)
		var result = get_tree().root.world_2d.direct_space_state.intersect_ray(query_parameters)

		if result.is_empty():
			# 如果没有碰撞,添加射线终点
			points.append(ray_end)
		else:
			points.append(result["position"])  # 添加碰撞点

	# 计算质心
	var centroid = Vector2.ZERO
	for p in points:
		centroid += p
	centroid /= points.size()
	return centroid

五、效果比对


<>
<>
<>
<>
<>

相关推荐
技术小甜甜13 小时前
【Godot引擎】如何使用内置的全局搜索功能提升开发效率
游戏引擎·godot
技术小甜甜13 小时前
【Godot】如何导出 Release 版本的安卓项目
android·游戏引擎·godot
ChiLi_Lin1 天前
Unity异常上报飞书工具
unity·游戏引擎·飞书
Magnum Lehar1 天前
vulkan游戏引擎的makefile启动环境实现
游戏引擎
地狱为王1 天前
基于VLC的Unity视频播放器(四)
unity·游戏引擎·音视频
1 天前
Unity与Excel表格交互热更方案
unity·游戏引擎·excel
装大炮的自行车2 天前
【Unity】R3 CSharp 响应式编程 - 使用篇(集合)(三)
windows·unity·游戏引擎
阿松爱学习2 天前
【Unity开发】控制手机移动端的震动
unity·游戏引擎·unity开发
快乐觉主吖2 天前
Unity安卓平台开发,启动app并传参
android·unity·游戏引擎