为什么rapier3d碰撞检测在bevy引擎中不起作用?

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

我正在使用 bevy 0.14 开发游戏。我正在慢慢地阅读手册。我尝试使用 rapier3d 检测碰撞。

由于没有反应,我想检查一下设置是否不正确。

我检查了几次手册并继续编码,但没有检测到崩溃事件,所以我想知道我的代码有什么问题。

下面的代码是我到目前为止的代码。为什么这里没有发生崩溃事件?

use bevy::input::mouse::{MouseMotion, MouseWheel};
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;

fn main() {
    App::new().
        add_plugins(DefaultPlugins).
        add_plugins(RapierPhysicsPlugin::<NoUserData>::default()).
        add_plugins(RapierDebugRenderPlugin::default()).
        add_systems(Startup, init_object).
        add_systems(Update, (player_movement, camera_movement)).
        add_systems(PostUpdate, landed_player_check).
        run();
}

// 플레이어 컴포넌트 정의
#[derive(Component)]
struct Player {
    is_jumping: bool,
}

impl Default for Player {
    fn default() -> Self {
        Self {is_jumping: false}
    }
}

#[derive(Component)]
struct Camera;

#[derive(Component)]
struct CameraFollow {
    offset: Vec3,    
}

#[derive(Component)]
struct Ground;


fn init_object(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 바닥
    commands.spawn((
        PbrBundle {
            mesh: meshes.add(Plane3d::default().mesh().size(20., 20.)),
            material: materials.add(Color::srgb_u8(255, 0, 0)),
            transform: Transform::from_xyz(0.0, 0.0, 0.0), 
            ..default()
        },
        Collider::cuboid(10.0, 0.0, 10.0), 
        Ground,
    ));


    // 플레이어
    commands.spawn((
        PbrBundle {
            mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)),
            transform: Transform::from_xyz(0.0, 1.0, 0.0), 킴
            material: materials.add(StandardMaterial {
                base_color: Color::WHITE,
                ..default()
            }),
            ..default()
        },
        Player::default(),
        RigidBody::Dynamic,
        Collider::cuboid(0.5, 0.5, 0.5), 
        GravityScale(10.0),
    ));

    // 빛
    commands.spawn(DirectionalLightBundle {
        transform: Transform::from_translation(Vec3::ONE).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });


    // 카메라
    commands.spawn((
        Camera3dBundle {
            transform: Transform::from_xyz(0.0, 10.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
            ..default()
        },
        Camera,
        CameraFollow {
            offset: Vec3::new(0.0, 10.0, 10.0), 
        },
    ));
}


fn player_movement(
    mut query: Query<(&mut Transform, &mut Player), With<Player>>, 
    keyboard_input: Res<ButtonInput<KeyCode>>,
    time: Res<Time>, 
) {
    let speed = 10.0;

    // 쿼리된 엔티티들의 Transform 반복 처리
    if let Ok((mut transform, mut player_state)) = query.get_single_mut() {
        if !player_state.is_jumping {
            let mut direction = Vec3::ZERO;
            if keyboard_input.pressed(KeyCode::KeyW) {
                direction.z -= 1.0;
            }
            if keyboard_input.pressed(KeyCode::KeyS) {
                direction.z += 1.0;
            }
            if keyboard_input.pressed(KeyCode::KeyA) {
                direction.x -= 1.0;
            }
            if keyboard_input.pressed(KeyCode::KeyD) {
                direction.x += 1.0;
            }
            if keyboard_input.pressed(KeyCode::Space) {
                player_state.is_jumping = true;
                direction.y += 10.0;
            }
            transform.translation += direction * speed * time.delta_seconds();
        }
    }
}


fn camera_movement(
    mut param_set: ParamSet<(
        Query<(&mut Transform, &mut Player), With<Player>>,  // 플레이어 쿼리
        Query<(&mut Transform, &mut CameraFollow), With<Camera>>,  // 카메라 쿼리
    )>,
    mouse_button: Res<ButtonInput<MouseButton>>,
    mut mouse_motion: EventReader<MouseMotion>,
    mut wheel_event: EventReader<MouseWheel>,
) {
    let zoom_speed = 0.5;



    // 마우스 중앙 버튼을 누른 경우, 카메라 회전을 처리합니다.
    if mouse_button.pressed(MouseButton::Middle) {
        for mouse_move_event in mouse_motion.read() {
            if let Ok((player_transform, _)) = param_set.p0().get_single() {
                let player_position = player_transform.translation;  // 플레이어 위치를 먼저 가져옴

                if let Ok((mut camera_transform, mut camera_follow)) = param_set.p1().get_single_mut() {
                    // 좌우 회전은 월드 Y축, 상하 회전은 카메라 로컬 X축을 기준으로 처리
                    // 음수를 곱해 마우스 이동 방향을 반전시킴
                    let rotation = Quat::from_rotation_y(-mouse_move_event.delta.x * 0.005)
                        * Quat::from_axis_angle(*camera_transform.local_x(), -mouse_move_event.delta.y * 0.005);

                    // 카메라 오프셋을 회전시켜 새로운 위치 계산
                    camera_follow.offset = rotation * camera_follow.offset;
                    camera_transform.translation = player_position + camera_follow.offset;

                    // 카메라가 항상 플레이어를 바라보도록 설정
                    camera_transform.look_at(player_position, Vec3::Y);
                }
            }
        }
    }


    // 이제 카메라의 위치를 수정합니다.
    if let Ok((player_transform, _)) = param_set.p0().get_single() {
        let player_position = player_transform.translation;
        if let Ok((mut camera_transform, camera_follow)) = param_set.p1().get_single_mut() {
            camera_transform.translation = player_position + camera_follow.offset;
            camera_transform.look_at(player_position, Vec3::Y);
        }
    }


    // 휠로 줌을 조정할 때, 오프셋을 Z축 방향으로만 조정합니다.
    for v in wheel_event.read() {
        if let Ok((_, mut camera_follow)) = param_set.p1().get_single_mut() {
            // Z축 오프셋만 조정하여 줌을 적용
            let zoom_delta = -v.y * zoom_speed;
            let offset_length = camera_follow.offset.length();

            // 줌 범위를 제한하고 오프셋을 조정
            let new_length = (offset_length + zoom_delta).clamp(5.0, 20.0);
            camera_follow.offset = camera_follow.offset.normalize() * new_length;
        }
    }
}


fn landed_player_check(
    mut collision_events: EventReader<CollisionEvent>,
    player_query: Query<Entity, With<Player>>,
    ground_query: Query<Entity, With<Ground>>,
) {
    let player_entity = player_query.get_single().ok();
    let ground_entity = ground_query.get_single().ok();

    for event in collision_events.read() {
        println!("Collision event detected: {:?}", event);
        match event {
            CollisionEvent::Started(entity1, entity2, _) => {
                println!("entity1: {:?}, entity2: {:?}", entity1, entity2);

                if let (Some(player), Some(ground)) = (player_entity, ground_entity) {
                    println!("Player Entity: {:?}, Ground Entity: {:?}", player, ground);

                    if (*entity1 == player && *entity2 == ground) || (*entity1 == ground && *entity2 == player) {
                        println!("플레이어가 바닥에 닿았습니다.");
                    } else {
                        println!("충돌은 발생했지만 플레이어와 바닥이 아닙니다.");
                    }
                }
            }
            _ => {}
        }
    }
}
rust bevy rapier rapier-3d
1个回答
0
投票

我最近也在努力解决这个问题,根据https://rapier.rs/docs/user_guides/bevy_plugin/colliders#active-collision-types,你必须明确启用特定类型的刚体和碰撞器之间的碰撞。检查 ActiveCollisionTypes 的文档以了解您需要哪些标志。

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