Prevent wobbling

Hi, I was following the wiki’s HelloPhysics tutorial (https://jmonkeyengine.github.io/wiki/jme3/beginner/hello_physics.html) and when I hit play, the bricks that constitute the wall wobbles for few seconds before it stabilises.
Is there a way to make the bricks stabilise as soon as the game loads? I tried bulletAppState.getPhysicsSpace().update(3f) but it just made the bricks more wobbly in the beginning.
Or if that is not possible, can you make it so that the physics for the bricks don’t update until something (e.g., a cannon ball in the example) collides with it?
Thank you.

1 Like

There probably might be better solutions but this is what came into my mind first:
When creating the RigidBodyControls for the wall you set kinematic to true. You also have to save your wall in a list or so. Then when the cannon ball hits the wall you go through every RigidBodyControl and set kinematic back to false.

However, as I said, there might be simpler approaches. I also don’t know if that what I described will affect the physics behavior in some kind. It would be cool if you please tell me if it worked for you :slight_smile:

This is a well known problem of physics engines. It rises because the constraints solver can only compare two objects and not the whole wall in one step. There are some great resources but I can explain it tomorrow in more detail if you are interested.

The approach of @Dominik has one downside. You have an unrealistic behaviour of the ball because it won’t go through the wall. It will always be “reflected” even though you have a paper wall and a stone ball because the wall is at the time of the contact a kinematic object. You also have to add the impulses manually to the bricks…

I would try to send the objects to sleep after launch by setting a high sleepThreshold. At the contact they will automatically be activated. Then you can reset the sleepThreshold. You can also play with “bumpyness” or something like that and other values to reduce the effect.

Getting the physics right needs lots of fine tuning. Good luck :slight_smile:

2 Likes

Thanks. I will try the method tomorrow.
However, I am kind of sceptical of that method since I actually tried setting the masses of bricks to 0 before adding them to the PhysicsSpace, then setting them back to 2f after adding them, and strangely enough the wall did not react to the ball at all.

Bullet has a concept of an “active” and an “inactive” object. When it detects that an object is no longer moving, it will deactivate it so that it is no longer processed, thus improving performance when there are many stationary objects in the scene. One way of preventing this wobbling is to just mark all the bricks as inactive, then until something actually hits them, they will not wobble. Unfortunately, jME exposes the function to activate an object, RigidBodyControl.activate(), but the function to deactivate an object is not exposed…

I don’t know what this is for but a hack of sorts is to set accuracy to a crazy number when initializing,

bulletAppState.setDebugEnabled(true);
bulletAppState.getPhysicsSpace().setAccuracy(1f / 240f);

Use a Boolean and after first shot is fired set accuracy back to default in actionListener,

           if (name.equals("shoot") && !keyPressed) {
                if (reset) {
                    bulletAppState.getPhysicsSpace().setAccuracy(1f / 60f);
                    reset = false;
                }
                makeCannonBall();
            }

If you shoot before the bricks become inactive the first time after initialization (about 2 seconds), as Momoko_Fan describes, then the motion caused by the controls “pushing” each other away will show.

The amount of motion decreases the closer you are to the initial timeout, with no motion after initial timeout.

Thanks for the answer. Unfortunately, when I tried to set the sleeping threshold of my RigidBodyControl, I get an exception:
Sep 19, 2017 12:38:59 AM com.jme3.app.LegacyApplication handleError
SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.NullPointerException: The native object does not exist.
at com.jme3.bullet.objects.PhysicsRigidBody.setSleepingThresholds(Native Method)
at com.jme3.bullet.objects.PhysicsRigidBody.setSleepingThresholds(PhysicsRigidBody.java:600)
at jmonks.tutorial.HelloPhysics.createWall(HelloPhysics.java:94)
at jmonks.tutorial.HelloPhysics.initObjects(HelloPhysics.java:67)
at jmonks.tutorial.HelloPhysics.simpleInitApp(HelloPhysics.java:50)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
at java.lang.Thread.run(Thread.java:745)

:frowning:
It would be nice if there was a way to precalculate all the physics so that when the game starts the wobbling would have stopped.

A bit late for you but the method is called setSleepingThresholds. It belongs to RigidBodyControl or PhysicsRigidBody depending on your usecase. It is somehow a dirty workaround to deactivate objects to get a behavior as Momoko_Fan has explained. A deactivate function would be a lot better suited here…

Sorry I am not using the RigidBodyControl and I’m not seeing your code but I guess you have to add it to the PhysicSpace or something like that first. (just a wild guess). Maybe you have to switch the order of your commands. I guess the native object isn’t initialized when you call the method.

I adapted your answer to change the accuracy back to 1/60f once a ball hits any brick.
I added a PhysicsCollisionListener to achieve this.
Seems to work okay. Here’s my code:

@Override
public void collision(PhysicsCollisionEvent pce) {
    if (!physicsAccuracyNormalised) {
        String nodeAParentName = pce.getNodeA().getParent().getName();
        String nodeBParentName = pce.getNodeB().getParent().getName();

        if (nodeAParentName.equals("n_Cannon Ball") && nodeBParentName.equals("n_Bricks") 
            || nodeAParentName.equals("n_Bricks") && nodeBParentName.equals("n_Cannon Ball"))
        {
            bulletAppState.getPhysicsSpace().setAccuracy(1/60f);
            physicsAccuracyNormalised = true;
        }
    }
}

Initially the accuracy of the PhysicsSpace was set to 1/240f as suggested.
Thank you for helping me solve the issue! Though I will not mark this question solved should better solutions arise.