Bevy 第一人称玩家模型不可见

问题描述 投票:0回答:1

我一直在尝试和bevy一起制作一款FPS游戏。第二天我遇到了一个问题,那就是如果我将玩家的手臂和武器模型附加到相机上,那么它是不可见的。看来 bevy 的渲染器通过算法将其隐藏起来,尽管这种情况不应该发生。我该如何解决这个问题?

我尝试使用

CheckVisibility
集中的系统强制它可见,但这似乎也不起作用。我不确定我在这里犯了什么错。

我将 fps 模型从相机上拆下来进行测试,果然,它渲染得很好,直到我靠近它,它实际上应该在的位置。然后,它就消失了。 :-(

这是我的代码:

use crate::character_controller::{
    CharacterControllerBundle, CharacterControllerPlugin, DirectionLooker,
};
use bevy::{
    ecs::event::ManualEventReader,
    input::mouse::MouseMotion,
    prelude::*,
    render::view::{check_visibility, VisibilitySystems::CheckVisibility},
    window::{CursorGrabMode, PrimaryWindow},
};
use bevy_xpbd_3d::{math::Scalar, prelude::*};

/// Marker component representing a `Camera` attached to the player
#[derive(Component)]
pub struct FPSCam;

/// Marker component representing the player
#[derive(Component)]
pub struct Player;

/// Marker component representing the player's view model
#[derive(Component)]
pub struct PlayerViewModel;

pub struct PlayerPlugin;
impl Plugin for PlayerPlugin {
    fn build(&self, app: &mut App) {
        app.init_resource::<InputState>()
            .init_resource::<LookSettings>()
            .add_plugins(CharacterControllerPlugin)
            .add_systems(Startup, setup)
            .add_systems(Update, (grab, look))
            .add_systems(
                PostUpdate,
                make_visible.in_set(CheckVisibility).after(check_visibility),
            );
    }
}

#[derive(Resource, Default)]
struct InputState {
    reader_motion: ManualEventReader<MouseMotion>,
}

#[derive(Resource)]
pub struct LookSettings {
    pub sensitivity: f32,
}

impl Default for LookSettings {
    fn default() -> Self {
        Self {
            sensitivity: 0.00006,
        }
    }
}

fn setup(mut commands: Commands, assets: Res<AssetServer>) {
    // player
    let player = commands
        .spawn((
            SpatialBundle {
                transform: Transform::from_xyz(0.0, 1.5, 0.0),
                ..default()
            },
            Player,
            DirectionLooker,
            CharacterControllerBundle::new(Collider::capsule(1.0, 0.4))
                .with_movement(30.0, 0.92, 7.0, (30.0 as Scalar).to_radians()),
            Friction::ZERO.with_combine_rule(CoefficientCombine::Min),
            Restitution::ZERO.with_combine_rule(CoefficientCombine::Min),
            GravityScale(2.0),
        ))
        .id();

    let mut fps_model_transform = Transform::from_xyz(0.0, 0.7, 0.0);
    fps_model_transform.rotate_y(180.0_f32.to_radians());

    let _fps_model = commands
        .spawn((
            SceneBundle {
                scene: assets.load("mp5.glb#Scene0"),
                transform: fps_model_transform,
                ..default()
            },
            PlayerViewModel,
        ))
        .id();

    // camera
    let camera = commands
        .spawn((
            Camera3dBundle {
                projection: PerspectiveProjection {
                    fov: 80.0_f32.to_radians(),
                    near: 0.001,
                    ..default()
                }
                .into(),
                transform: Transform::from_xyz(0.0, 0.5, 0.0),
                ..default()
            },
            FPSCam,
        ))
        .id();
    commands.entity(player).push_children(&[camera]);
}

fn make_visible(mut query: Query<&mut ViewVisibility, With<PlayerViewModel>>) {
    for mut visibility in &mut query {
        visibility.set();
    }
}

fn grab(
    mut windows: Query<&mut Window>,
    keys: Res<Input<KeyCode>>,
    mouse: Res<Input<MouseButton>>,
) {
    let mut window = windows.single_mut();

    if mouse.just_pressed(MouseButton::Right) {
        window.cursor.visible = false;
        window.cursor.grab_mode = CursorGrabMode::Locked;
    } else if keys.just_pressed(KeyCode::Escape) {
        window.cursor.visible = true;
        window.cursor.grab_mode = CursorGrabMode::None;
    }
}

fn look(
    settings: Res<LookSettings>,
    primary_window: Query<&Window, With<PrimaryWindow>>,
    motion: Res<Events<MouseMotion>>,
    mut state: ResMut<InputState>,
    mut player_query: Query<(&mut Transform, With<Player>, Without<FPSCam>)>,
    mut camera_query: Query<(&mut Transform, With<FPSCam>, Without<Player>)>,
) {
    if let Ok(window) = primary_window.get_single() {
        for ev in state.reader_motion.read(&motion) {
            for (mut player_transform, _, _) in player_query.iter_mut() {
                let mut yaw =
                    player_transform.rotation.to_euler(EulerRot::YXZ).0;

                match window.cursor.grab_mode {
                    CursorGrabMode::None => (),
                    _ => {
                        // Using smallest of height or width ensures equal
                        // vertical and horizontal sensitivity
                        let window_scale = window.height().min(window.width());
                        yaw -=
                            (settings.sensitivity * ev.delta.x * window_scale)
                                .to_radians();
                    }
                }

                player_transform.rotation = Quat::from_axis_angle(Vec3::Y, yaw);
            }

            for (mut camera_transform, _, _) in camera_query.iter_mut() {
                let mut pitch =
                    camera_transform.rotation.to_euler(EulerRot::YXZ).1;

                match window.cursor.grab_mode {
                    CursorGrabMode::None => (),
                    _ => {
                        // Using smallest of height or width ensures equal
                        // vertical and horizontal sensitivity
                        let window_scale = window.height().min(window.width());
                        pitch -=
                            (settings.sensitivity * ev.delta.y * window_scale)
                                .to_radians();
                    }
                }

                camera_transform.rotation =
                    Quat::from_axis_angle(Vec3::X, pitch.clamp(-1.54, 1.54));
            }
        }
    } else {
        warn!("Primary window not found!");
    }
}

rust game-development bevy
1个回答
0
投票

发生这种情况的原因是 Bevy 的自动视锥体剔除。通过将

NoFrustumCulling
组件添加到
Mesh
可以轻松修复它。但是,由于我没有使用普通的
Mesh
而是使用 glTF
Scene
,因此我使用
bevy-scene-hook
NoFrustumCulling
组件应用到具有
Handle<Mesh>
的任何内容。现在可以了。

    let fps_model = commands
        .spawn(HookedSceneBundle {
            scene: SceneBundle {
                scene: assets.load("mp5.glb#Scene0"),
                transform: fps_model_transform,
                ..default()
            },
            hook: SceneHook::new(|entity, commands| {
                if entity.get::<Handle<Mesh>>().is_some() {
                    commands.insert(NoFrustumCulling);
                }
            }),
        })
        .id();

当然,请确保从

bevy_scene_hook
箱中导入适当的类型。另外,您还需要添加
HookPlugin

© www.soinside.com 2019 - 2024. All rights reserved.