Input.is_action_just_released
2026/4/14大约 6 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — Input.is_action_just_released
Input.is_action_just_released
定义
想象你在用弹弓——你一直往后拉橡皮筋,当你松手的那一瞬间,石头才会飞出去。is_action_just_released 就是用来检测"玩家刚刚松开按键的那一刻"的。
和 is_action_just_pressed 是一对好兄弟:just_pressed 检测"按下的瞬间",just_released 检测"松开的瞬间"。两者都只在对应的那一帧返回 true。
一句话总结
is_action_just_released = "你刚刚松开按键了吗?"——只在松开那一帧返回 true,常用于蓄力释放、停止射击等操作。
函数签名
C#
public static bool IsActionJustReleased(StringName action, bool exactMatch = false)GDScript
is_action_just_released(action: StringName, exact_match: bool = false) -> bool参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| action | StringName | 是 | 动作名称,在项目设置(Project Settings -> Input Map)中定义。比如 "shoot"、"charge" |
| exactMatch | bool | 否 | 是否精确匹配。默认 false;设为 true 时只匹配完全相同的输入设备 |
返回值
bool — 如果指定的动作在当前帧刚刚被松开,返回 true;否则返回 false。
代码示例
基础用法
最简单的用法——检测玩家何时松开了按键:
C#
using Godot;
public partial class TestInput : Node
{
public override void _Process(double delta)
{
// 检测玩家是否刚刚松开了 "jump" 键
if (Input.IsActionJustReleased("jump"))
{
GD.Print("玩家松开了跳跃键!");
}
// 运行结果: (按住空格然后松开的那一帧)打印 "玩家松开了跳跃键!"
// (按住不放时)不打印
// (没有按过就不管)不打印
}
}GDScript
extends Node
func _process(delta: float) -> void:
# 检测玩家是否刚刚松开了 "jump" 键
if Input.is_action_just_released("jump"):
print("玩家松开了跳跃键!")
# 运行结果: (按住空格然后松开的那一帧)打印 "玩家松开了跳跃键!"
# (按住不放时)不打印
# (没有按过就不管)不打印实际场景
实现一个"蓄力跳跃"机制——按住跳跃键蓄力,松开后根据蓄力时间决定跳跃高度:
C#
using Godot;
public partial class ChargeJumpPlayer : CharacterBody2D
{
[Export] public float ExMinJumpForce = -200f;
[Export] public float ExMaxJumpForce = -600f;
[Export] public float ExMaxChargeTime = 1.0f; // 最长蓄力1秒
private float _chargeTime = 0f;
private bool _isCharging = false;
private float _gravity = 980f;
public override void _PhysicsProcess(double delta)
{
Vector2 velocity = Velocity;
// 重力
if (!IsOnFloor())
{
velocity.Y += _gravity * (float)delta;
}
// 按住跳跃键时开始蓄力
if (Input.IsActionPressed("jump") && IsOnFloor())
{
_isCharging = true;
_chargeTime += (float)delta;
_chargeTime = Mathf.Min(_chargeTime, ExMaxChargeTime);
// 显示蓄力进度
float chargePercent = _chargeTime / ExMaxChargeTime * 100f;
GD.Print($"蓄力中... {chargePercent:F0}%");
// 运行结果: 蓄力中... 25%
// 蓄力中... 50%
// 蓄力中... 100%(蓄满)
}
// 松开跳跃键时执行跳跃
if (Input.IsActionJustReleased("jump") && _isCharging)
{
float chargeRatio = _chargeTime / ExMaxChargeTime;
float jumpForce = Mathf.Lerp(ExMinJumpForce, ExMaxJumpForce, chargeRatio);
velocity.Y = jumpForce;
GD.Print($"释放!蓄力 {_chargeTime:F2}s, 跳跃力度 {jumpForce:F0}");
// 运行结果: 释放!蓄力 0.50s, 跳跃力度 -400
// 释放!蓄力 1.00s, 跳跃力度 -600(满蓄力)
_isCharging = false;
_chargeTime = 0f;
}
Velocity = velocity;
MoveAndSlide();
}
}GDScript
extends CharacterBody2D
@export var ex_min_jump_force: float = -200.0
@export var ex_max_jump_force: float = -600.0
@export var ex_max_charge_time: float = 1.0 # 最长蓄力1秒
var _charge_time: float = 0.0
var _is_charging: bool = false
var _gravity: float = 980.0
func _physics_process(delta: float) -> void:
var velocity := velocity
# 重力
if not is_on_floor():
velocity.y += _gravity * delta
# 按住跳跃键时开始蓄力
if Input.is_action_pressed("jump") and is_on_floor():
_is_charging = true
_charge_time += delta
_charge_time = minf(_charge_time, ex_max_charge_time)
# 显示蓄力进度
var charge_percent := _charge_time / ex_max_charge_time * 100.0
print("蓄力中... %d%%" % charge_percent)
# 运行结果: 蓄力中... 25%
# 蓄力中... 50%
# 蓄力中... 100%(蓄满)
# 松开跳跃键时执行跳跃
if Input.is_action_just_released("jump") and _is_charging:
var charge_ratio := _charge_time / ex_max_charge_time
var jump_force := lerpf(ex_min_jump_force, ex_max_jump_force, charge_ratio)
velocity.y = jump_force
print("释放!蓄力 %.2fs, 跳跃力度 %d" % [_charge_time, jump_force])
# 运行结果: 释放!蓄力 0.50s, 跳跃力度 -400
# 释放!蓄力 1.00s, 跳跃力度 -600(满蓄力)
_is_charging = false
_charge_time = 0.0
self.velocity = velocity
move_and_slide()进阶用法
实现一个完整的蓄力攻击系统——按住攻击键蓄力,松开时释放技能,同时处理中断和蓄力上限:
C#
using Godot;
public partial class CombatPlayer : CharacterBody2D
{
public enum EnumAttackType { Normal, Heavy, Special }
[Export] public float ExMoveSpeed = 300f;
[Export] public float ExMaxChargeTime = 2.0f;
[Export] public float ExNormalDamage = 10f;
[Export] public float ExHeavyDamage = 30f;
[Export] public float ExSpecialDamage = 80f;
private float _chargeTime = 0f;
private bool _isCharging = false;
private bool _chargeInterrupted = false;
private ProgressBar _chargeBar;
private Label _statusLabel;
public override void _Ready()
{
_chargeBar = GetNode<ProgressBar>("HUD/ChargeBar");
_statusLabel = GetNode<Label>("HUD/StatusLabel");
_chargeBar.Visible = false;
}
public override void _PhysicsProcess(double delta)
{
// 按住攻击键蓄力
if (Input.IsActionPressed("attack") && !_chargeInterrupted)
{
if (!_isCharging)
{
_isCharging = true;
_chargeBar.Visible = true;
}
_chargeTime += (float)delta;
_chargeTime = Mathf.Min(_chargeTime, ExMaxChargeTime);
// 更新蓄力条
_chargeBar.Value = (_chargeTime / ExMaxChargeTime) * 100f;
}
// 松开攻击键时释放
if (Input.IsActionJustReleased("attack"))
{
if (_isCharging && !_chargeInterrupted)
{
EnumAttackType attackType;
float damage;
if (_chargeTime < 0.5f)
{
attackType = EnumAttackType.Normal;
damage = ExNormalDamage;
}
else if (_chargeTime < 1.5f)
{
attackType = EnumAttackType.Heavy;
damage = ExHeavyDamage;
}
else
{
attackType = EnumAttackType.Special;
damage = ExSpecialDamage;
}
GD.Print($"释放 {attackType} 攻击!伤害: {damage}, 蓄力: {_chargeTime:F2}s");
// 运行结果: 释放 Normal 攻击!伤害: 10, 蓄力: 0.20s
// 释放 Heavy 攻击!伤害: 30, 蓄力: 1.00s
// 释放 Special 攻击!伤害: 80, 蓄力: 2.00s
}
// 重置蓄力状态
_isCharging = false;
_chargeTime = 0f;
_chargeInterrupted = false;
_chargeBar.Visible = false;
}
// 受伤时中断蓄力
// _chargeInterrupted = true; (在实际的受伤处理方法中设置)
}
}GDScript
extends CharacterBody2D
enum EnumAttackType { NORMAL, HEAVY, SPECIAL }
@export var ex_move_speed: float = 300.0
@export var ex_max_charge_time: float = 2.0
@export var ex_normal_damage: float = 10.0
@export var ex_heavy_damage: float = 30.0
@export var ex_special_damage: float = 80.0
var _charge_time: float = 0.0
var _is_charging: bool = false
var _charge_interrupted: bool = false
var _charge_bar: ProgressBar
var _status_label: Label
func _ready() -> void:
_charge_bar = get_node("HUD/ChargeBar")
_status_label = get_node("HUD/StatusLabel")
_charge_bar.visible = false
func _physics_process(delta: float) -> void:
# 按住攻击键蓄力
if Input.is_action_pressed("attack") and not _charge_interrupted:
if not _is_charging:
_is_charging = true
_charge_bar.visible = true
_charge_time += delta
_charge_time = minf(_charge_time, ex_max_charge_time)
# 更新蓄力条
_charge_bar.value = (_charge_time / ex_max_charge_time) * 100.0
# 松开攻击键时释放
if Input.is_action_just_released("attack"):
if _is_charging and not _charge_interrupted:
var attack_type: EnumAttackType
var damage: float
if _charge_time < 0.5:
attack_type = EnumAttackType.NORMAL
damage = ex_normal_damage
elif _charge_time < 1.5:
attack_type = EnumAttackType.HEAVY
damage = ex_heavy_damage
else:
attack_type = EnumAttackType.SPECIAL
damage = ex_special_damage
print("释放 %s 攻击!伤害: %s, 蓄力: %.2fs" % [attack_type, damage, _charge_time])
# 运行结果: 释放 NORMAL 攻击!伤害: 10.0, 蓄力: 0.20s
# 释放 HEAVY 攻击!伤害: 30.0, 蓄力: 1.00s
# 释放 SPECIAL 攻击!伤害: 80.0, 蓄力: 2.00s
# 重置蓄力状态
_is_charging = false
_charge_time = 0.0
_charge_interrupted = false
_charge_bar.visible = false
# 受伤时中断蓄力
# _charge_interrupted = true (在实际的受伤处理方法中设置)注意事项
- 只在松开那一帧触发:
is_action_just_released只会在玩家刚刚松开按键的那一帧返回true,之后一直返回false。这和is_action_just_pressed的行为是对称的。 - 必须先按下再松开:如果玩家从来没有按下过对应的按键,
is_action_just_released永远不会返回true。这听起来很理所当然,但意味着你需要确保按键的按下和松开成对出现。 - 蓄力系统的最佳搭档:
is_action_just_released最典型的应用场景就是"蓄力释放"——用is_action_pressed来持续蓄力,用is_action_just_released来触发释放。这种组合可以做出弹弓、蓄力攻击、蓄力跳跃等多种游戏机制。 - 必须在 Input Map 中定义动作:和其他输入方法一样,需要先在 Godot 编辑器的 项目设置 -> Input Map 中定义对应的动作名称。
- C# 差异:C# 中方法名用 PascalCase(
Input.IsActionJustReleased),GDScript 中用 snake_case(Input.is_action_just_released)。
