Tuesday, April 22, 2014

"Sonar"


Sonar

This “Sonar” functionality allows users to test distances to the nearest objects. This helps users determine their distance from important objects. This function mimics the use of reverberation to calculate the proximity of objects. In the virtual world, we can convey this information even when the object is very far away.

Use case:

User is navigating room, attempting to follow wall. The user loses track of wall on right-hand side. The user continues navigating but becomes lost. The user suspects that they are moving towards the North wall, which is where the exit is. They query around themselves but no objects are within range. The user tries to find the wall by sending a “sonar” signal forward. After a short delay, they hear a “knock” coming back from the front. From experience, they associate this “knock” with an interior wall. The user estimates their distance from the wall based on the length of the delay. Comfortable that they have made progress towards the north wall, the user continues until they reach the wall, takes a right turn, and follows the wall to the exit.

Calculating Delay

Calculating the sound delay is a simple matter of determining the distance between the user and the object and accounting for the speed of sound. Where a and b are 3D points representing user and object positions:


        double dist = Math.sqrt( Math.pow((a.x - b.x ), 2) + Math.pow((a.y - b.y), 2) +                    Math.pow((a.z - b.z), 2) );;

        double delayAsSeconds = dist/speedOfSound * 2;
        double delayAsMilliseconds = delayAsSeconds * 1000;


The play thread is then qued with the appropriate delay and sound. The sound is always the one associated with the relevant object.

Tuesday, April 1, 2014

UI for Android: Touchscreen




I have createda gesture listener class to handle these.

You have to manually set what constitutes a "swipe"-- how far the user has to move their finger (both min and max). You have to set the speed at which they move their finger, so as not to conflate with a "scroll":
  private int swipe_Min_Distance = 100;
    private int swipe_Max_Distance = 800;
    private int swipe_Min_Velocity = 40;
Then you catch the probable swipe as a "fling." You make sure it's a swipe and determine its direction--manually setting the leeway.
@Override
    public boolean onFling(
        MotionEvent e1,
        MotionEvent e2,
        float velocityX,
        float velocityY)
    {
        final float xDistance = Math.abs(e1.getX() - e2.getX());
        final float yDistance = Math.abs(e1.getY() - e2.getY());

        if(xDistance > this.swipe_Max_Distance || yDistance > this.swipe_Max_Distance)
         return false;

        velocityX = Math.abs(velocityX);
        velocityY = Math.abs(velocityY);
              boolean result = false;

        if(velocityX > this.swipe_Min_Velocity && xDistance > this.swipe_Min_Distance){
         if(e1.getX() > e2.getX()) // right to left
          this.onSwipe(Globals.SWIPE_LEFT);
         else
          this.onSwipe(Globals.SWIPE_RIGHT);
         result = true;
        }
        else if(velocityY > this.swipe_Min_Velocity && yDistance > this.swipe_Min_Distance){
         if(e1.getY() > e2.getY()) // bottom to up
          this.onSwipe(Globals.SWIPE_UP);
         else
          this.onSwipe(Globals.SWIPE_DOWN);
         result = true;
        }
         return result;
    }
Have to differentiate between single taps, long presses and double taps:

 @Override
    public boolean onSingleTapConfirmed(MotionEvent e)
    {        float scaledX, scaledY;
        gs.touchCell(scaleX(e.getX()), scaleY(e.getY()), false);
        return true;
    }

 @Override
    public boolean onDoubleTapEvent(MotionEvent e)
    {
        gs.startListening();
        return true;
    }