// Path: src/main/java/com/simsilica/sim/SimTime.java
// public class SimTime {
//     private long frame;
//     private long lastRealTime;
//     private boolean rebase;
//     
//     /**
//      *  gameTime is the 0-based 'game time' that is adjusted based on
//      *  the advancement of 'real time' provided by update().
//      */
//     private long gameTime;
//     
//     private double tpf;
//     private double invTimeScale = 1000000000.0; // nanos  
//     private double timeScale = 1.0 / invTimeScale;
//     
//     public SimTime() {
//     }
// 
//     public void update( long realTime ) {
//         long timeDelta;
//         if( frame == 0 || rebase ) {
//             timeDelta = 0;
//             rebase = false;
//         } else {
//             timeDelta = realTime - lastRealTime;
//         }
//         lastRealTime = realTime;
//         
//         frame++;
//         tpf = timeDelta * timeScale;
//         this.gameTime += timeDelta;
//     }
//  
//     /**
//      *  Returns the SimTime version of the specified timestamp that
//      *  is compatible with what would normally be provided to update().
//      *  SimTime.getTime() will provide 'frame locked' timestamps that will
//      *  not update during a frame which is what the systems will want 99.99%
//      *  of the time.  Rarely it is desirable to get a "real" timestamp that 
//      *  is not locked to frames, usually as part of providing matching accurate
//      *  timesource information to something else that is trying to synch.
//      */   
//     public long getUnlockedTime( long realTime ) {
//         // Figure out what time would be if realTime were
//         // passed to update.
//         long timeDelta;
//         if( frame == 0 || rebase ) {
//             timeDelta = 0;
//         } else {
//             timeDelta = realTime - lastRealTime;
//         }
//         return gameTime + timeDelta;
//     }
//  
//     public long toSimTime( double seconds ) {
//         return (long)(seconds * invTimeScale);
//     }
//  
//     public long getFutureTime( double seconds ) {
//         return gameTime + toSimTime(seconds); 
//     }        
//     
//     public final double getTpf() {
//         return tpf;
//     }
//     
//     public final long getFrame() {
//         return frame;
//     }
//     
//     public final long getTime() {
//         return gameTime;
//     }
//     
//     /**
//      *  Force the game time to a certain value.  Note that going backwards while
//      *  systems are running may have undesirable effects.  
//      *  The next immediate call to getTime() will return the specified value.
//      *  If update() is called then getTime() will return this value plus whatever
//      *  time has passed since the last time update() was called.
//      *  This is primarily used as a way for games to preset the game time to
//      *  some known value, say when restoring a saved game or a persistent world.
//      */
//     public final void setCurrentTime( long time ) {
//         this.gameTime = time;
//         this.rebase = true;
//     }
//     
//     public final double getTimeInSeconds() {
//         return gameTime * timeScale;
//     }
//     
//     public final double getTimeScale() {
//         return timeScale;
//     }
//  
//     public final long addMillis( long ms ) {
//         return gameTime + ms * 1000000L;
//     }
//  
//     @Override   
//     public String toString() {
//         return getClass().getSimpleName() + "[tpf=" + getTpf() + ", seconds=" + getTimeInSeconds() + "]";
//     }
// }


import java.util.Random;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.math.*;
import com.simsilica.es.*;
import com.simsilica.sim.SimTime;
import com.simsilica.bullet.*;

    protected float calculateWanderSteer() {
        // We do this by imagining a wheel in front of us that randomly
        // turns left or right... we will steer towards wherever the 0 degree
        // mark on the wheel happens to be in our field of view.
        float volatility = 0.4f;
        headingAngle += random.nextFloat() * volatility - (volatility * 0.499);
        while( headingAngle > FastMath.TWO_PI ) {
            headingAngle -= FastMath.TWO_PI;
        }
        while( headingAngle < -FastMath.TWO_PI ) {
            headingAngle += FastMath.TWO_PI;
        }
         
        float sin = FastMath.sin(headingAngle);
        float cos = FastMath.cos(headingAngle);
        
        // Project it in front of us some distance
        // The farther out, the less dramatic turning will be
        cos += 10f; 
 
        // The heading is imaginary and already in local space...
        Vector3f heading = new Vector3f(sin, 0, cos).normalizeLocal();
        //Vector3f left = Vector3f.UNIT_X;
        
        //System.out.println("Steer:" + heading.x + "  headingAngle:" + headingAngle + "   heading:" + heading);
        
        return heading.x; //heading.dot(left);        
    }
          
    @Override

// Path: src/main/java/com/simsilica/sim/SimTime.java
// public class SimTime {
//     private long frame;
//     private long lastRealTime;
//     private boolean rebase;
//     
//     /**
//      *  gameTime is the 0-based 'game time' that is adjusted based on
//      *  the advancement of 'real time' provided by update().
//      */
//     private long gameTime;
//     
//     private double tpf;
//     private double invTimeScale = 1000000000.0; // nanos  
//     private double timeScale = 1.0 / invTimeScale;
//     
//     public SimTime() {
//     }
// 
//     public void update( long realTime ) {
//         long timeDelta;
//         if( frame == 0 || rebase ) {
//             timeDelta = 0;
//             rebase = false;
//         } else {
//             timeDelta = realTime - lastRealTime;
//         }
//         lastRealTime = realTime;
//         
//         frame++;
//         tpf = timeDelta * timeScale;
//         this.gameTime += timeDelta;
//     }
//  
//     /**
//      *  Returns the SimTime version of the specified timestamp that
//      *  is compatible with what would normally be provided to update().
//      *  SimTime.getTime() will provide 'frame locked' timestamps that will
//      *  not update during a frame which is what the systems will want 99.99%
//      *  of the time.  Rarely it is desirable to get a "real" timestamp that 
//      *  is not locked to frames, usually as part of providing matching accurate
//      *  timesource information to something else that is trying to synch.
//      */   
//     public long getUnlockedTime( long realTime ) {
//         // Figure out what time would be if realTime were
//         // passed to update.
//         long timeDelta;
//         if( frame == 0 || rebase ) {
//             timeDelta = 0;
//         } else {
//             timeDelta = realTime - lastRealTime;
//         }
//         return gameTime + timeDelta;
//     }
//  
//     public long toSimTime( double seconds ) {
//         return (long)(seconds * invTimeScale);
//     }
//  
//     public long getFutureTime( double seconds ) {
//         return gameTime + toSimTime(seconds); 
//     }        
//     
//     public final double getTpf() {
//         return tpf;
//     }
//     
//     public final long getFrame() {
//         return frame;
//     }
//     
//     public final long getTime() {
//         return gameTime;
//     }
//     
//     /**
//      *  Force the game time to a certain value.  Note that going backwards while
//      *  systems are running may have undesirable effects.  
//      *  The next immediate call to getTime() will return the specified value.
//      *  If update() is called then getTime() will return this value plus whatever
//      *  time has passed since the last time update() was called.
//      *  This is primarily used as a way for games to preset the game time to
//      *  some known value, say when restoring a saved game or a persistent world.
//      */
//     public final void setCurrentTime( long time ) {
//         this.gameTime = time;
//         this.rebase = true;
//     }
//     
//     public final double getTimeInSeconds() {
//         return gameTime * timeScale;
//     }
//     
//     public final double getTimeScale() {
//         return timeScale;
//     }
//  
//     public final long addMillis( long ms ) {
//         return gameTime + ms * 1000000L;
//     }
//  
//     @Override   
//     public String toString() {
//         return getClass().getSimpleName() + "[tpf=" + getTpf() + ", seconds=" + getTimeInSeconds() + "]";
//     }
// }


// Path: demos/bullet/src/main/java/com/simsilica/demo/bullet/WanderDriver.java
import java.util.Random;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.math.*;
import com.simsilica.es.*;
import com.simsilica.sim.SimTime;
import com.simsilica.bullet.*;

    protected float calculateWanderSteer() {
        // We do this by imagining a wheel in front of us that randomly
        // turns left or right... we will steer towards wherever the 0 degree
        // mark on the wheel happens to be in our field of view.
        float volatility = 0.4f;
        headingAngle += random.nextFloat() * volatility - (volatility * 0.499);
        while( headingAngle > FastMath.TWO_PI ) {
            headingAngle -= FastMath.TWO_PI;
        }
        while( headingAngle < -FastMath.TWO_PI ) {
            headingAngle += FastMath.TWO_PI;
        }
         
        float sin = FastMath.sin(headingAngle);
        float cos = FastMath.cos(headingAngle);
        
        // Project it in front of us some distance
        // The farther out, the less dramatic turning will be
        cos += 10f; 
 
        // The heading is imaginary and already in local space...
        Vector3f heading = new Vector3f(sin, 0, cos).normalizeLocal();
        //Vector3f left = Vector3f.UNIT_X;
        
        //System.out.println("Steer:" + heading.x + "  headingAngle:" + headingAngle + "   heading:" + heading);
        
        return heading.x; //heading.dot(left);        
    }
          
    @Override

    public void update( SimTime time, EntityRigidBody body ) {
