BoomingTech / Piccolo

Piccolo (formerly Pilot) – mini game engine for games104
MIT License
5.9k stars 1.83k forks source link

在加入了复杂的碰撞检查之后当发生碰撞时人物的速度变得特别的快 #257

Closed Fanby1 closed 2 years ago

Fanby1 commented 2 years ago

Describe the bug | Bug描述 A clear and concise description of what the bug is. 在加入了复杂的碰撞检查之后任务的速度变得特别的快

Steps to reproduce | 如何复现 Steps to reproduce the behavior:

  1. 加入一个递归的检查是否碰撞并进行抬升和策划的move函数
  2. 运行小引擎并让小人装上物体
  3. 物体的displacement.length()上升到1左右
  4. 在平地上行走
  5. 物体的displacement.length()回到10^(-2)量级

Expected behavior | 预期行为 A clear and concise description of what you expected to happen. 在发生碰撞时以正常速度行走

Actual behavior | 实际行为 A clear and concise description of what actually happened. 人物跑的飞快

Screenshots/Logs | 截图/日志 If applicable, add screenshots and/or a video to help explain your problem. 我在move函数中加入了一个对displacement.length()的输出。和一些辅助我查找bug的输出。 代码:

    Vector3 CharacterController::move(const Vector3& current_position, const Vector3& displacement)
    {
        float len = displacement.length();
        m_calculate_times ++;
        if(len == 0){
            return current_position;
        }
        else if(m_calculate_times >= 4|| displacement.length() < 0.000001){
            m_calculate_times = 0;
            return current_position + displacement;
        }

        std::cout << displacement.length() << std::endl;
        std::shared_ptr<PhysicsScene> physics_scene =
            g_runtime_global_context.m_world_manager->getCurrentActivePhysicsScene().lock();
        ASSERT(physics_scene);

        std::vector<PhysicsHitInfo> hits;

        Transform world_transform = Transform(
            current_position + 0.1f * Vector3::UNIT_Z,
            Quaternion::IDENTITY,
            Vector3::UNIT_SCALE);

        Vector3 vertical_displacement   = displacement.z * Vector3::UNIT_Z;
        Vector3 horizontal_displacement = Vector3(displacement.x, displacement.y, 0.f);

        Vector3 vertical_direction   = vertical_displacement.normalisedCopy();
        Vector3 horizontal_direction = horizontal_displacement.normalisedCopy();

        Vector3 final_position = current_position;

        m_is_touch_ground = physics_scene->sweep(
            m_rigidbody_shape,
            world_transform.getMatrix(),
            Vector3::NEGATIVE_UNIT_Z,
            0.105f,
            hits);

        hits.clear();

        world_transform.m_position -= 0.1f * Vector3::UNIT_Z;

        // vertical pass
        if (physics_scene->sweep(
            m_rigidbody_shape,
            world_transform.getMatrix(),
            vertical_direction,
            vertical_displacement.length(),
            hits))
        {
            final_position += hits[0].hit_distance * vertical_direction;
        }
        else
        {
            final_position += vertical_displacement;
        }

        hits.clear();

        // side pass
        if (physics_scene->sweep(
            m_rigidbody_shape,
            world_transform.getMatrix(),
            horizontal_displacement,
            horizontal_displacement.length(),
            hits))
        {
            std::cout << "front crash" << std::endl;
            world_transform.m_position += 0.5f * Vector3::UNIT_Z;
            std::vector<PhysicsHitInfo> forward_hits,up_hits;
            if (physics_scene->sweep(
                m_rigidbody_shape,
                world_transform.getMatrix(),
                horizontal_displacement,
                horizontal_displacement.length(),
                forward_hits
            ) || physics_scene->sweep(
                m_rigidbody_shape,
                world_transform.getMatrix(),
                Vector3::UNIT_Z,
                0.005f,
                up_hits
            ))
            {  
                Vector3 length = hits[0].hit_distance * horizontal_direction;
                final_position += length;
                horizontal_displacement = horizontal_direction - length;
                Vector3 new_normal = - (hits[0].hit_normal.dotProduct(horizontal_displacement)) * hits[0].hit_normal;
                Vector3 new_displacement = horizontal_displacement + new_normal;
                std::cout << std::to_string(m_calculate_times) + " not jump\n" + 
                std::to_string(horizontal_displacement.x) + " " + std::to_string(horizontal_displacement.y) + " " + std::to_string(horizontal_displacement.z)
                + "\n" + std::to_string(hits[0].hit_normal.x) + " " + std::to_string(hits[0].hit_normal.y) + " " + std::to_string(hits[0].hit_normal.z)
                + "\n" + std::to_string(hits[0].hit_distance) + " Id" + std::to_string(hits[0].body_id)
                + '\n' + std::to_string((hits[0].hit_distance * horizontal_direction).length())
                + "\n" + std::to_string(final_position.x) + " " + std::to_string(final_position.y) + " " + std::to_string(final_position.z)
                << std::endl;
                final_position = CharacterController::move(final_position,new_displacement);
            }
            else{

                std::vector<PhysicsHitInfo> length_hits;
                if(physics_scene->sweep(
                    m_rigidbody_shape,
                    world_transform.getMatrix(),
                    Vector3::NEGATIVE_UNIT_Z,
                    0.505f,
                    length_hits
                )){
                    final_position += length_hits[0].hit_distance * Vector3::UNIT_Z;
                }else{
                    final_position += 0.5f * Vector3::UNIT_Z;
                }
                Vector3 length = hits[0].hit_distance * horizontal_direction;
                final_position += length;
                std::cout << 
                std::to_string(m_calculate_times) + "jump" 
                + "\n" + std::to_string(final_position.x) + " " + std::to_string(final_position.y) + " " + std::to_string(final_position.z)
                << std::endl;
                final_position = CharacterController::move(final_position,horizontal_direction - length);
            }
        }
        else
        {
            final_position += horizontal_displacement;
            if (m_calculate_times > 1){
                std::cout << 
                std::to_string(m_calculate_times) + "not crash"
                + "\n" + std::to_string(horizontal_displacement.x) + " " + std::to_string(horizontal_displacement.y) + " " + std::to_string(horizontal_displacement.z)
                + "\n" + std::to_string(final_position.x) + " " + std::to_string(final_position.y) + " " + std::to_string(final_position.z)
                << std::endl;
            }
        }

        m_calculate_times = 0;
        return final_position;
    }

输出: 1)正常行走时 image 2)撞墙时

image

可以看到在front crash 前面是输出的距离。明显过大。 Desktop | 桌面环境

Additional context | 补充信息 Add any other context about the problem here. 不清楚这是不是一个bug,不过感觉是。我想查到怎么算出的displacement,但是没能查到。

Ol6rin commented 2 years ago

原始来自motor的displacement是engine\source\runtime\function\framework\component\motor\motor_component.cpp:174调用controller的move传入,具体m_desired_displacement的计算参见MotorComponent::calculateDesiredDisplacement函数。你的问题应该是递归导致。