FrictionCallback

Here's a preliminary copy of my FrictionCallback I'm working on.  Any criticism or requests for features let me know.  I haven't really had much time to test, I'm about to run to bed but wanted to get some feedback.  I'll be working on this tomorrow night so if nobody responds it's not a big deal. :o


/*
 * Copyright (c) 2005-2006 jME Physics 2
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 *  * Neither the name of 'jME Physics 2' nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.jmex.physics.callback;

import java.lang.ref.*;
import java.util.*;
import java.util.concurrent.*;

import com.jme.math.*;
import com.jmex.physics.*;

/**
 * FrictionCallback provides features to apply friction per step for a DynamicPhysicsNode.
 * This class is thread-safe.
 *
 * @author Matthew D. Hicks
 */
public class FrictionCallback implements PhysicsUpdateCallback {
   private ConcurrentLinkedQueue<FrictionEncapsulation> nodes;
   
   public FrictionCallback() {
      nodes = new ConcurrentLinkedQueue<FrictionEncapsulation>();
   }
   
   public boolean add(DynamicPhysicsNode node, float forceFriction, float angularFriction) {
      return nodes.add(new FrictionEncapsulation(node, forceFriction, angularFriction));
   }
   
   public void afterStep(PhysicsSpace space, float time) {
      Iterator<FrictionEncapsulation> iterator = nodes.iterator();
      FrictionEncapsulation fe;
      while (iterator.hasNext()) {
         fe = iterator.next();
         if (!fe.call(space, time)) {
            iterator.remove();
         }
      }
   }

   public void beforeStep(PhysicsSpace space, float time) {
   }
}

class FrictionEncapsulation {
   private static Vector3f store = new Vector3f();
   
   private WeakReference<DynamicPhysicsNode> node;
   private float forceFriction;
   private float angularFriction;
   
   public FrictionEncapsulation(DynamicPhysicsNode dpn, float forceFriction, float angularFriction) {
      this.node = new WeakReference<DynamicPhysicsNode>(dpn);
      this.forceFriction = forceFriction;
      this.angularFriction = angularFriction;
   }
   
   public boolean call(PhysicsSpace space, float time) {
      DynamicPhysicsNode dpn = node.get();
      if (dpn == null) return false;
      
      if (forceFriction != 0.0f) {
         dpn.getForce(store);
         float change = forceFriction * time;
         applyFriction(change);
         dpn.clearForce();
         dpn.addForce(store);
      }
      if (angularFriction != 0.0f) {
         dpn.getAngularVelocity(store);
         float change = angularFriction * time;
         applyFriction(change);
         dpn.setAngularVelocity(store);
      }
      
      return true;
   }
   
   private void applyFriction(float change) {
      if (store.x > 0.0f) {
         store.x -= change;
         if (store.x < 0.0f) store.x = 0.0f;
      } else if (store.x < 0.0f) {
         store.x = store.x + change;
         if (store.x > 0.0f) store.x = 0.0f;
      }
      if (store.y > 0.0f) {
         store.y = store.y - change;
         if (store.y < 0.0f) store.y = 0.0f;
      } else if (store.y < 0.0f) {
         store.y = store.y + change;
         if (store.y > 0.0f) store.y = 0.0f;
      }
      if (store.z > 0.0f) {
         store.z = store.z - change;
         if (store.z < 0.0f) store.z = 0.0f;
      } else if (store.z < 0.0f) {
         store.z = store.z + change;
         if (store.z > 0.0f) store.z = 0.0f;
      }
   }
}

I wonder how many people are working on spacebased games right now… at least 3 right in this thread. :wink:



And yeah, EL, thats pretty much what I was implying without being semi-specific!

@thzero, if you're saying that you're working on a space game as well, then that would technically be four since Irrisor has a space game as well (I think it's not currently being maintained at the moment though). :-p

That's right, I've seen the screenies… looks nice.:slight_smile:

Well I might use this, but only when in atmosphere, space is frictionless… <shakes fist>



Looks fine, though so far.



:smiley:

EmperorLiam said:

space is frictionless... <shakes fist>


Not quite, no, but close enough for most purposes... :)

Deep space has virtually no matter… and in solar systems the solar winds push out from the star.  Nebulas are not thick with matter, they only are visible (well, their shadow is) when viewed from very far away and are extremely sparse in matter.  ER from stars has more force on an object in deep space than matter. 



If I could think of a better name for DarkFrog to call this, I'd bug him to use that.  For my game, ships will require omini-directional thrusters to stabilize their ship… in reality it would be the same code but take thruster fuel and power into account and also give you the option of not stabilizing. 



I just want clipping an asteroid to send you spinning out of control so that it takes skill to pilot.  Lol, people are going to find my game  so frustrating!



Hmmm, StabalizeCallback and StabalizeEncapsulation…






err, does that forceFriction stuff work? I doubt it. And if it would - does it even make sense to have a 'friction' which reduces forces?

Yeah, right after I went to bed last night I realized that the addForce after clearForces is probably silly considering I should addForce to negate the current force instead of just taking the current force, modifying it, clear it, then reapply the modified.  I would expect this will work, but not very efficiently.  I'll fix that tonight and after I've tested it I'll get it checked in.



@EmperorLiam, yes, I could make my space game as realistic as possible but I want the game to be FUN.  :P  I may add extra features in the future to add more realism if I can do it in a way that doesn't detract from the enjoyment of the game, but at this point I'll be happy with getting something finished and released.  :wink:

Okay, fixed some bugs from my untested version above and created a test for it in the interactive tests.  This is all checked in.

What about naming this VelocityDamper (or similar) instead. It's not really friction. And the parameter and field really should not be called forceFriction but linearFriction/Damping.

That sounds good…I agree that the naming should be changed…I'll have a look this evening.



On a side-note, how did you go about creating throttle controls in your game?  I'm trying to modify my throttle controller to work with physics but it's become a lot more complicated now that I have to accommodate other forces as well.

throttle controls? what exactly do you mean? I applied forces for each thruster on the ship at the thrusters position, into the same direction like the thruster. Then I recorded the effect of each thruster and triggered the thrusters according to the recorded data and the desired (rotational/linear) velocity of the ship…

But if the thruster keeps applying force how do you keep it from going too fast?



If I addForce(0.0f, 0.0f, 50.0f) consistently I'll be going faster than the speed of light eventually, right? :o

darkfrog said:

But if the thruster keeps applying force how do you keep it from going too fast?

I did not :)
Actually the controller input was only allowing to specify an absolute speed, so this was not an issue.
But if you want to restrict it to e.g. light speed you can simply apply less force with raising speed - nearly like in reality :) (probably you want to have less speed, though)
Additionally the shield was penetrated by space durst at high speeds, to prevent the user from speeding ;)
irrisor said:

Additionally the shield was penetrated by space durst at high speeds, to prevent the user from speeding ;)


If that's anything like Fred Durst I can see why it worked!  :P
irrisor said:

I did not :)
Actually the controller input was only allowing to specify an absolute speed, so this was not an issue.


Can't you just track the linear and angular velocity of an object when performing the callbacks, and if the force from the controller is 0, then just reapply the velocities to the object? 

Thats what I was doing when I was working with the NewtonGameDynamics engine (via .NET before HD crashed) instead.

I add friction to a rolling ball, and it slows down.



it doesn't seem to matter whether I use rolling or sliding (angular or velocity based) friction (using both at the moment - just in case), but it never actually stops



I don't know why - can't figure it out.



Another weird thing is that the time constant passed in always seems to be 0.1 … regardless of framerate (1/tpf, right?). although it seems to behave consistently.



I thought it could be with float zero approximations, but your code should handle that… any ideas?

ebola said:

Another weird thing is that the time constant passed in always seems to be 0.1 ... regardless of framerate (1/tpf, right?). although it seems to behave consistently.

That's ok, it is called for each physics step. These steps have the same length.

Darkfrog any ideas on the problem with not stopping?

Not sure, I just glanced at the code and it seems pretty straight-forward, but it was a while back that I wrote this.  Do you perhaps have anything else that's applying force to it?  Is it possible that gravity is effecting you as well and providing more force than the friction callback is?



Try increasing the friction and see if that helps.