Sort of a Math Question on Physics

I’m doing a top down 2d space fighter game. I made it top down and “2d” (i.e. movement is restricted to the xz plane) to try and keep things simple since this is my first project and I’m not crazy enough to attempt a MMORPG before I’ve even written pong hehe.



Anyway, I’m using the great new Physics Engine done by DP and Per and I’ve run into an implementation problem. When my ship collides with an object it bounces off and spins in all kinds of directions. Prior to swtiching to the new Physics System the ship would not spin and rotations were limited to around the Y axis (so you could not leave the xz plane).



Now however, the ship spins around after collisions and not just around the Y axis. Therefore after colliding the ship might be pointing in the Y or -Y direction which means when I apply a force the ship leaves the xz plane (hopefully that makes sense)



I decided that the spinning is so cool looking that I want to keep it and allow the ship to spin in every direction (after a collision). However, now I need a way to revert back to moving in the xz plane.



My current idea is this … After a collision let the ship do whatever it wants (it always stays in the xz plane right now because it is only colliding into flat surfaces) If any ship movement key is pressed (i.e. WASD) then 1) stop the ships rotation

2) Level the ship back to parallel with the xz plane.



Problem 1

#1 is easy since DP and Per made the Physics System so easy to use. I just setAngularVelocity to 0. #2 has got me stumped. Anyone know how I can rotate the ship back to being parallel with the xz plane but preserve the direction it was facing. More of a math question than anything else.



EDIT Problem 2: The ship does leave the xz plane upon collision. Its very minor but it does. I’m trying to think of a fix for that as well. I tried to set the linear velocity of the ship in the y direction to 0 after a collision but for some reason it still moves in the Y direction. Basically I need to restrict movement to the xz plane. Any ideas how to do this??[/b]

Ok, well, our physicsSystem was designed for 3d applications. However, that doesn’t mean that 2D shouldn’t be doable.



You basically have two options that i can see…



Option 1:

in the update method, the first thing you need to do before updating the physics is setting the localTranslation of the ship to be on the x-z plane. And then syncing the physicsobject with it.



So your method would look like:



public void update(float interpolation) {
  PhysicsWorld.getInstance().update();
  shipPhyObj.getjMEGeometry().getLocalTranslation().y = 0;
  shipPhyObj.syncWithGraphical(false);
  // do other stuff to do with physics...etc
}



Thats basically option 1.

Option 2
Option two is slightly harder to code but i think provides a more realistic approach to things. It also gives the player a true sense of 3D without the game being 3d.

Upon initing the PhysicsMethod, create a ContactAction method that detects for a collision to the ship. This monitors the position of the ship alogn the y plane. If it has gone off the y plane, then simply create a "SpatialTransformer" to move that ship back down smoothly down. Ofcourse make sure you sync the physics with graphics too.

This i believe is more reaslistic as it gives the player a sense of complication. The ship does have an onboard computer and it is doing something! ;)

Those are your options (if i haven't missed one out...) you chose which is best for you.

DP

Hiya DP,

This is what I’ve been trying but it doesn’t seem to work



       ContactAction shipContactAction = new ContactAction(shipObj) {
         
         public void onContact(PhysicsObject obj, Contact contact) {
             //This is definitely getting called
             System.out.println("Collision Baby!");
             Vector3f velocity = new Vector3f();
             shipObj.getLinearVelocity(velocity);
             velocity.y = 0;
             System.out.println(velocity);
            shipObj.setLinearVelocity(velocity);
         }
         
      };



I added an onContact function which should set the y velocity of the ship to 0 upon a collision. However, for some reason the ship manages to move in the y direction still. I would have thought this would be impossible given that there is no velocity in the y direction. *Edit:* Somehow the ship is still getting a y velocity eventhough I think I'm setting it to zero upon a collision.

By the way your first solution worked fine (looks good too) and I’ll probably stick with that. I should have thought of that myself ://



You wouldn’t happen to have any ideas in regards to the other problem would you?


Problem 1
#1 is easy since DP and Per made the Physics System so easy to use. I just setAngularVelocity to 0. #2 has got me stumped. Anyone know how I can rotate the ship back to being parallel with the xz plane but preserve the direction it was facing. More of a math question than anything else.


Basically after a collision I want to let the ship flip/rotate around in any direction (restricted to the xz plane) but upon pressing any ship movement keys the ship "magically" rights itself to being parallel to the xz plane and still facing whatever direction it was facing.

You would have to store the directional matrix of the ship before collision and update it every frame. Then when a collision occurs, stop setting it to the local Rotation of the object by a simple boolean value.



When the player presses the key, peform the rotation, and set that boolean value to update again.



Is that kinda clear? cause it seems fuzzy to me and thats the only way i can explain it to you…



DP

Makes sense but I think it would only work halfway.



If you store the rotation matrix right before the collision then upon a player pressing a key you apply the saved rotation matrix the ship would indeed return to “pointing” parallel to the xz matrix. The problem is the ship will also change directions to whatever direction the ship was going prior to the collision. This could be exactly opposite to the direction the ship is currently facing and would look really odd. The ship would just flip directions.



I’m trying to come up with a way where you level the ship with xz plane but keep it’s current heading.

hehehe, use a SpatialTransformer to do that. Spatital transformers transform location/rotation/scaling across a time path.



So it will smoothly change the direction of your ship to face the saved direction.



I suggest you read up on the javadocs/tutorials regarding SpatialTransformer. Its very useful.



DP

That wouldn’t work either because then you effectively can’t control your ship while it’s rotating to face the new direction.



I hate these stupid math problems heh.

oh no, you can!



Keep the spatial transformer going. Basically, all your translation/rotation go through the spatial transformer before going onto the actual spatial. This way, the person can keep on rotating and the spatial transformer will keep everything smooth.



Ok, take it this way. Say the spatialTransformer has to rotate the object 2 degrees in 10 seconds. All of a sudden, the player rotates this more to the right, so it has to rotation 9.8 degrees in 10 seconds. The player keeps pressing so its 20 degrees in 9.6 seconds. That means it has to spead up to compensate. So it starts to give more rotations/tick to the spatial. And i belive it does this…



I am overexagurating btw…It would never be 10 seconds, maximum would be half a second or something like that…and the angle would be alot more then 2 degrees…



But thats the idea. Hope that helps



DP

Here’s my line of thinking right now


  1. Get the z and x component of the direction vector for the ship.

    a) How do we get this?

    i) Could I create a vector (0,0,1) then multiply this by the current rotation matrix to get a direction vector in the xz plane? Not sure if that would work


  2. So supposing I have a direction vector which is parallel to the xz plane. Then I could apply the old rotation matrix I saved. This would put the ship parallel to the xz plane.


  3. Then I need to rotate the ship to face in the same direction as the direction vector I found in step 1. Not sure how to do this yet.

Hmm would something like this work.

take the x and z rotation (column 0 and 2) out of the rotation matrix and then set the y rotation to 0?



so …



x1–0--z1

x2–1--z2

x3–0--z3



Would that work? man … I should have paid more attention in lin alg.

yes, that would work. But you can optimise that even furthur. Since coloumn 1 only going to contain 1 float which is at the top. Coloumn 2 is the y (middle value) and coloumn 3 is the lower most. You can effectively obtain a Vector3f and call that a direction…



But thats too complex and probably is easier to keep it in a matrix form:



x1–00–00

00–01–00

00–00–z3



And that would be your direction…



Who cares about classes…the internet has everything! :wink:



DP

Why can


Who cares about classes...the internet has everything!

hahahah true dat.

Let me give this a shot tonight. Gonna go grab some dinner. Oh ... by the way, did i tell you how awesome the PhysicsEngine is :D

I think you should have a sticky at the top of the physics forum with information about the library and maybe a known bug list and a link to the bleeding edge jar file. For someone who doesn't troll the forums like I do they'll probably miss a lot of the information on the library that's hidden deep within some of the threads.

I am not a moderator. Mojo is. When we release a new physics system, it will be on the front page! :smiley:



Yes, you have told me how great the physics stuff is. And to be honest, i am very humbled! :// Its the best feeling in the world to know that something you made makes other people happy! Hehe



DP

Did you get this working? Because when reading the original question (how to reset the y rotation while keeping x and z) this is what came into mind:



Say ship is your PhysicsObject…



// Get the old direction as a Vector3f.
Vector3f direction = new Vector3f();
ship.getjMEGeometry().getLocalRotation().getRotationColumn(0, direction);
ship.getjMEGeometry().getLocalRotation().getRotationColumn(1, direction);
ship.getjMEGeometry().getLocalRotation().getRotationColumn(2, direction);

// Reset y.
direction.y = 0;
direction.normalize();

// Convert back to a Quaternion.
Quaternion dirQuat = new Quaternion(new float[] {direction.x, direction.y, direction.z}));

// Apply all the newness.
ship.getjMEGeometry().setLocalDirection(dirQuat);
ship.syncWithGraphical(false);



Note: math is not one of my skills, and I havn't tested this or anything :)

You do realise when doing this:



ship.getjMEGeometry().getLocalRotation().getRotationColumn(0, direction);
ship.getjMEGeometry().getLocalRotation().getRotationColumn(1, direction);
ship.getjMEGeometry().getLocalRotation().getRotationColumn(2, direction);



the information is stored onto the vector and not added/multiplied?

so at the end of all that, the x value is 0, the y value is 0 and the z value is the direction in the z...

Just thought id point that out. But the idea is sound tho...

DP

Here’s what I’ve been doing which is kind of working but I think I want to improve on it.


    public void performAction(InputActionEvent evt) {
       //If we are in a collision make the ship level to the xz plane by resetting y rotation axis
        if(((ShipModel)shipObj.getjMEGeometry()).inCollision == true){
            ((ShipModel)shipObj.getjMEGeometry()).inCollision = false;
            Matrix3f rotMatrix = new Matrix3f(shipObj.getjMEGeometry().getLocalRotation().toRotationMatrix());
            rotMatrix.m01 = 0;
            rotMatrix.m11 = 1;
            rotMatrix.m21 = 0;
            rotMatrix.m10 = 0;
            rotMatrix.m20 = 0;
            rotMatrix.m02 = 0;
            rotMatrix.m12 = 0;
            shipObj.getjMEGeometry().setLocalRotation(rotMatrix);
            //Remove any spinning
            shipObj.setAngularVelocity(new Vector3f(0,0,0));
            System.out.println(rotMatrix);
        }
       incr.loadIdentity();
        if (lockAxis == null) {
            incr.fromAxisAngle(shipObj.getjMEGeometry().getLocalRotation().getRotationColumn(1,
                    tempVa), -speed * evt.getTime());
        } else {
            incr.fromAxisAngle(lockAxis, -speed * evt.getTime());
        }
        shipObj.getjMEGeometry().getLocalRotation().fromRotationMatrix(
                incr.mult(shipObj.getjMEGeometry().getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        shipObj.getjMEGeometry().getLocalRotation().normalize();
        shipObj.syncToGraphical(false);
      }



I noticed I didn't normalize the rotation matrix after setting most of the values to zero. Let me try Per's code and see if I get a better result.

Well I tried Per’s code (slightly modified) and it didn’t work. Maybe I’m doing something wrong here.



            Vector3f columnX = new Vector3f();
            Vector3f columnZ = new Vector3f();
                       
            shipObj.getjMEGeometry().getLocalRotation().getRotationColumn(0, columnX);
            shipObj.getjMEGeometry().getLocalRotation().getRotationColumn(2, columnZ);
            Vector3f direction = new Vector3f(columnX.x,0,columnZ.z);
           
            direction.normalize();
            Quaternion dirQuat = new Quaternion(new float[] {direction.x, direction.y, direction.z});
            shipObj.getjMEGeometry().setLocalRotation(dirQuat);



For one there is no setLocalDirection() method so I assumed you meant setLocalRotation??

Also, I assumed that getRotationColumn returned the vector3f of the column you were asking for. So we need to ask for column 0 and column 2 (x and z). Then we want the first value in column 0 and the third value in column 2.

x0
y0
z0
x1
y1
z1
x2
y2
z2

So we grab x0, and z2 then create a vector3f(x0,0,z2) and use that to make the quternion.

One thing I noticed is that x1,x2,z0 and z1 are not zero. I beleive DP said they should all be zero so you only need the diagonal values (x0,y1,z2) to get it to work.

Not sure if that sheds some light on anything. Thanks for all the help so far.

Haha DP, you are absolutely right. I copy-pasted that snippet from a method I wrote a long time ago. It served its purpose since only the last call was needed :// :slight_smile:



About the problem I think it needs a person with a somewhat deeper understanding of the math classes (I’m just learning myself)… I can’t believe this problem would be hard to crack.