lerp_angle
最后同步日期:2026-04-15 | Godot 官方原文 — lerp_angle
lerp_angle
定义
lerp_angle() 是专门用于角度值的线性插值函数。它和 lerp() 的作用一样——在两个值之间按比例取中间值——但它多了一个关键能力:自动处理角度的环绕问题。
打个比方:想象你手里拿着一个指南针。当前指针指向 350 度(差不多朝北偏西一点),你想让它转到 10 度(差不多朝北偏东一点)。如果用普通的 lerp(),指针会逆时针转一大圈,经过 270 度、180 度、90 度,最后才到 10 度——足足转了 340 度!但 lerp_angle() 会聪明地选择最短路径,让指针顺时针轻轻一转就到了,只转 20 度。
为什么角度会"环绕"? 因为角度是一个"首尾相连"的值——0 度和 360 度其实是同一个方向,-180 度和 180 度也是同一个方向。普通的 lerp() 不知道这一点,所以当角度跨越这个"接缝"时,就会走弯路。lerp_angle() 会自动识别最短的角度路径,让旋转始终走"近路"。
函数签名
public static float LerpAngle(float from, float to, float weight)func lerp_angle(from: float, to: float, weight: float) -> float参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
from | float | 是 | 起始角度(弧度制)。当 weight 为 0 时,返回此值 |
to | float | 是 | 目标角度(弧度制)。当 weight 为 1 时,返回此值 |
weight | float | 是 | 插值权重。0.0 = 完全是 from,1.0 = 完全是 to,0.5 = 正中间 |
关于弧度制:Godot 中所有角度统一使用弧度制。PI 弧度 = 180 度,2 * PI 弧度 = 360 度。如果你习惯角度制,可以用
Mathf.DegToRad()/deg_to_rad()转换输入,用Mathf.RadToDeg()/rad_to_deg()转换输出。
返回值
float -- 返回从 from 到 to 之间按 weight 插值后的角度值(弧度制)。函数会自动选择最短的角度路径进行插值。
代码示例
基础用法:对比 lerp 和 lerp_angle
using Godot;
public partial class LerpAngleExample : Node
{
public override void _Ready()
{
// 从 350 度转到 10 度——跨越 0 度/360 度的边界
float from = Mathf.DegToRad(350.0f);
float to = Mathf.DegToRad(10.0f);
// 用普通 lerp:会走远路(逆时针转 340 度)
float normalResult = Mathf.Lerp(from, to, 0.5f);
GD.Print($"普通 lerp: {Mathf.RadToDeg(normalResult):F1} 度"); // 运行结果: 180.0 度(走了远路)
// 用 lerp_angle:走近路(顺时针转 20 度,半路就是 0 度)
float angleResult = Mathf.LerpAngle(from, to, 0.5f);
GD.Print($"lerp_angle: {Mathf.RadToDeg(angleResult):F1} 度"); // 运行结果: 0.0 度(走了近路)
}
}func _ready():
# 从 350 度转到 10 度——跨越 0 度/360 度的边界
var from = deg_to_rad(350.0)
var to = deg_to_rad(10.0)
# 用普通 lerp:会走远路(逆时针转 340 度)
var normal_result = lerp(from, to, 0.5)
print("普通 lerp: %.1f 度" % rad_to_deg(normal_result)) # 运行结果: 180.0 度(走了远路)
# 用 lerp_angle:走近路(顺时针转 20 度,半路就是 0 度)
var angle_result = lerp_angle(from, to, 0.5)
print("lerp_angle: %.1f 度" % rad_to_deg(angle_result)) # 运行结果: 0.0 度(走了近路)实际场景:角色平滑转向敌人
using Godot;
public partial class PlayerRotation : Node2D
{
// 导出属性:转向速度(越大转得越快)
[Export] public float ExTurnSpeed = 5.0f;
// 内部变量:目标角度
private float _targetAngle = 0.0f;
public override void _Process(double delta)
{
// 使用 lerp_angle 让角色平滑转向目标角度
// 越接近目标转得越慢,产生自然的"减速转向"效果
Rotation = Mathf.LerpAngle(Rotation, _targetAngle, ExTurnSpeed * (float)delta);
}
// 让角色朝向指定位置
public void LookAtTarget(Vector2 targetPosition)
{
Vector2 direction = targetPosition - GlobalPosition;
_targetAngle = Mathf.Atan2(direction.Y, direction.X);
}
}extends Node2D
# 导出属性:转向速度(越大转得越快)
@export var turn_speed: float = 5.0
# 内部变量:目标角度
var _target_angle: float = 0.0
func _process(delta):
# 使用 lerp_angle 让角色平滑转向目标角度
# 越接近目标转得越慢,产生自然的"减速转向"效果
rotation = lerp_angle(rotation, _target_angle, turn_speed * delta)
# 让角色朝向指定位置
func look_at_target(target_position: Vector2):
var direction = target_position - global_position
_target_angle = atan2(direction.y, direction.x)进阶用法:炮塔自动追踪目标
using Godot;
public partial class Turret : Node2D
{
// 导出属性:炮塔旋转速度
[Export] public float ExRotationSpeed = 3.0f;
// 导出属性:检测范围
[Export] public float ExDetectionRange = 300.0f;
// 内部变量:当前目标
private Node2D _target = null;
public override void _PhysicsProcess(double delta)
{
if (_target != null && IsInstanceValid(_target))
{
// 计算目标方向的角度
Vector2 direction = _target.GlobalPosition - GlobalPosition;
float targetAngle = Mathf.Atan2(direction.Y, direction.X);
// 使用 lerp_angle 平滑转向目标(自动处理 360 度环绕)
Rotation = Mathf.LerpAngle(Rotation, targetAngle, ExRotationSpeed * (float)delta);
}
}
// 当目标进入检测范围时调用
public void OnTargetDetected(Node2D target)
{
float distance = GlobalPosition.DistanceTo(target.GlobalPosition);
if (distance <= ExDetectionRange)
{
_target = target;
GD.Print("发现目标!");
}
}
}extends Node2D
# 导出属性:炮塔旋转速度
@export var rotation_speed: float = 3.0
# 导出属性:检测范围
@export var detection_range: float = 300.0
# 内部变量:当前目标
var _target: Node2D = null
func _physics_process(delta):
if _target != null and is_instance_valid(_target):
# 计算目标方向的角度
var direction = _target.global_position - global_position
var target_angle = atan2(direction.y, direction.x)
# 使用 lerp_angle 平滑转向目标(自动处理 360 度环绕)
rotation = lerp_angle(rotation, target_angle, rotation_speed * delta)
# 当目标进入检测范围时调用
func on_target_detected(target: Node2D):
var distance = global_position.distance_to(target.global_position)
if distance <= detection_range:
_target = target
print("发现目标!")注意事项
角度使用弧度制:Godot 中所有角度函数统一使用弧度制,不是角度制。PI 弧度 = 180 度。如果你习惯角度制,用
Mathf.DegToRad()/deg_to_rad()转换输入,用Mathf.RadToDeg()/rad_to_deg()转换输出。自动选择最短路径:
lerp_angle()内部会计算两个方向哪个更近,然后沿短的那边插值。你不需要手动判断该顺时针还是逆时针转。与
lerp()的区别:lerp()直接在数值之间走直线,不知道"角度"的概念。当角度跨越 0 度/360 度边界时,lerp()会走远路。只有lerp_angle()能正确处理这种情况。weight可以超过 0~1:和lerp()一样,weight超过 1.0 会导致角度"越过"目标继续转,weight为负值则反向转。大多数情况下你会在 0~1 范围内使用。与
lerp_angle()配合使用的常见写法:lerp_angle(current, target, speed * delta)是游戏开发中最常见的平滑转向写法。speed * delta保证了转向速度与帧率无关。
