Unity RigidBody Physics: столкновение при НЕ перекрывающемся слое

Есть ли в Unity что-то вроде метода CollideWhenRigidBodyLeavesLayer? Вот почему:

У моего NPC есть три типа движения: ходьба, плавание и полет.

Они используют жесткое тело для своих движений, и это прекрасно работает с персонажами, которые ходят.

Это также хорошо работает для летающих персонажей. Вызывая Physics.IgnoreLayerCollision (FlyingCharacterLayer, WaterLayer), летающие персонажи теперь могут летать над водой.

У меня вопрос, как я могу сделать так, чтобы мое плавающее существо продолжало перекрывать слой воды?

Я включил Physics.IgnoreLayerCollision (SwimmingCharacterLayer, WaterLayer). Теперь плавающие персонажи могут перекрывать воду.

Но как мне проверить, что мое морское существо покидает воду и создает здесь столкновение, чтобы оно развернулось и продолжило плавать вместо того, чтобы превратиться в ходячую рыбу ...

Мой уровень (и, следовательно, вода) генерируются динамически, поэтому добавление препятствия по периметру для тестирования столкновений - не очень хороший вариант.

Кроме того, графическое изображение / слой «земля» существует под слоем «Вода», поэтому я не думаю, что есть хороший способ проверить столкновение с землей, потому что моя рыба перекрывает землю и воду одновременно.

Надеюсь, мне не хватает чего-то базового :)

Спасибо!

ОБНОВЛЕНИЕ: я могу проверить, не перекрывает ли мой плавающий персонаж воду с помощью Physics.CheckSphere

Но я не могу понять, что оттуда делать. Если я пытаюсь повернуть его на 180 градусов, он переворачивает каждый кадр и иногда возвращается в воду, иногда нет ...

if(Physics.CheckSphere(transform.position, 0.25f, LayerMask.NameToLayer("Water")) == false)
{
    // Now I know that my fish is out of the water
    // but I can not figure out how to turn him around
}

person Captain Noah    schedule 17.10.2019    source источник
comment
К сожалению, физическая система работает не так. :(   -  person Draco18s no longer trusts SE    schedule 17.10.2019
comment
Как не дать ходящему войти в воду? Разве это не должно работать и наоборот?   -  person derHugo    schedule 17.10.2019
comment
Думаю, было бы лучше понять, если бы вы добавили более полный пример кода   -  person derHugo    schedule 17.10.2019
comment
@derHugo Спасибо, что задумались об этом! На самом деле нет тонны кода, чтобы показать ... вода - это трехмерный объект высотой около 0,1 единицы, который находится прямо над землей. К нему прикреплен коллайдер, поэтому персонажи, идущие по твердому телу, просто взаимодействуют с ним с помощью магии физики твердого тела :)   -  person Captain Noah    schedule 17.10.2019


Ответы (1)


Я не очень горжусь этим, но после того, как поигрался здесь, я придумал.

Вроде удерживает рыбу в пруду, но отскоки не очень приятные.

Это также полностью нарушает правило «Не суетись с преобразованием твердых тел» ... но поскольку физическая система в любом случае не будет работать со мной ...

enum CheckDirection { AHEAD, LEFT, RIGHT };
bool CheckAheadIsWater(CheckDirection dir = CheckDirection.AHEAD)
    {
        if(dir == CheckDirection.AHEAD)
            return Physics.CheckSphere(transform.position + transform.forward * 1.5f, 0.5f, LayerMask.GetMask(Settings.LayerWater));
        if(dir == CheckDirection.RIGHT)
            return Physics.CheckSphere(transform.position + forward + transform.right * 2f, 0.5f, LayerMask.GetMask(Settings.LayerWater));
        if(dir == CheckDirection.LEFT)
            return Physics.CheckSphere(transform.position + transform.forward - transform.right * 2f, 0.5f, LayerMask.GetMask(Settings.LayerWater));

        throw new System.Exception("No Check Existes For " + dir);
    }

void Update()
{
       if (!CheckAheadIsWater(CheckDirection.RIGHT))
        {
            print("about to leave water RIGHT");

            //turn left 45 degrees
            transform.rotation = Quaternion.LookRotation(transform.forward + transform.right * 0.5f);
        }

        if (!CheckAheadIsWater(CheckDirection.LEFT))
        {
            print("about to leave water LEFT");

            //turn right 45 degrees           
            transform.rotation = Quaternion.LookRotation(transform.forward - transform.right * 0.5f);
        }

        if (!CheckAheadIsWater())
        {
            print("about to leave water AHEAD");

            //bounce back 1 unit
            physicalBody.MovePosition(transform.position - transform.forward);
            //swim the opposite direction
            transform.rotation = Quaternion.LookRotation(-transform.forward);
        }
}

person Captain Noah    schedule 17.10.2019