remap
最后同步日期:2026-04-15 | Godot 官方原文 — remap
remap
定义
remap() 的作用是把一个值从一个范围"搬"到另一个范围。它在第一个范围里的相对位置不变,只是换了一套"刻度尺"。
打个比方:考试得了 85 分(满分 100 分),你想知道这个成绩折算成 GPA(0~4 分制)是多少。remap(85, 0, 100, 0, 4) 就帮你算了——85 分相当于 100 分制的 85%,所以映射到 0~4 分制就是 3.4。相对位置一样,只是数字换了。
再比如:游戏手柄的摇杆推到一半,返回值是 0.5(范围 0~1)。你想让角色的速度在 100~500 之间变化。remap(0.5, 0, 1, 100, 500) 返回 300——摇杆推一半,速度也是"一半"。
内部原理:remap 其实就是先用 inverse_lerp 算出值在第一个范围的位置百分比,再用 lerp 把这个百分比映射到第二个范围。一步到位。
函数签名
public static float Remap(float value, float istart, float istop, float ostart, float ostop)func remap(value: float, istart: float, istop: float, ostart: float, ostop: float) -> float参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
value | float | 是 | 你想转换的那个值 |
istart | float | 是 | 输入范围的起始值(原始范围的最小值) |
istop | float | 是 | 输入范围的结束值(原始范围的最大值) |
ostart | float | 是 | 输出范围的起始值(目标范围的最小值) |
ostop | float | 是 | 输出范围的结束值(目标范围的最大值) |
返回值
float -- 返回 value 从输入范围(istart`istop`)映射到输出范围(`ostart`ostop)后的值。
- 当
value == istart时返回ostart - 当
value == istop时返回ostop - 当
value在中间时,按相同比例映射到输出范围 - 当
value超出输入范围时,结果也会超出输出范围
代码示例
基础用法:范围转换
using Godot;
public partial class RemapExample : Node
{
public override void _Ready()
{
// 把 85 分(0~100 分制)映射到 GPA(0~4 分制)
float gpa = Mathf.Remap(85f, 0f, 100f, 0f, 4f);
GD.Print(gpa); // 运行结果: 3.4
// 把 50%(0~1)映射到速度范围(100~500)
float speed = Mathf.Remap(0.5f, 0f, 1f, 100f, 500f);
GD.Print(speed); // 运行结果: 300
// 把 0 度(-180~180)映射到 0~255(用于颜色通道)
float color = Mathf.Remap(0f, -180f, 180f, 0f, 255f);
GD.Print(color); // 运行结果: 127.5
// 把 30 度角映射到 0~1 的百分比
float percent = Mathf.Remap(30f, 0f, 90f, 0f, 1f);
GD.Print(percent); // 运行结果: 0.333...
}
}func _ready():
# 把 85 分(0~100 分制)映射到 GPA(0~4 分制)
var gpa = remap(85.0, 0.0, 100.0, 0.0, 4.0)
print(gpa) # 运行结果: 3.4
# 把 50%(0~1)映射到速度范围(100~500)
var speed = remap(0.5, 0.0, 1.0, 100.0, 500.0)
print(speed) # 运行结果: 300.0
# 把 0 度(-180~180)映射到 0~255(用于颜色通道)
var color = remap(0.0, -180.0, 180.0, 0.0, 255.0)
print(color) # 运行结果: 127.5
# 把 30 度角映射到 0~1 的百分比
var percent = remap(30.0, 0.0, 90.0, 0.0, 1.0)
print(percent) # 运行结果: 0.333...实际场景:手柄摇杆控制角色速度
using Godot;
public partial class JoystickMover : CharacterBody3D
{
// 导出属性:最小速度
[Export] public float ExMinSpeed = 50.0f;
// 导出属性:最大速度
[Export] public float ExMaxSpeed = 300.0f;
public override void _PhysicsProcess(double delta)
{
// 获取手柄摇杆输入(范围 -1.0 到 1.0)
float inputX = Input.GetJoyAxis(0, JoyAxis.LeftX);
float inputY = Input.GetJoyAxis(0, JoyAxis.LeftY);
// 取摇杆的推力大小(0 到 1)
float magnitude = new Vector2(inputX, inputY).Length();
// 把摇杆推力(0~1)映射到速度范围(最小~最大)
float speed = Mathf.Remap(magnitude, 0f, 1f, ExMinSpeed, ExMaxSpeed);
// 计算移动方向并应用速度
Vector2 inputDir = new Vector2(inputX, inputY).Normalized();
Vector3 direction = new Vector3(inputDir.X, 0f, inputDir.Y);
Velocity = direction * speed;
MoveAndSlide();
GD.Print($"摇杆推力: {magnitude:F2}, 速度: {speed:F0}");
// 运行结果示例: 摇杆推力: 0.70, 速度: 225
}
}extends CharacterBody3D
# 导出属性:最小速度
@export var min_speed: float = 50.0
# 导出属性:最大速度
@export var max_speed: float = 300.0
func _physics_process(delta):
# 获取手柄摇杆输入(范围 -1.0 到 1.0)
var input_x = Input.get_joy_axis(0, JOY_AXIS_LEFT_X)
var input_y = Input.get_joy_axis(0, JOY_AXIS_LEFT_Y)
# 取摇杆的推力大小(0 到 1)
var magnitude = Vector2(input_x, input_y).length()
# 把摇杆推力(0~1)映射到速度范围(最小~最大)
var speed = remap(magnitude, 0.0, 1.0, min_speed, max_speed)
# 计算移动方向并应用速度
var input_dir = Vector2(input_x, input_y).normalized()
var direction = Vector3(input_dir.x, 0.0, input_dir.y)
velocity = direction * speed
move_and_slide()
print("摇杆推力: %.2f, 速度: %.0f" % [magnitude, speed])
# 运行结果示例: 摇杆推力: 0.70, 速度: 225进阶用法:距离影响光照强度
using Godot;
public partial class ProximityLight : OmniLight3D
{
// 导出属性:最近感应距离
[Export] public float ExMinDistance = 1.0f;
// 导出属性:最远感应距离
[Export] public float ExMaxDistance = 10.0f;
// 导出属性:最小光照能量
[Export] public float ExMinEnergy = 0.2f;
// 导出属性:最大光照能量
[Export] public float ExMaxEnergy = 5.0f;
// 内部变量:追踪目标
private Node3D _target = null;
public override void _Process(double delta)
{
if (_target == null) return;
// 计算到目标的距离
float distance = GlobalPosition.DistanceTo(_target.GlobalPosition);
// 把距离映射到光照能量:
// 距离越近(接近 ExMinDistance)-> 能量越大(接近 ExMaxEnergy)
// 距离越远(接近 ExMaxDistance)-> 能量越小(接近 ExMinEnergy)
// 注意:这里把输出范围反过来写了,实现"越近越亮"的效果
float energy = Mathf.Remap(distance, ExMinDistance, ExMaxDistance, ExMaxEnergy, ExMinEnergy);
// 限制在合理范围
LightEnergy = Mathf.Clamp(energy, ExMinEnergy, ExMaxEnergy);
GD.Print($"距离: {distance:F1}, 光照: {LightEnergy:F1}");
// 运行结果示例: 距离: 3.0, 光照: 3.8
}
}extends OmniLight3D
# 导出属性:最近感应距离
@export var min_distance: float = 1.0
# 导出属性:最远感应距离
@export var max_distance: float = 10.0
# 导出属性:最小光照能量
@export var min_energy: float = 0.2
# 导出属性:最大光照能量
@export var max_energy: float = 5.0
# 内部变量:追踪目标
var _target: Node3D = null
func _process(delta):
if _target == null:
return
# 计算到目标的距离
var distance = global_position.distance_to(_target.global_position)
# 把距离映射到光照能量:
# 距离越近(接近 min_distance)-> 能量越大(接近 max_energy)
# 距离越远(接近 max_distance)-> 能量越小(接近 min_energy)
# 注意:这里把输出范围反过来写了,实现"越近越亮"的效果
var energy = remap(distance, min_distance, max_distance, max_energy, min_energy)
# 限制在合理范围
light_energy = clampf(energy, min_energy, max_energy)
print("距离: %.1f, 光照: %.1f" % [distance, light_energy])
# 运行结果示例: 距离: 3.0, 光照: 3.8注意事项
输出范围可以反转:你可以让
ostart大于ostop,实现"反向映射"。比如remap(0.5, 0, 1, 100, 0)返回 50,输入越大输出越小。这在游戏开发中很常见——比如距离越近声音越大。超出范围的值不会被 clamp:如果
value超出了istart~istop的范围,结果也会超出ostart~ostop的范围。如果你需要结果严格限制在输出范围内,请在外层套用Mathf.Clamp()/clampf()。当
istart等于istop时会除零:和inverse_lerp一样,输入范围的起始值和结束值不能相同,否则会除零导致异常结果。等价于
inverse_lerp+lerp:remap(value, a, b, c, d)等价于lerp(c, d, inverse_lerp(a, b, value))。remap只是把这两步合在一起,写起来更简洁。不会自动 clamp:如果你希望输出值被限制在目标范围内,需要手动使用
clampf()。
