Proper way to freeze / disable entity?

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
vendetta
Posts: 18
Joined: Sat Dec 31, 2011 7:49 pm

Proper way to freeze / disable entity?

Post by vendetta »

Hi Norbo,
I'm working on a server authoritative shooter where each client has a capsule on the server. The code is done except for 'freezing' each entity except the one that I'm receiving input for (each time a user input comes in, the server is updated to the client's last received time).

What is the best way to 'freeze' / disable an entity without removing it from the space? Or would it be more efficient to add it to the space, update it, and then remove it from the space immediately after?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Proper way to freeze / disable entity?

Post by Norbo »

What is the best way to 'freeze' / disable an entity without removing it from the space? Or would it be more efficient to add it to the space, update it, and then remove it from the space immediately after?
I'm not exactly clear on what kind of freezing you wish to use; the following post may miss the mark a bit. That said, here's a couple of 'freezing'-like operations you can perform:

1) Removing an entity from the space removes it from the simulation entirely; if that is truly the desired effect, then you could avoid removing things from the simulation by adjusting collision rules to avoid collisions, turning off entity.IsAffectedByGravity while frozen, and setting the linear/angular velocity to zero. When unfrozen, set the collision rules and gravity back to normal and reset the velocity to what it was before. This is more efficient than removing entities in most cases (though it depends on the specifics, of course).

2) If you want to keep objects collidable within the simulation but prevent them from responding to any collision, making them kinematic would do the trick (entity.BecomeKinematic). This gives the entities essentially infinite mass; they cannot be moved by collisions.

Be careful: going back from kinematic->dynamic (entity.BecomeDynamic) will perform some expensive calculations unless you supply the appropriate cached local inertia tensor (which can be grabbed from the entity before forcing it to become kinematic).

Also note that entities will preserve their velocity by default when swapping from dynamic to kinematic and vice versa. To avoid this, set the LinearVelocity and AngularVelocity to zero after the swap.

(Depending on the particular implementation of the rewind-replay operation, you may find that incorporating some of the known past entity motion produces more coherent results than freezing everything in place for the duration of the replay. Of course, this depends heavily on the type of simulation, and rewind-replay isn't kind to complex interactions anyway. If the goal isn't rewind-replay, I have misunderstood something :))
vendetta
Posts: 18
Joined: Sat Dec 31, 2011 7:49 pm

Re: Proper way to freeze / disable entity?

Post by vendetta »

What Is happening is the space has a capsule for each player. The players each send in their commands at a set interval on the client, so player A's input may arrive at 400, and player B's at 450. Because I cannot update each player/capsule indivually (but update the space as a whole), I need to freeze every player except the one being updated. Each time a player input is received, I'm doing this:
(Also I should explain this is all server side code. The client is simply a rendering dummy, the server handles all the physics, and the world is a simple planar static mesh for testing purposes):

Code: Select all

 
                             //Unfreezing the player
                            player.CharacterController.CharacterController.Body.BecomeDynamic(player.Mass);
                            player.CharacterController.CharacterController.Body.IsAffectedByGravity = true;
                            player.CharacterController.CharacterController.Body.LinearVelocity = player.storedLinearVelocity;
                            player.CharacterController.CharacterController.Body.AngularVelocity = player.storedAngularVelocity;
                            player.CharacterController.CharacterController.Body.LocalInertiaTensorInverse = player.storedTensorVelocity;                        

                            //Updating the player to the latest received input
                            for (int i = 0; i < incomingMovesCount; i++)
                            {
                                Move incomingMove = inc.ReadMove();

                                Console.WriteLine("Updating player {0}", inc.SenderConnection.RemoteEndpoint);
                                player.Camera.Yaw = incomingMove.Yaw;
                                player.Camera.Pitch = incomingMove.Pitch;
                                player.CharacterController.Update(0.016f, incomingMove.Input);
                                player.Camera.Update(0.016f);
                                space.Update(0.016f);                                                              
                            }
                             //Freezing the player again
                            player.CharacterController.CharacterController.Body.IsAffectedByGravity = false;       
                            player.storedLinearVelocity = player.CharacterController.CharacterController.Body.LinearVelocity;
                            player.storedAngularVelocity = player.CharacterController.CharacterController.Body.AngularVelocity;
                            player.storedTensorVelocity = player.CharacterController.CharacterController.Body.LocalInertiaTensorInverse;
                            player.CharacterController.CharacterController.Body.BecomeKinematic();
This code works fine if only 1 player is in the server (i.e. if nothing else is updating the world space). However, if anything else updates the space (another player, or debugging and calling it on a keypress etc.) the 'frozen' player still moves.

Additionally, if I add this code to the 'Freezing' section above, it crashes with an NaN error upon calling the next space.Update():

Code: Select all

  player.CharacterController.CharacterController.Body.IsAffectedByGravity = false;
                            player.CharacterController.CharacterController.Body.AngularVelocity = Vector3.Zero;
                            player.CharacterController.CharacterController.Body.LinearVelocity = Vector3.Zero;                            
                            player.CharacterController.CharacterController.Body.CollisionInformation.CollisionRules.Personal 
                                = BEPUphysics.CollisionRuleManagement.CollisionRule.NoSolver;
Thanks for your help on the subject, I've tried everything I can think of :cry:
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Proper way to freeze / disable entity?

Post by Norbo »

Code: Select all

                             //Unfreezing the player
                            player.CharacterController.CharacterController.Body.BecomeDynamic(player.Mass);
                            player.CharacterController.CharacterController.Body.IsAffectedByGravity = true;
                            player.CharacterController.CharacterController.Body.LinearVelocity = player.storedLinearVelocity;
                            player.CharacterController.CharacterController.Body.AngularVelocity = player.storedAngularVelocity;
                            player.CharacterController.CharacterController.Body.LocalInertiaTensorInverse = player.storedTensorVelocity;   
Instead of setting the local inertia tensor inverse after the fact, just pass the local inertia tensor directly into the BecomeDynamic method to save computations.

Also, note that setting IsAffectedByGravity is not needed when freezing objects using the kinematic approach. Kinematic entities cannot be moved by forces of any kind; they have effectively infinite mass.
Additionally, if I add this code to the 'Freezing' section above, it crashes with an NaN error upon calling the next space.Update():
There's nothing in that chunk in isolation which should cause it to crash. I would assume it happens because of some external interaction. If you want to try narrowing it down, compile BEPUphysics with the CHECKMATH compilation symbol. It will insert NaN/Infinity checks to most common access points.

Also, adding that chunk (without further modifications to the existing code) would amount to a partial hybridization of the options #1 and #2 in my previous post- which isn't particularly useful.
However, if anything else updates the space (another player, or debugging and calling it on a keypress etc.) the 'frozen' player still moves.
A kinematic entity with zero velocity will not move unless told to. Likewise, a dynamic entity that cannot collide with anything, cannot be affected by gravity, and has zero velocity will not move unless specifically pushed into doing so. If something that is supposed to be 'frozen' moves around, it is not actually frozen- or it has been explicitly told to move.

It may also be worth reconsidering the architecture of the server depending on the nature of the simulation. Updating individual entities by freezing the rest of the simulation and running a bunch of space time steps is expensive and, unless there's really only one object moving at any given time, won't likely produce a better result than some simpler models.
ecosky
Posts: 69
Joined: Fri Nov 04, 2011 7:13 am
Contact:

Re: Proper way to freeze / disable entity?

Post by ecosky »

Hi,

I recently had a similar problem which I was able to solve with a fairly simple change in SimulationIslandSimulator.cs. Essentially, I added "bool IsAlwaysDeactivationCandidate" which is checked in UpdateDeactivationCandidacy and causes the instance to disregard velocity and timeouts when trying to deactivate. It has the effect of letting objects resolve collisions as expected, but they stop moving immediately afterward.

This is the closest thread I could find on the topic I was dealing with, so it seems like a fitting place to post this.

My game has a networking, streaming world, where objects are spawned on the client as directed by the host as players move around. They are placed exactly where they need to be, and having them activate just by being placed in the scene was causing timing problems with other objects and needless overhead. I don't want the objects to be kinematic either, they just need to be created without falling since sometimes their support objects appear after the object in question. If there's a better way to solve this problem, that would be good to know but this turned out to be a low cost solution for me. I've attached the file for diffing in case anyone wants the changes.

I think this idea could be expanded nicely with an enum instead of a bool to control how this behavior behaves when an object is activated by impacts from another object. Right now I have to manually clear this flag which is ok for my purposes but I can imagine this would be more useful if instead of a bool this was an enum with the following behaviors, and better names:

enum DeactivationBehavior
{
Normal, // current behavior
OneTime, // converts to Normal the first time this object hits another object
Always // always ignore velocity and timouts for deactivation
}

Thanks Norbo for such a useful engine, it's always fun to dig in and tweak it here and there.
Attachments
SimulationIslandMember.cs
(18.55 KiB) Downloaded 290 times
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Proper way to freeze / disable entity?

Post by Norbo »

If there's a better way to solve this problem, that would be good to know but this turned out to be a low cost solution for me.
Another way would be to handle entire simulation islands together. All the involved entities could be plopped in at once. If the source island was inactive, the whole group could then be deactivated together.

There is some trickiness involved in that last part, however. The entities must be forced into the same simulation island. The related systems are complicated enough that I can't remember off the top of my head if simply setting the SimulationIsland would be safe (it would need to be done with an internal modification regardless), or if forced island merging would be required, or if there are other details that I've forgotten.

Something like this approach will be used for our own purposes, so when I get around to it, the related systems should be cleaned up to make it easier to do externally.
ecosky
Posts: 69
Joined: Fri Nov 04, 2011 7:13 am
Contact:

Re: Proper way to freeze / disable entity?

Post by ecosky »

Handling source islands would be useful if possible but it's not a fit for my particular use case - there's no tracking of what might be loaded, or how many things, just that the things that get added to the world need to not move when they do get put in there, unless they happen to be penetrating another object in which case I want them to separate but deactivate as soon as they do to prevent objects from getting pushed any further from their spawn point than necessary.
Post Reply