acos
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — acos
acos
定义
acos() 是反余弦函数(arc cosine)——它是 cos() 的"反过来的操作"。
如果 cos() 是问"给我一个角度,告诉我它在圆上的水平位置",那 acos() 就是反过来问"我知道圆上的水平位置了,你告诉我对应的角度是多少"。
打个比方:cos() 就像你告诉朋友"从正东方逆时针转 60 度,你走到了什么位置",朋友说"我到了水平偏左 0.5 的位置"。acos() 则是你问朋友"我在水平偏左 0.5 的位置,你能猜出我转了多少度吗"——从水平位置反推出角度。
重要限制:因为 cos() 的输出范围是 -1 到 1,所以 acos() 的输入也只能是 -1 到 1 之间的数。
角度单位是弧度,不是度数
acos() 返回的结果是弧度,不是度数。如果需要度数,用 rad_to_deg() 转换。
函数签名
C#
// 使用 Godot 的 Mathf(推荐,返回 float)
public static float Acos(float s)GDScript
func acos(s: float) -> float参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
s | float | 是 | 余弦值,必须在 -1.0 到 1.0 之间(含端点)。超出此范围会返回 NaN |
返回值
类型: float
返回一个弧度值,范围在 0 到 PI 之间(即 0 度到 180 度)。
| 输入 | 输出(弧度) | 输出(约等于度数) | 说明 |
|---|---|---|---|
| 1.0 | 0.0 | 0 度 | cos(0) = 1 的逆运算 |
| 0.0 | PI/2 | 90 度 | cos(90度) = 0 的逆运算 |
| -1.0 | PI | 180 度 | cos(180度) = -1 的逆运算 |
| 0.5 | PI/3 | 60 度 | cos(60度) = 0.5 的逆运算 |
代码示例
基础用法:从余弦值反推角度
C#
using Godot;
public partial class AcosExample : Node
{
public override void _Ready()
{
// 已知余弦值,反推角度
float a1 = Mathf.Acos(1f);
GD.Print("acos(1) = " + a1 + " 弧度 = " + Mathf.RadToDeg(a1) + " 度");
// 运行结果: acos(1) = 0 弧度 = 0 度
float a2 = Mathf.Acos(0f);
GD.Print("acos(0) = " + a2 + " 弧度 = " + Mathf.RadToDeg(a2) + " 度");
// 运行结果: acos(0) = 1.5707964 弧度 = 90 度
float a3 = Mathf.Acos(-1f);
GD.Print("acos(-1) = " + a3 + " 弧度 = " + Mathf.RadToDeg(a3) + " 度");
// 运行结果: acos(-1) = 3.1415927 弧度 = 180 度
float a4 = Mathf.Acos(0.5f);
GD.Print("acos(0.5) = " + a4 + " 弧度 = " + Mathf.RadToDeg(a4) + " 度");
// 运行结果: acos(0.5) = 1.0471976 弧度 = 60 度
}
}GDScript
extends Node
func _ready():
# 已知余弦值,反推角度
var a1 = acos(1.0)
print("acos(1) = ", a1, " 弧度 = ", rad_to_deg(a1), " 度")
# 运行结果: acos(1) = 0 弧度 = 0 度
var a2 = acos(0.0)
print("acos(0) = ", a2, " 弧度 = ", rad_to_deg(a2), " 度")
# 运行结果: acos(0) = 1.5707964 弧度 = 90 度
var a3 = acos(-1.0)
print("acos(-1) = ", a3, " 弧度 = ", rad_to_deg(a3), " 度")
# 运行结果: acos(-1) = 3.1415927 弧度 = 180 度
var a4 = acos(0.5)
print("acos(0.5) = ", a4, " 弧度 = ", rad_to_deg(a4), " 度")
# 运行结果: acos(0.5) = 1.0471976 弧度 = 60 度实际场景:计算两个方向向量之间的夹角
C#
using Godot;
public partial class AngleBetweenVectors : Node
{
public override void _Ready()
{
// 两个方向向量
Vector2 dirA = new Vector2(1f, 0f); // 朝右
Vector2 dirB = new Vector2(0.5f, 0.866f); // 朝右上约 60 度
// 归一化(如果向量还没归一化的话)
dirA = dirA.Normalized();
dirB = dirB.Normalized();
// 点乘结果 = cos(夹角)
float dot = dirA.Dot(dirB);
// 用 acos 从点乘值反推出角度
float angleRad = Mathf.Acos(dot);
GD.Print($"方向A: {dirA}, 方向B: {dirB}");
GD.Print($"点乘: {dot:F4}, 夹角: {Mathf.RadToDeg(angleRad):F1} 度");
// 运行结果: 方向A: (1, 0), 方向B: (0.5, 0.866)
// 运行结果: 点乘: 0.5000, 夹角: 60.0 度
}
}GDScript
extends Node
func _ready():
# 两个方向向量
var dir_a := Vector2(1.0, 0.0) # 朝右
var dir_b := Vector2(0.5, 0.866) # 朝右上约 60 度
# 归一化(如果向量还没归一化的话)
dir_a = dir_a.normalized()
dir_b = dir_b.normalized()
# 点乘结果 = cos(夹角)
var dot := dir_a.dot(dir_b)
# 用 acos 从点乘值反推出角度
var angle_rad := acos(dot)
print("方向A: %s, 方向B: %s" % [dir_a, dir_b])
print("点乘: %.4f, 夹角: %.1f 度" % [dot, rad_to_deg(angle_rad)])
# 运行结果: 方向A: (1, 0), 方向B: (0.5, 0.866)
# 运行结果: 点乘: 0.5000, 夹角: 60.0 度进阶用法:用 acos 判断敌人是否在视野锥内
C#
using Godot;
public partial class EnemyVision : Node2D
{
// 导出属性:视野半角(度)
[Export] public float ExFieldOfView = 45f;
// 导出属性:视线距离
[Export] public float ExSightRange = 200f;
public bool IsTargetInSight(Vector2 targetPos)
{
Vector2 toTarget = targetPos - GlobalPosition;
float distance = toTarget.Length();
// 超出视线距离
if (distance > ExSightRange) return false;
// 归一化后计算与正前方的夹角
Vector2 forward = new Vector2(1f, 0f).Rotated(Rotation);
Vector2 dirToTarget = toTarget.Normalized();
float dot = forward.Dot(dirToTarget);
// 点乘值可能因浮点误差略微超出 [-1, 1],需要限制
dot = Mathf.Clamp(dot, -1f, 1f);
float angle = Mathf.Acos(dot);
float halfFov = Mathf.DegToRad(ExFieldOfView);
GD.Print($"目标角度: {Mathf.RadToDeg(angle):F1} 度, 视野半角: {ExFieldOfView} 度");
// 运行结果: 目标角度: 30.0 度, 视野半角: 45 度(在视野内)
return angle <= halfFov;
}
}GDScript
extends Node2D
## 导出属性:视野半角(度)
@export var ex_field_of_view: float = 45.0
## 导出属性:视线距离
@export var ex_sight_range: float = 200.0
func is_target_in_sight(target_pos: Vector2) -> bool:
var to_target := target_pos - global_position
var distance := to_target.length()
# 超出视线距离
if distance > ex_sight_range:
return false
# 归一化后计算与正前方的夹角
var forward := Vector2(1.0, 0.0).rotated(rotation)
var dir_to_target := to_target.normalized()
var dot := forward.dot(dir_to_target)
# 点乘值可能因浮点误差略微超出 [-1, 1],需要限制
dot = clampf(dot, -1.0, 1.0)
var angle := acos(dot)
var half_fov := deg_to_rad(ex_field_of_view)
print("目标角度: %.1f 度, 视野半角: %d 度" % [rad_to_deg(angle), ex_field_of_view])
# 运行结果: 目标角度: 30.0 度, 视野半角: 45 度(在视野内)
return angle <= half_fov注意事项
- 输入范围严格限制:
acos()只接受 -1 到 1 之间的值。传入 1.5 或 -2 会返回NaN。做点乘运算后,建议用Mathf.Clamp()限制一下范围,因为浮点误差可能导致结果略微超出。 - 输出范围是 0 到 PI:
acos()只返回 0 到 180 度之间的角度。它不区分"左边 30 度"和"右边 30 度"——两者都会返回 30 度。如果需要区分方向,应该用atan2()。 - 返回的是弧度:结果需要用
rad_to_deg()转换才能得到度数。 - 计算两向量夹角的利器:
acos(dot(A, B))是计算两个归一化向量之间夹角的标准方法,在游戏中非常常用。 - C# 中的选择:推荐使用
Mathf.Acos()(返回float),而不是Math.Acos()(返回double)。
