2 (or 3) Possible Bugs I Found

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
MitchellKrenz
Posts: 6
Joined: Thu Jul 02, 2015 2:26 pm

2 (or 3) Possible Bugs I Found

Post by MitchellKrenz »

Hello, me again...

So I took your advice and went with a StaticGroup, its working great! After I got over that hurdle I was able to implement many more things and that's how I came across the following:

1. When an instance of CharacterController is standing on top of a StaticGroup that has had it's top extended with .Shaps.Add() the character kind of bounces up and down forever... If you reconstruct the StaticGroup by removing the old from the space and create a new StaticGroup with the exact same set of collidables the problem does not occur. I tried to debug this the best I could to give you as much information as possible and from what I can tell the player is sinking into the top of the StaticGroup and then during collision detection this is realized and an impulse is generated with a positive Y vector and the character is boosted into the air. Then the player is caught by gravity and starts falling again until it sinks far enough into the StaticGroup that the process repeats. Tried to look into how it was constructing the bounding boxes differently for each situation and I quit when the recursion started popping up everywhere... That code is nuts, I didn't understand most of it haha.

2. The second bug I found, or maybe it isn't a bug at all? is related to the CharacterController and its VerticalMotionConstraint not being updated if it doesn't have any external input that results in a net change in goal Y velocity. The easiest way to reproduce is to stand on a floor with gravity set to earths gravity, then on a key press do something like this Space.ForceUpdater.Gravity += new BEPUutilities.Vector3(0, 1, 0); After hitting that key 10 or more times you would think that you should start moving up, even changes to CharacterController.HorizontalMotionConstraint.MovementDirection have no effect. however if you run off an edge, or jump (, or run up a slope I presume) you will be lifted into the air as you should be. I also saw this manifest without changing Space.ForceUpdater.Gravity at all. I just stood on top of a tower of 3 voxels and looked down, clicked the voxel below me to deleted it and at this point I should have fallen to the next voxel but I don't fall until I move, but in this case changes to the HorizontalMotionConstraint will make me fall also, so this may be an entirely separate bug or a known limitation caused by the effort required to make it realistic?

Also with the second part of #2 (deleting box below me and not falling) I tested it with deleting the box both ways, Shapes.Remove and removing the block from the source collidable list and then reconstructing the entire static group and I saw the same thing both ways though it is only reproduceable on about 50% of the times I delete a block below me.

If you would like any more info related to these I'd be happy to provide it, anything in my power I can do to make BEPU better, I'd love to do!
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: 2 (or 3) Possible Bugs I Found

Post by Norbo »

When an instance of CharacterController is standing on top of a StaticGroup that has had it's top extended with .Shaps.Add() the character kind of bounces up and down forever...
That's a bug; the StaticGroup didn't register a ShapeChanged event correctly. It should now be fixed in the source version. To work around it in the current version, call StaticGroup.UpdateBoundingBox after adding or removing things.

Thanks for the report!
The second bug I found, or maybe it isn't a bug at all? is related to the CharacterController and its VerticalMotionConstraint not being updated if it doesn't have any external input that results in a net change in goal Y velocity. The easiest way to reproduce is to stand on a floor with gravity set to earths gravity, then on a key press do something like this Space.ForceUpdater.Gravity += new BEPUutilities.Vector3(0, 1, 0); After hitting that key 10 or more times you would think that you should start moving up, even changes to CharacterController.HorizontalMotionConstraint.MovementDirection have no effect. however if you run off an edge, or jump (, or run up a slope I presume) you will be lifted into the air as you should be.
That is expected behavior. Characters in games often run at absurd speeds that would make them go flying at the top of any staircase or small hill. To combat that, the VerticalMotionConstraint glues the character down.

You can tune this behavior by reducing the VerticalMotionConstraint.MaximumGlueForce or just setting the VerticalMotionConstraint.IsActive to false.
I also saw this manifest without changing Space.ForceUpdater.Gravity at all. I just stood on top of a tower of 3 voxels and looked down, clicked the voxel below me to deleted it and at this point I should have fallen to the next voxel but I don't fall until I move, but in this case changes to the HorizontalMotionConstraint will make me fall also, so this may be an entirely separate bug or a known limitation caused by the effort required to make it realistic?
This is a separate issue related to deactivation. The character went to sleep due to a lack of movement. Unlike adding/removing entities, modifying static groups does not result in activation of nearby entities; the collision pairs and reporting mechanism lack the information to handle that sort of situation gracefully right now. This would be a slightly larger change that I'm not sure about doing yet- the rewrite in progress would probably invalidate all of that effort.

A workaround is to directly activate any objects that have pairs with the removed object. Unfortunately, child collidables in StaticGroups and CompoundCollidables do not maintain their own pair lists. If there are a small number of collisions with the StaticGroup itself, you could enumerate its pairs. If there are a lot of collisions, it would be faster to just do a space query using the removed collidable's AABB:

Code: Select all

                    Space.BroadPhase.QueryAccelerator.GetEntries(collidableToRemove.BoundingBox, overlaps);
                    foreach (var overlap in overlaps)
                    {
                        var entityOverlap = overlap as EntityCollidable;
                        if (entityOverlap != null)
                        {
                            entityOverlap.Entity.ActivityInformation.Activate();

                        }
                    }
MitchellKrenz
Posts: 6
Joined: Thu Jul 02, 2015 2:26 pm

Re: 2 (or 3) Possible Bugs I Found

Post by MitchellKrenz »

Thanks Norbo! You're as helpful as always! I manually updated my source using the changeset referenced and it worked great! I was leery about downloading the dev trunk because I wasn't sure if you keep the Dev trunk in a state that's always stable or not. The second item I mentioned doesn't affect me, I just happened upon it so no changes there and then with the removal I used the code snipped you provided which I tucked into an extension method and that worked great too! I didn't quite understand what your last sentence meant about the two choices I had. I could have on remove just called CharacterController.Activate() or its rough equivalent but my main use case is that if I remove a block someone else is standing on I don't want them to float either. And because of box size the worst case scenario would be one or two players on a single block. In that use case is the code snippet's method better or the other? Or is it so basic that it doesn't really matter either way? That's what I was thinking since its not going to be a super frequent action since unlike minecraft most of our world will actually be static and when using it I didn't notice any lag or anything. Mostly I just want to understand it better because I have a lot more work to do with this game and I'm hoping in the not to distant future I'll be familiar enough with BEPU that I wont be asking you for help every other day haha.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: 2 (or 3) Possible Bugs I Found

Post by Norbo »

I manually updated my source using the changeset referenced and it worked great! I was leery about downloading the dev trunk because I wasn't sure if you keep the Dev trunk in a state that's always stable or not.
It's pretty much always stable- in this case, more stable than the 'stable' version. I try not to push anything public that I know won't compile or is just flat out broken. There are rare exceptions to this- in those cases, the commit message will typically contain a description of what doesn't work.
I didn't quite understand what your last sentence meant about the two choices I had. I could have on remove just called CharacterController.Activate() or its rough equivalent but my main use case is that if I remove a block someone else is standing on I don't want them to float either. And because of box size the worst case scenario would be one or two players on a single block. In that use case is the code snippet's method better or the other? Or is it so basic that it doesn't really matter either way? That's what I was thinking since its not going to be a super frequent action since unlike minecraft most of our world will actually be static and when using it I didn't notice any lag or anything. Mostly I just want to understand it better because I have a lot more work to do with this game and I'm hoping in the not to distant future I'll be familiar enough with BEPU that I wont be asking you for help every other day haha.
The other option was to enumerate the pairs listing of the StaticGroup to find colliding entities. The details of each pair could be analyzed to see if the associated entity should be woken up. This can wake up more than just one character.

Something like this, if you just wanted to wake up every entity touching any of the static group:

Code: Select all

            foreach (var pair in group.Pairs)
            {
                if (pair.Colliding)
                {
                    //Directly activate any entities that are in contact with the group.
                    //For pairs that directly involve a StaticGroup, any potential entity is in the B slot.
                    if (pair.EntityB != null)
                        pair.EntityB.ActivityInformation.Activate();
                }
            }
A deeper inspection could be done to only wake up the necessary subset, though it's more complicated:

Code: Select all

            foreach (var pair in group.Pairs)
            {
                //We are interested in waking up entities which are colliding with a particular child of the group.
                //We also know the entities we want to wake up have general convex collidables.
                //(If you didn't have this assumption, you'd also need to handle the other pair types...)
                if (pair.Colliding)
                {
                    var groupConvexPair = pair as StaticGroupConvexPairHandler;
                    if (groupConvexPair != null)
                    {
                        foreach (var childPair in groupConvexPair.ChildPairs)
                        {
                            //No guarantees on which slot the collidable is in, have to check both.
                            if (childPair.Value.CollidableA == collidableToRemove)
                            {
                                if (childPair.Value.EntityB != null)
                                    childPair.Value.EntityB.ActivityInformation.Activate();
                            }
                            else if (childPair.Value.CollidableB == collidableToRemove)
                            {
                                if (childPair.Value.EntityA != null)
                                    childPair.Value.EntityA.ActivityInformation.Activate();
                            }
                        }
                    }
                }
            }
In the event that there are very few pairs, doing a direct enumeration could be faster than a volume query. But if you expect to have dozens of objects and characters scampering across the StaticGroup, the volume approach is simple and faster. It doesn't matter much either way.
Post Reply