[Godot] C#2D平台游戏基础移动和进阶跳跃代码

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

实现效果


场景搭建

因为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);
    }
}

总结

给大家的代码还算比较完整,我实践测试感觉手感还是不对,大家根据自己的需要进行修改优化吧

相关推荐
微祎_14 小时前
Flutter for OpenHarmony:构建一个 Flutter 镜像绘图游戏,对称性认知、空间推理与生成式交互设计
flutter·游戏·交互
前端不太难16 小时前
HarmonyOS 游戏项目,从 Demo 到可上线要跨过哪些坑
游戏·状态模式·harmonyos
子春一16 小时前
Flutter for OpenHarmony:色彩捕手:基于 CIELAB 色差模型与人眼感知的高保真色彩匹配游戏架构解析
flutter·游戏·架构
前端不太难20 小时前
在 HarmonyOS 上,游戏状态该怎么“死而复生”
游戏·状态模式·harmonyos
ujainu1 天前
Flutter + OpenHarmony 游戏开发进阶:用户输入响应——GestureDetector 实现点击发射
flutter·游戏·openharmony
ujainu1 天前
Flutter + OpenHarmony 实现无限跑酷游戏开发实战—— 对象池化、性能优化与流畅控制
flutter·游戏·性能优化·openharmony·endless runner
小李也疯狂1 天前
Unity 中的立方体贴图(Cubemaps)
unity·游戏引擎·贴图·cubemap
呆呆敲代码的小Y1 天前
【Unity工具篇】| 超实用工具LuBan,快速上手使用
游戏·unity·游戏引擎·unity插件·luban·免费游戏·游戏配置表
EQ-雪梨蛋花汤1 天前
【Unity优化】Unity多场景加载优化与资源释放完整指南:解决Additive加载卡顿、预热、卸载与内存释放问题
unity·游戏引擎
我的offer在哪里1 天前
用 Unity 从 0 做一个「可以玩的」游戏,需要哪些步骤和流程
游戏·unity·游戏引擎