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

news2025/5/11 13:31:19

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

实现效果


场景搭建

因为Godot不像Unity,一个节点只能绑定一个脚本,所以我们可以创建一个节点,用来存放绑定各种脚本,这样能大大规范化我们的代码,毕竟一个脚本写几千行代码相信大家也不想经历(本人曾经深受其害)

有一点,玩家的碰撞体最好用胶囊或者其他的边角圆润的形状,否则我们直接绑的一个方块,会导致跳跃到平台边缘根本上不去

其中的RayCast2D节点是我用来判断玩家顶头的,大家可以根据需要调整,下面我给大家分享一下代码


代码

Player

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

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

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

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2341269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Unity笔记】Unity + OpenXR项目无法启动SteamVR的排查与解决全指南

图片为AI生成 一、前言 随着Unity在XR领域全面转向OpenXR标准&#xff0c;越来越多的开发者选择使用OpenXR来构建跨平台的VR应用。但在项目实际部署中发现&#xff1a;打包成的EXE程序无法正常启动SteamVR&#xff0c;或者SteamVR未能识别到该应用。本文将以“Unity OpenXR …

使用 rebase 轻松管理主干分支

前言 最近遇到一个技术团队的 dev 环境分支错乱&#xff0c;因为是多人合作大家各自提交信息&#xff0c;导致出现很多交叉合并记录&#xff0c;让对应 log 看起来非常混乱&#xff0c;难以阅读。 举例说明 假设我们有一个项目&#xff0c;最初develop分支有 3 个提交记录&a…

【愚公系列】《Python网络爬虫从入门到精通》063-项目实战电商数据侦探(主窗体的数据展示)

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…

HttpSessionListener 的用法笔记250417

HttpSessionListener 的用法笔记250417 以下是关于 HttpSessionListener 的用法详解&#xff0c;涵盖核心方法、实现步骤、典型应用场景及注意事项&#xff0c;帮助您全面掌握会话&#xff08;Session&#xff09;生命周期的监听与管理&#xff1a; 1. 核心功能 HttpSessionLi…

火山RTC 5 转推CDN 布局合成规则

实时音视频房间&#xff0c;转推CDN&#xff0c;文档&#xff1a; 转推直播--实时音视频-火山引擎 一、转推CDN 0、前提 * 在调用该接口前&#xff0c;你需要在[控制台](https://console.volcengine.com/rtc/workplaceRTC)开启转推直播功能。<br> * 调…

Spark两种运行模式与部署

1. Spark 的运行模式 部署Spark集群就两种方式&#xff0c;单机模式与集群模式 单机模式就是为了方便开发者调试框架的运行环境。但是生产环境中&#xff0c;一般都是集群部署。 现在Spark目前支持的部署模式&#xff1a; &#xff08;1&#xff09;Local模式&#xff1a;在本地…

qt画一朵花

希望大家的生活都更加美好&#xff0c;画一朵花送给大家 效果图 void FloatingArrowPubshButton::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing);QPen pen;pen.setColor("green");pen.setWidth(5);QBrush…

服务器上安装maven

1.安装 下载安装包 https://maven.apache.org/download.cgi 解压安装包 cd /opt/software tar -xzvf apache-maven-3.9.9-bin.tar.gz 安装目录(/opt/maven/) mv /opt/software/apache-maven-3.9.9 /opt/ 3.权限设置 把/opt/software/apache-maven-3.9.9 文件夹重命名为ma…

UOS+N 卡 + CUDA 环境下 X86 架构 DeepSeek 基于 vLLM 部署与 Dify 平台搭建指南

一、文档说明 本文档是一份关于 DeepSeek 在X86架构下通vLLM工具部署的操作指南&#xff0c;主要面向需要在UOSN卡CUDA环境中部署DeepSeek的技术人员&#xff0c;旨在指导文档使用者完成从 Python 环境升级、vLLM 库安装、模型部署到 Dify 平台搭建的全流程操作。 二、安装Pyt…

MySQL终章(8)JDBC

目录 1.前言 2.正文 2.1JDBC概念 2.2三种编码方式 2.2.1第一种 2.2.2第二种&#xff08;优化版&#xff09; 2.2.3第三种&#xff08;更优化版&#xff09; 3.小结 1.前言 哈喽大家好吖&#xff0c;今天来给大家带来Java中的JDBC的讲解&#xff0c;之前学习的都是操作…

Python 爬虫如何伪装 Referer?从随机生成到动态匹配

一、Referer 的作用与重要性 Referer 是 HTTP 请求头中的一个字段&#xff0c;用于标识请求的来源页面。它在网站的正常运行中扮演着重要角色&#xff0c;例如用于统计流量来源、防止恶意链接等。然而&#xff0c;对于爬虫来说&#xff0c;Referer 也可能成为被识别为爬虫的关…

【MySQL】表的约束(主键、唯一键、外键等约束类型详解)、表的设计

目录 1.数据库约束 1.1 约束类型 1.2 null约束 — not null 1.3 unique — 唯一约束 1.4 default — 设置默认值 1.5 primary key — 主键约束 自增主键 自增主键的局限性&#xff1a;经典面试问题&#xff08;进阶问题&#xff09; 1.6 foreign key — 外键约束 1.7…

基于STC89C52RC和8X8点阵屏、独立按键的小游戏《打砖块》

目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、8X8点阵屏2、独立按键3、定时器04、定时器1 四、主函数总结 系列文章目录 前言 用的是普中A2开发板&#xff0c;外设有&#xff1a;8X8LED点阵屏、独立按键。 【单片机】STC89C52RC 【频率】12T11.0592MHz 效…

数字电子技术基础(五十)——硬件描述语言简介

目录 1 硬件描述语言简介 1.1 硬件描述语言简介 1.2 硬件编程语言的发展历史 1.3 两种硬件描述的比较 1.4 硬件描述语言的应用场景 1.5 基本程序结构 1.5.1 基本程序结构 1.5.2 基本语句和描述方法 1.5.3 仿真 1 硬件描述语言简介 1.1 硬件描述语言简介 硬件描述语…

【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件common.py解读

【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件common.py解读 文章目录 【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件common.py解读前言autopad函数Conv类__init__成员函数forward成员函数forward_fuse成员函数 Bottleneck类__init__成员…

16.Chromium指纹浏览器开发教程之WebGPU指纹定制

WebGPU指纹概述 WebGPU是下一代的Web图形和计算API&#xff0c;旨在提供高性能的图形渲染和计算能力。它是WebGL的后继者&#xff0c;旨在利用现代GPU的强大功能&#xff0c;使得Web应用能够实现接近原生应用的图形和计算性能。而且它是一个低级别的API&#xff0c;可以直接与…

SQL预编译——预编译真的能完美防御SQL注入吗

SQL注入原理 sql注入是指攻击者拼接恶意SQL语句到接受外部参数的动态SQL查询中&#xff0c;程序本身 未对插入的SQL语句进行过滤&#xff0c;导致SQL语句直接被服务端执行。 拼接的SQL查询例如&#xff0c;通过在id变量后插入or 11这样的条件&#xff0c;来绕过身份验证&#…

运行neo4j.bat console 报错无法识别为脚本,PowerShell 教程:查看语言模式并通过注册表修改受限模式

无法将“D:\neo4j-community-4.4.38-windows\bin\Neo4j-Management\Get-Args.ps1”项识别为cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。 前提配置好环境变量之后依然报上面的错…

【EDA软件】【设计约束和分析操作方法】

1. 设计约束 设计约束主要分为物理约束和时序约束。 物理约束主要包括I/O接口约束&#xff08;如引脚分配、电平标准设定等物理属性的约束&#xff09;、布局约束、布线约束以及配置约束。 时序约束是FPGA内部的各种逻辑或走线的延时&#xff0c;反应系统的频率和速度的约束…

【Lua】Lua 入门知识点总结

Lua 入门学习笔记 本教程旨在帮助有编程基础的学习者快速入门Lua编程语言。包括Lua中变量的声明与使用&#xff0c;包括全局变量和局部变量的区别&#xff0c;以及nil类型的概念、数值型、字符串和函数的基本操作&#xff0c;包括16进制表示、科学计数法、字符串连接、函数声明…