You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust Bevy中利用时间实现玩家重力系统?

在Rust Bevy引擎中实现玩家重力系统的可行方案

你当前的代码存在两个核心问题:一是重复获取Velocity2可变引用会触发panic(同一查询无法同时获取两次可变权限);二是直接将y速度设置为固定值乘时间增量的方式不符合真实物理逻辑(重力应作为加速度持续改变速度,而非直接赋值)。以下是几种更合理的实现方案:


方案1:基于物理加速度的标准实现(手动处理)

将重力逻辑与玩家输入拆分,让系统职责更清晰,同时符合物理规律:

1. 玩家输入控制单独处理

fn player_movement(
    kb: Res<Input<KeyCode>>,
    mut query: Query<&mut Velocity2, With<Player2>>,
) {
    let mut velocity = query.single_mut();
    
    // 水平移动速度设置
    velocity.x = match (kb.pressed(KeyCode::A), kb.pressed(KeyCode::D)) {
        (true, false) => -5.0,  // 可根据需求调整移动速度
        (false, true) => 5.0,
        _ => 0.0,
    };

    // 跳跃触发(使用just_pressed防止持续跳跃)
    if kb.just_pressed(KeyCode::W) {
        velocity.y = 8.0;  // 跳跃初速度
    }

    // 下蹲/快速下落
    if kb.pressed(KeyCode::S) {
        velocity.y = -6.0;
    }
}

2. 重力加速度单独应用

fn apply_gravity(
    mut query: Query<&mut Velocity2, With<Player2>>,
    time: Res<Time>,
) {
    let mut velocity = query.single_mut();
    const GRAVITY: f32 = -9.8;  // 模拟现实重力,可自定义调整
    velocity.y += GRAVITY * time.delta_seconds();
}

记得在App中同时添加这两个系统,且保证重力系统在输入系统之后执行(可以通过SystemSet或after方法排序)。


方案2:使用Bevy内置物理插件(省心高效)

如果项目需要处理碰撞、地面检测等复杂物理逻辑,直接用Bevy官方推荐的物理插件(如bevy_rapier2d或bevy_xpbd)更高效:

  1. 添加依赖到Cargo.toml:
bevy_rapier2d = "0.21"  # 版本号需匹配你的Bevy版本
  1. 初始化物理插件:
use bevy_rapier2d::prelude::*;

App::new()
    .add_plugins(DefaultPlugins)
    .add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
    .add_plugins(RapierDebugRenderPlugin::default())  // 可选:调试碰撞体渲染
    .add_systems(Startup, spawn_player)
    .add_systems(Update, player_controls)
    .run();
  1. 生成带物理组件的玩家:
fn spawn_player(mut commands: Commands) {
    commands.spawn((
        Player2,
        SpriteBundle {
            sprite: Sprite {
                color: Color::RED,
                custom_size: Some(Vec2::new(32.0, 32.0)),
                ..default()
            },
            transform: Transform::from_xyz(0.0, 0.0, 0.0),
            ..default()
        },
        RigidBody::Dynamic,  // 动态刚体,受重力和外力影响
        Collider::cuboid(16.0, 16.0),  // 碰撞体尺寸匹配精灵
        GravityScale(1.0),  // 重力缩放系数,可调整
        Velocity::zero(),
    ));
}
  1. 玩家输入控制(只需操作物理引擎的速度):
fn player_controls(
    kb: Res<Input<KeyCode>>,
    mut query: Query<&mut Velocity, With<Player2>>,
) {
    let mut velocity = query.single_mut();
    const MOVE_SPEED: f32 = 500.0;
    const JUMP_FORCE: f32 = 800.0;

    velocity.linvel.x = match (kb.pressed(KeyCode::A), kb.pressed(KeyCode::D)) {
        (true, false) => -MOVE_SPEED,
        (false, true) => MOVE_SPEED,
        _ => 0.0,
    };

    if kb.just_pressed(KeyCode::W) {
        velocity.linvel.y = JUMP_FORCE;
    }
}

物理引擎会自动处理重力、碰撞、地面检测等逻辑,无需手动编写重力代码。


方案3:简化单系统实现(快速原型)

如果不想拆分系统,可修复原代码的可变引用问题,并正确应用重力:

fn player_2_keyboard_event_system(
    kb: Res<Input<KeyCode>>,
    mut query: Query<&mut Velocity2, With<Player2>>,
    time: Res<Time>,
) {
    let mut velocity2 = query.single_mut();

    // 水平移动
    velocity2.x = if kb.pressed(KeyCode::A) {
        -5.0
    } else if kb.pressed(KeyCode::D) {
        5.0
    } else {
        0.0
    };

    // 垂直控制与重力
    if kb.pressed(KeyCode::S) {
        velocity2.y = -6.0;
    } else if kb.just_pressed(KeyCode::W) {
        velocity2.y = 8.0;
    } else {
        const GRAVITY: f32 = -9.8;
        velocity2.y += GRAVITY * time.delta_seconds();
    }
}

内容的提问来源于stack exchange,提问作者Rusty_Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:45:31