本文章给大家分享一下如何实现基本的移动和进阶的跳跃(跳跃缓冲、可变跳跃、土狼时间)以及相对应的重力代码,大家可以根据自己的需要自行修改
实现效果

场景搭建

因为Godot不像Unity,一个节点只能绑定一个脚本,所以我们可以创建一个节点,用来存放绑定各种脚本,这样能大大规范化我们的代码,毕竟一个脚本写几千行代码相信大家也不想经历(本人曾经深受其害)
有一点,玩家的碰撞体最好用胶囊或者其他的边角圆润的形状,否则我们直接绑的一个方块,会导致跳跃到平台边缘根本上不去
其中的RayCast2D节点是我用来判断玩家顶头的,大家可以根据需要调整,下面我给大家分享一下代码
代码
Player
cs
using Godot;
using System;
public partial class Player : CharacterBody2D
{
[ExportCategory("Item")]
[Export] public float _moveSpeed; // 玩家移动速度
[Export] public float _jumpForce; // 跳跃初始力度(用于起跳)
[Export] public float _jumpCumulative; // 可变跳跃额外加速度(持续跳跃时叠加)
[Export] public float _downSpeed; // 快速下落的速度(按下下落键时使用)
[Export] public float _gravity; // 重力加速度(用于下落)
[ExportGroup("Time")]
[Export] public float _jumpBufferTime; // 跳跃缓冲时间(提前按跳跃键后多长时间内仍有效)
[Export] public float _jumpCumulativeTime; // 跳跃蓄力时间(可变跳跃持续多久)
[Export] public float _jumpDeadZoneTime; // 跳跃死区时间(短时间内跳跃输入无效)
[Export] public float _coyoteTime; // 土狼时间(离地后多久内仍可跳跃)
[ExportGroup("Node")]
[Export] public RayCast2D RayHead; // 检测头顶碰撞的射线(用于防止跳跃时顶头)
public override void _PhysicsProcess(double delta)
{
MoveAndSlide(); // 移动函数(实际处理碰撞和滑动)
}
}
PlayerMove
cs
using Godot;
using System;
public partial class PlayerMove : Node2D
{
private Player player; // 引用 Player 脚本,用于访问属性和控制玩家
public override void _Ready()
{
// 获取 Player 脚本(父节点 -> 父节点 -> Player)
player = GetParent().GetParent<Player>();
}
public override void _PhysicsProcess(double delta)
{
Move(); // 每帧执行移动逻辑
}
private void Move()
{
float directionX = 0f; // 水平方向,右为 +1,左为 -1
if (Input.IsActionPressed("Right"))
{
directionX += 1f;
}
if (Input.IsActionPressed("Left"))
{
directionX -= 1f;
}
// 设置玩家水平速度,垂直方向保持不变
player.Velocity = new Vector2(directionX * player._moveSpeed, player.Velocity.Y);
}
}
PlayerJump
cs
using Godot;
using System;
public partial class PlayerJump : Node2D
{
private Player player;
// 跳跃数值参数
private float _jumpForce; // 跳跃初始力度
private float _jumpCumulative; // 可变跳跃额外力度
private float _downSpeed; // 下坠加速度
private float _gravity; // 重力值
// 时间控制参数
private float _jumpBufferTime; // 跳跃缓冲持续时间
private float _jumpCumulativeTime; // 可变跳跃持续时间
private float _jumpDeadZoneTime; // 按键死区(防止短按立刻进入长跳)
private float _coyoteTime; // 土狼时间(离地后仍可跳的时间)
// 跳跃状态计时器
private float _jumpBufferTimer; // 当前跳跃缓冲计时
private float _jumpCumulativeTimer; // 当前可变跳跃剩余时间
private float _jumpHoldZoneTimer; // 按住跳跃键的持续时间
public float _coyoteTimer; // 当前土狼时间计时器
private float _jumpCumulativeForce; // 当前可变跳跃施加的力度
private float _downTempSpeed; // 临时下坠速度(用于中断跳跃)
private bool _isJumping; // 是否处于跳跃状态(长跳过程)
public override void _Ready()
{
// 获取参数引用
player = GetParent().GetParent<Player>();
_jumpForce = player._jumpForce;
_gravity = player._gravity;
_jumpCumulative = player._jumpCumulative;
_downSpeed = player._downSpeed;
_jumpBufferTime = player._jumpBufferTime;
_jumpCumulativeTime = player._jumpCumulativeTime;
_jumpDeadZoneTime = player._jumpDeadZoneTime;
_coyoteTime = player._coyoteTime;
}
public override void _PhysicsProcess(double delta)
{
Jump((float)delta);
PlayerGravity((float)delta);
}
private void Jump(float delta)
{
// 跳跃缓冲:按下跳跃键时记录缓冲时间
if (Input.IsActionJustPressed("Jump"))
{
_jumpBufferTimer = _jumpBufferTime;
}
else
{
_jumpBufferTimer -= delta;
}
// 死区检测:跳跃中按住跳跃键时间
if (Input.IsActionPressed("Jump") && _isJumping)
{
_jumpHoldZoneTimer += delta;
}
else
{
_jumpHoldZoneTimer = 0f;
}
// 可变跳跃高度控制(长按跳得更高)
if (Input.IsActionPressed("Jump") && _isJumping && _jumpCumulativeTimer > 0f && _jumpHoldZoneTimer > _jumpDeadZoneTime)
{
player.Velocity = new Vector2(player.Velocity.X, player.Velocity.Y - _jumpCumulativeForce * delta);
_jumpCumulativeTimer -= delta;
}
// 提前松开跳跃键:终止可变跳跃
else if (Input.IsActionJustReleased("Jump"))
{
_jumpCumulativeForce = 0f;
_isJumping = false;
}
// 满足缓冲与土狼时间,可以跳跃
if (_jumpBufferTimer > 0f && _coyoteTimer > 0f)
{
player.Velocity = new Vector2(player.Velocity.X, player.Velocity.Y - _jumpForce);
_jumpBufferTimer = 0f;
_jumpCumulativeTimer = _jumpCumulativeTime;
_jumpCumulativeForce = _jumpCumulative;
_isJumping = true;
}
// 玩家在地面或攀爬中,重置跳跃状态
if ((player.IsOnFloor() || player._isClimbing) && MathF.Abs(player.Velocity.Y) < 0.1f)
{
_jumpCumulativeTimer = 0f;
_downTempSpeed = 0f;
_coyoteTimer = _coyoteTime;
_isJumping = false;
}
else
{
_coyoteTimer -= delta;
}
// 限制最大跳跃速度(防止过快)
if (player.Velocity.Y < -_jumpForce)
{
player.Velocity = new Vector2(player.Velocity.X, -_jumpForce);
}
// 顶头检测,取消跳跃力
if (player.RayHead.IsColliding())
{
_jumpCumulativeTimer = 0f;
_jumpCumulativeForce = 0f;
player.Velocity = new Vector2(player.Velocity.X, _gravity / 4);
}
}
private void PlayerGravity(float delta)
{
// 空中才加重力
if (player.IsOnFloor()) return;
player.Velocity = new Vector2(player.Velocity.X, player.Velocity.Y + _gravity * delta);
}
}
总结
给大家的代码还算比较完整,我实践测试感觉手感还是不对,大家根据自己的需要进行修改优化吧