Wednesday, 5 January 2011

Defining the route path between two points in 2D coordination system and Java implementation

I currently develop a 2D ball game for Android OS therefore this computing is important for the game to define the ball’s route in the game. In Android OS, there is a TranslateAnimation class to fulfil the Translate operation (changing the X, Y coordinates of an instance of a View class) but TranslateAnimation class does not supply the information of the animated object’s current x, y coordinate state. In my game, the ball’s place in time is important to take action according to its location. Therefore, I developed my own Extended TranslateAnimation class.

***The Algorithm***

I divide the animation operation in to two parts. First part is path resolving between the destination and the source points and the second part is animating the instance of a View class (animated object) and displaying it on the screen graphically. This article explains the path resolving operation which’s algorithm is below.

The figure below shows the representation of the destination(X1, Y1) and the source (X0, Y0) points. Red line (hypotenuse) shows the full path between points, green line shows the base and blue line shows the leg of the right triangle. The aim is, from the point 0 to point 1 if the animated object moves long as “d” on the redline (hypotenuse), what will be the new location on 2D plane( the “x, y” value of the very top and left had side of the plane is “0, 0” and it increases to the bottom right hand side). If it was calculated this new location’s coordinates, it would be set to the animated object’s location and the object would move to there.

clip_image001

The step by step algorithm is defined below for “d” distance.

1. Get little hypotenuse length (hypo=d)

2. Calculate the length of Hypotenuse (RealHypo)

3. Find Tan α = Blue Line/ Green Line

4. Find the α angle (use ArcTan)

5. Calculate the Cos α and Sin α values

Until here, we know the Cos α and Sin α values so we can calculate the base and leg length of the small right triangle which’s hypotenuse is “d” and top point is X0, Y0. So we just need to find the coordinate of the other tip of “d” (X’, Y’).

6. Find the difference between X0 – X’ = d*Cos α

7. Find the difference between Y0 – Y’ = d*Sin α

8. Subtract/Add these differences to X0 and Y0 According to the equations in step 5-6.

9. hypo=hypo+d

X’ = X0 - d*Cos α

Y’ = Y0 - d*Sin α

That’s all. One important note is Subtract/Add option changes according to the movement of the animated object therefore the direction calculation should be computed in step 7 as well.

Code

Full Java Code (VectoralPathResolver) is added below.

VectoralPathResolver.java

   1: package aliolci.CrazyBall;
   2: /*
   3:  * By Ali Olcay SAHIN 
   4:  * www.aliolci.com
   5:  * aliolci@gmail.com
   6:  * Thank you for using it.
   7:  * */
   8: import java.util.ArrayList;
   9: import java.util.List;
  10:  
  11: import android.graphics.PointF;
  12:  
  13: public class VectoralPathResolver {
  14:     private float FromXDelta, ToXDelta, FromYDelta, ToYDelta;
  15:     private float d =(float) 0.1;//sensitivity
  16:     private float realHypo;
  17:     private float hypo;
  18:     private double TanAngle;
  19:     private double cosValue;
  20:     private double sinValue;
  21:     private byte signX;
  22:     private byte signY;
  23:     public VectoralPathResolver(float fromXDelta, float toXDelta,
  24:             float fromYDelta, float toYDelta) {
  25:         FromXDelta = fromXDelta;
  26:         ToXDelta = toXDelta; 
  27:         FromYDelta = fromYDelta;
  28:         ToYDelta = toYDelta;
  29:         
  30:         realHypo = (float) Math.sqrt(Math.pow(FromXDelta-ToXDelta, 2)+Math.pow(FromYDelta-ToYDelta, 2));
  31:         hypo =0;
  32:         TanAngle = Math.atan((ToYDelta-FromYDelta)/(ToXDelta-FromXDelta));
  33:         cosValue =Math.cos(TanAngle);
  34:         sinValue =Math.sin(TanAngle);
  35:         signX = (byte) (Integer.signum((int) (ToXDelta-FromXDelta))<0?-1:1);
  36:         signY = (byte) (Integer.signum((int) (ToYDelta-FromYDelta))<0?-1:1);
  37:     }
  38:     public List<PointF> ResolveReturnFullPath()
  39:     {
  40:         List<PointF> path= new ArrayList<PointF>();
  41:         PointF f;
  42:         do
  43:         {
  44:             f=this.Next();
  45:             if(f!=null)
  46:                 path.add(f);
  47:         }
  48:         while(f!=null);
  49:         
  50:         return path;
  51:     }
  52:     public void setSensitivity(float sensitivity)
  53:     {
  54:         d=sensitivity;
  55:     }
  56:     public PointF Next()
  57:     {
  58:         if(realHypo>hypo)
  59:         {
  60:             hypo+=d;
  61:             float Xnew = (float)(cosValue*hypo*signX)+FromXDelta;
  62:             float Ynew =(float)(sinValue*hypo*signY)+FromYDelta;
  63:             return new PointF(Xnew,Ynew);
  64:         }
  65:         else
  66:             return null;
  67:     }
  68:     public PointF Next(int HowMuchEachTime)
  69:     {
  70:         if(realHypo>hypo)
  71:         {
  72:             hypo+=d*HowMuchEachTime;
  73:             float Xnew = (float)(cosValue*hypo*signX)+FromXDelta;
  74:             float Ynew =(float)(sinValue*hypo*signY)+FromYDelta;
  75:             return new PointF(Xnew,Ynew);
  76:         }
  77:         else
  78:             return null;
  79:     }
  80:     public void reset()
  81:     {
  82:         hypo=0;
  83:     }
  84:     public int getTotalSteps()
  85:     {
  86:         return (int)(realHypo/d);
  87:     }
  88: }

1 comment:

Anonymous said...

Hi,
Excellent article. But it doesn't give u correct points if starting point is moved from top-right to bottom-left corner. The angle calculation is incorrect in that case.

Can you upgrade and post it again?
Thanks.
MAZHAR