0
votes

Does Unity have something like a CollideWhenRigidBodyLeavesLayer method? Here is why:

My npc's have three MovementTypes: Walk, Swim, and Fly

They use a rigidbody for their movement and it works beautifully for characters that walk.

It also works nicely for characters that fly. By calling Physics.IgnoreLayerCollision(FlyingCharacterLayer, WaterLayer) Flying characters are now able to fly over water.

My question is, how can I make my swimming creature stay overlapping the Water Layer?

I have turned on Physics.IgnoreLayerCollision(SwimmingCharacterLayer, WaterLayer) So now swimming characters can overlap water.

But how do I test that my sea creature is leaving the water and create a collision here so he turns around and continues to swim instead of evolving into a walking fish...

My level (and therefore water) are generated dynamically so adding a perimeter obstacle for collision testing is not a very good option.

Also, the "ground" graphic/layer exists under the Water layer so I don't think there is a good way to test for collision with ground because my fish is overlapping the ground and water at the same time.

I hope I am missing something basic :)

Thanks!

UPDATE: I can check if my swimming character is no longer overlapping water with Physics.CheckSphere

But I can't figure out what to do from there. If I try to turn him around 180 degrees, he flips every frame and sometimes goes back to the water sometimes not...

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
}
1
Unfortunately, that's not how the physics system works. :(Draco18s no longer trusts SE
How do you stop the walking one from entering the water? Shouldn't that also work the other way round?derHugo
I guess it would help to understand better if you added a more complete code examplederHugo
@derHugo Thanks for putting your mind to this! There really isnt a ton of code to show... the water is a 3d object that is about 0.1 units high and sits just above the ground. It has a Collider attached to it so the rigidbody walking characters just interact with it by the magic of rigidbody physics :)Captain Noah

1 Answers

0
votes

I'm not really proud of it but after fiddling around here is what I have come up with.

It seems to keep the fish in the pond, but the bounces aren't pretty.

It also totally violate the "Dont fuss with rigidbodies transform" rule ...but since the physics system wont work with me anyway...

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);
        }
}