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

五、效果比对


<>
<>
<>
<>
<>

相关推荐
AA陈超1 小时前
虚幻引擎5 GAS开发俯视角RPG游戏 P07-18.生成火球术
c++·游戏·ue5·游戏引擎·虚幻
Doc.S6 小时前
多无人机任务自定义(基于ZJU-FAST-Lab / EGO-Planner-v2)
游戏引擎·无人机·cocos2d
nnsix8 小时前
Unity OpenXR开发HTC Vive Cosmos
unity·游戏引擎
nnsix8 小时前
Unity OpenXR,扳机键交互UI时,必须按下扳机才触发
unity·游戏引擎
老朱佩琪!9 小时前
Unity访问者模式
unity·游戏引擎·访问者模式
不定时总结的那啥9 小时前
Unity实现点击Console消息自动选中预制体的方法
unity·游戏引擎
nnsix10 小时前
Unity OpenXR 关闭手柄的震动
unity·游戏引擎
CreasyChan10 小时前
Unity 中的反射使用详解
unity·c#·游戏引擎·游戏开发
习惯就好zz10 小时前
Godot GDExtension 4.5 windows编译记录
windows·godot·cpp·gdextension
天途小编10 小时前
无人机操控模式解析:美国手、日本手、中国手
游戏引擎·无人机·cocos2d