Godot 4 源码分析 - Path2D与PathFollow2D

文章讲述了在Godot游戏引擎中,Path2D用于创建路径,而PathFollow2D则用于跟随路径并动态生成移动对象(Mob)的路径和方向。通过设置PathFollow2D的progress,开发者可以控制Mob在路径上的位置和方向,实现自定义的移动行为。

学习演示项目dodge_the_creeps,发现里面多了一个Path2D与PathFollow2D

 研究GDScript代码发现,它主要用于随机生成Mob

	var mob_spawn_location = get_node(^"MobPath/MobSpawnLocation")
	mob_spawn_location.progress = randi()

	# Set the mob's direction perpendicular to the path direction.
	var direction = mob_spawn_location.rotation + PI / 2

	# Set the mob's position to a random location.
	mob.position = mob_spawn_location.position

	# Add some randomness to the direction.
	direction += randf_range(-PI / 4, PI / 4)
	mob.rotation = direction

	# Choose the velocity for the mob.
	var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
	mob.linear_velocity = velocity.rotated(direction)

这个有这么大的作用,不明觉厉

但不知道如何下手

查看源码,有编辑器及类源码

先从应用角度,到B站上找找有没有视频,结果发现这个

Godot塔防游戏 - 01 -核心路径制作 Path2D_哔哩哔哩_bilibili

看了之后,就知道使用方法了:

  • 添加Path2D
  • 在编辑器中设置路径各关键点,形成路径

  • 在Path2D下增加PathFollow2D

这就OK了。剩下的就是使用

所谓使用,输入为PathFollow2D的progress,输出为路径上的点信息(position, rotation...),然后用户再根据这些信息去确定相应的属性

比如演示项目中,Path2D定制了一个外框路径(左上角 > 右上角 > 右下角 > 左下角 > 左上角),在生成MOB时,随机指定其下的PathFollow2D的progress值为randi(),即为0 ~ 2^32 - 1的随机整数。因为路径是有长度的,本例中为2400,randi()值将按2400取模得到最终的随机值0 - 2399,当然也可以归一化,设置其progress_ratio值为0.0 - 1.0,意思一样。

查看源码,set_progress的逻辑不只是取模,还有限制范围。即PathFollow2D还有一个Loop属性,如果Loop为真,才会取模,为false时,会直接限制在路径长度范围内 progress = CLAMP(progress, 0, path_length); 之后统一更新_update_transform

void PathFollow2D::set_progress(real_t p_progress) {
	ERR_FAIL_COND(!isfinite(p_progress));
	progress = p_progress;
	if (path) {
		if (path->get_curve().is_valid()) {
			real_t path_length = path->get_curve()->get_baked_length();

			if (loop && path_length) {
				progress = Math::fposmod(progress, path_length);
				if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) {
					progress = path_length;
				}
			} else {
				progress = CLAMP(progress, 0, path_length);
			}
		}

		_update_transform();
	}
}

void PathFollow2D::_update_transform() {
	if (!path) {
		return;
	}

	Ref<Curve2D> c = path->get_curve();
	if (!c.is_valid()) {
		return;
	}

	real_t path_length = c->get_baked_length();
	if (path_length == 0) {
		return;
	}

	if (rotates) {
		Transform2D xform = c->sample_baked_with_rotation(progress, cubic);
		xform.translate_local(v_offset, h_offset);
		set_rotation(xform[1].angle());
		set_position(xform[2]);
	} else {
		Vector2 pos = c->sample_baked(progress, cubic);
		pos.x += h_offset;
		pos.y += v_offset;
		set_position(pos);
	}
}

从PathFollow2D代码来看,它派生于Node2D,所以具备trans

Godot 4.4.1 中,`CharacterBody2D` 是用于实现 2D 角色移动和碰撞检测的核心节点之一。它不会自动场景中的其他物理对象进行响应式交互,而是需要手动处理移动逻辑,并通过内置函数检测碰撞。 要检测 `CharacterBody2D` 平台之间的碰撞,可以通过以下方式实现: ### 使用 `move_and_slide()` 和 `get_collision_*()` 方法 当调用 `move_and_slide()` 方法时,`CharacterBody2D` 会自动处理其他物体的碰撞并滑动。可以利用 `get_collision_normal()` 和 `is_on_floor()` 等方法来判断角色是否平台发生接触。 例如,在 `_physics_process(delta)` 函数中添加如下代码片段以检测是否着陆在平台上: ```gdscript func _physics_process(delta): var direction = Vector2.ZERO if Input.is_action_pressed("ui_right"): direction.x += 1 if Input.is_action_pressed("ui_left"): direction.x -= 1 velocity.x = direction.x * move_speed velocity.y += gravity * delta velocity = move_and_slide(velocity, Vector2.UP) # 检测是否地面发生碰撞 if is_on_floor(): print("Landing on platform") ``` ### 使用信号或 Area2D 检测特定平台 如果希望检测特定平台(例如可穿透的地板或触发器)的碰撞,可以使用 `Area2D` 节点作为检测区域。将 `Area2D` 添加到 `CharacterBody2D` 或平台节点上,并连接其 `body_entered` 或 `area_entered` 信号来监听碰撞事件。 例如,在 `CharacterBody2D` 上添加一个 `Area2D` 子节点,并为其绑定脚本: ```gdscript extends Area2D func _on_body_entered(body): if body.name == "Platform": print("Collided with platform") ``` 确保在编辑器中为该 `Area2D` 添加合适的 `CollisionShape2D` 并启用 `monitoring` 属性。 ### 利用导航代理检测路径可达性 如果同时集成了 `NavigationAgent2D`,可以结合 `is_target_reachable()` 和 `get_next_path_position()` 来判断目标位置是否可达,从而间接确认是否存在障碍物或平台阻挡[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值