LineDrawing: the Android Version

more libgdx

Some time back I did a tutorial on how to move from ActionScript to Objective-C and I used a LineDrawing game code example, kind of like the engine used in the game Flight Control. So I figured I might as well do a Java version and run it with LibGDX. And here's the result.

In case you missed the other tutorials here's a recap:

I did the code in ActionScript.

Then I changed it to Objective-C.

Then I built the demo with Cocos2D (OpenGL).

And the same thing with Quartz 2D.

Now, the Java Version...

LineDrawing.java

package com.rengelbert.linedrawing;

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GLCommon;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;


public class LineDrawing implements ApplicationListener {
	
	
	public SpriteBatch spriteBatch;
	public OrthographicCamera camera;
	public int screenWidth;
	public int screenHeight;
	
	private boolean _collect = false;
	private List _points;
	private int _maxDistance = 20;
	private LinePath2D _linePath;
	
	//space between dashes or dots
	private float _gap = 20f;
	
	private Plane _plane;
	private float _planeAnimationTime = 0f;
	//the plane speed
	private float _speed = 0.5f;
	private float _speedOnPath = 0f;
	private Sprite _dash;
			
	private float _progress = 0f;
	private float _oldLength = 0f;
	private float _oldProgress = 0f;
	
	//rotation easing
	private float _dr = 0f;
	private float _ar = 0f;
	private float _vr = 0f;
	private float _targetRotation = 0f;
	private float _rotationSpring = 0.1f;
	private float _rotationDamping = 0.6f;
	
	private Vector3 _touchPoint;
	private PointPool _vectorPool;
	
	@Override
	public void create() {
		
		screenWidth = 480;
		screenHeight = 320;
		
		camera = new OrthographicCamera(screenWidth, screenHeight);
		camera.position.set(screenWidth * 0.5f, screenHeight * 0.5f, 0);
		
		
		spriteBatch = new SpriteBatch();
		
		Assets.load();
		
		_linePath = new LinePath2D();
		_plane = new Plane(50, 50);
		_plane.setSkin(Assets.planeFrame1);
		
		
		_dash = new Sprite (Assets.dash);
		_touchPoint = new Vector3();
		_points = new ArrayList();
		
		_vectorPool = new PointPool();

	}

	private void updateSpeedAndProgress () {
		float iterations = (_linePath.totalLength/_speed);
		_speedOnPath = 1/iterations;
		
		if (_oldLength != 0 && _linePath.totalLength - _oldLength > 10) {
			_progress = (_oldLength * _oldProgress)/_linePath.totalLength;
			_linePath.renderObjectAt(_plane, _progress);
		}
		_oldLength = _linePath.totalLength;
		_oldProgress = _progress;
	}
	
	
	@Override
	public void render() {
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//grab user input
		if (Gdx.input.isTouched(0)) {
			
			camera.unproject(_touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
			
			if (_collect) {
			
				Vector2 point = _vectorPool.getObject();
				point.set(_touchPoint.x, _touchPoint.y);
				
				if (_points.size() == 0) {
					_linePath.points.clear();
					_progress = 0f;
					point.set(_plane.x, _plane.y);
					_points.add(point);
					_linePath.insertMultiplePoints(_points, 0);
				} else {
					
					Vector2 lastPoint = _points.get(_points.size() - 1);
					//only add a point if the distance to the previous point is long enough 
					//(you don't want to add the same point over and over again!) 
					if (point.dst(lastPoint) > _maxDistance) {
						_points.add(point);
						_linePath.appendPoint(point);
						updateSpeedAndProgress();
						
					}
				}
			} else {
				_points.clear();
				_linePath.points.clear();
				_collect = false;
				if (_plane.bounds().contains(_touchPoint.x, _touchPoint.y)) {
					_collect = true;
				} 
			}
		} else{
			_collect = false;
		}
		
		if (Gdx.input.justTouched()) {
			_collect = false;
		}
		
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//update plane
		//is path has not been set, or plane has reached the end of the path, keep moving plane
		if (_linePath.points.size() <= 1 || _progress + _speedOnPath >= 1 || _linePath.totalLength < 5) {

			float angle = _plane.rotation * (float) Math.PI /  180;
			
			_plane.x = (float) (_plane.x + _speed * Math.cos(angle));
			_plane.y = (float) (_plane.y + _speed * Math.sin(angle)); 
			
		} else {
			//increment progress with our calculated speedOnPath
			//this ensures the plane keeps moving at the speed set in _speed variable
			_progress += _speedOnPath;
			if (_linePath.points.size() > 1) _linePath.renderObjectAt(_plane, _progress);
			//set target rotation for ease/spring logic bellow
			_targetRotation = _linePath.angle;
			if (_targetRotation > _plane.rotation + 180) _targetRotation -= 360;
			if (_targetRotation < _plane.rotation - 180) _targetRotation += 360;
			
			//redraw the line so dashes/dots already transposed by plane are not redrawn. meaning, they are erased.
			_oldProgress = _progress;
			
			//ease and spring the rotation a bit so it looks nicer!
			_dr = _targetRotation - _plane.rotation;
			_ar = _dr * _rotationSpring;
			_vr += _ar;
			_vr *= _rotationDamping;
			_plane.rotation +=  _vr;
		}
		
		
		
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//render
		GLCommon gl = Gdx.gl;
		gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		
		camera.update();
		spriteBatch.setProjectionMatrix(camera.combined);
		spriteBatch.enableBlending();
		spriteBatch.begin();
		
		//draw line
		if (_linePath.totalLength > 100 &&  _linePath.points.size() != 0 && _points.size() != 0)  {
		
			float points  = _linePath.totalLength / _gap;
			float progressIncrement = 1/points;
			
			//spread the points evenly
			float p = 0f;
			Vector2 point;
			
			while (p < 1 ) {
				//in order to draw the path, traverse it with a fixed progress and grab the points from that
				point = _linePath.getPointAtProgress(p);
				
				//check p against progress so we don't draw the dashes/dots the plane has moved past already
				if (point != null && p > _linePath.progress + 0.01) {
					/*
					 //Use Dash
					_dash.setRotation(_linePath.angle);
					_dash.setPosition(point.x, point.y);
					_dash.draw(spriteBatch);
					*/

					//Use dot
					spriteBatch.draw(Assets.dot, point.x, point.y);
				}
				p += progressIncrement;
			}
		}
		
		
		//draw plane
		_plane.skin = Assets.planeAnimation.getKeyFrame(_planeAnimationTime, true);
		//**draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation) 
		spriteBatch.draw(_plane.skin, _plane.x - _plane.width * 0.5f, _plane.y - _plane.height * 0.5f, _plane.width*0.5f, _plane.height*0.5f, _plane.width, _plane.height, 1, 1, _plane.rotation);
		_planeAnimationTime += Gdx.graphics.getDeltaTime();
		if (_planeAnimationTime > 10) _planeAnimationTime = 0;
		
		spriteBatch.end();
	}
		

	@Override
	public void resume() {}
	@Override
	public void resize(int arg0, int arg1) {}
	@Override
	public void dispose() {
		_linePath.dispose();
		_vectorPool.dispose();
	}
	@Override
	public void pause() {}
}

Of notice here is how to track more complex touch events, and how to ignore multiple touches by passing a touch pointer to the method isTouched.

I also used a different SpriteBatch.draw() method this time. An overloaded version that accepts a value for rotation. I used it to draw the Plane. Notice how I use the draw() method to center the TextureRegion.

//params: TextureRegion, x, y, origin x, origin y, scale x, scale y, rotation 
spriteBatch.draw(_plane.skin, _plane.x - _plane.width * 0.5f, _plane.y - _plane.height * 0.5f, _plane.width*0.5f, _plane.height*0.5f, _plane.width, _plane.height, 1, 1, _plane.rotation);

I draw with textures now. It is somewhat complicated to use LibGDX to draw primitives. Nope, not complicated at all. Here is the same class but using ShapeRenderer to draw primitives.

package com.rengelbert.linedrawing;

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GLCommon;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;


public class LineDrawing implements ApplicationListener {
	
	
	public SpriteBatch spriteBatch;
	public ShapeRenderer shapeRenderer;
	public OrthographicCamera camera;
	public int screenWidth;
	public int screenHeight;
	
	private boolean _collect = false;
	private List _points;
	private int _maxDistance = 20;
	private LinePath2D _linePath;
	
	//space between dashes or dots
	private float _gap = 20f;
	
	private Plane _plane;
	private float _planeAnimationTime = 0f;
	//the plane speed
	private float _speed = 0.5f;
	private float _speedOnPath = 0f;
			
	private float _progress = 0f;
	private float _oldLength = 0f;
	private float _oldProgress = 0f;
	
	//rotation easing
	private float _dr = 0f;
	private float _ar = 0f;
	private float _vr = 0f;
	private float _targetRotation = 0f;
	private float _rotationSpring = 0.1f;
	private float _rotationDamping = 0.6f;
	
	private Vector3 _touchPoint;
	private PointPool _vectorPool;
	
	@Override
	public void create() {
		
		screenWidth = 480;
		screenHeight = 320;
		
		camera = new OrthographicCamera(screenWidth, screenHeight);
		camera.position.set(screenWidth * 0.5f, screenHeight * 0.5f, 0);
		
		
		spriteBatch = new SpriteBatch();
		shapeRenderer = new ShapeRenderer();
		
		Assets.load();
		
		_linePath = new LinePath2D();
		_plane = new Plane(50, 50);
		_plane.setSkin(Assets.planeFrame1);
		
		
		_touchPoint = new Vector3();
		_points = new ArrayList();
		
		_vectorPool = new PointPool();
				
		//set the point size for the path
		Gdx.gl11.glPointSize(3.0f);

	}

	private void updateSpeedAndProgress () {
		float iterations = (_linePath.totalLength/_speed);
		_speedOnPath = 1/iterations;
		
		if (_oldLength != 0 && _linePath.totalLength - _oldLength > 10) {
			_progress = (_oldLength * _oldProgress)/_linePath.totalLength;
			_linePath.renderObjectAt(_plane, _progress);
		}
		_oldLength = _linePath.totalLength;
		_oldProgress = _progress;
	}
	
	
	@Override
	public void render() {
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//grab user input
		if (Gdx.input.isTouched(0)) {
			
			camera.unproject(_touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
			
			if (_collect) {
			
				Vector2 point = _vectorPool.getObject();
				point.set(_touchPoint.x, _touchPoint.y);
				
				if (_points.size() == 0) {
					_linePath.points.clear();
					_progress = 0f;
					point.set(_plane.x, _plane.y);
					_points.add(point);
					_linePath.insertMultiplePoints(_points, 0);
				} else {
					
					Vector2 lastPoint = _points.get(_points.size() - 1);
					//only add a point if the distance to the previous point is long enough 
					//(you don't want to add the same point over and over again!) 
					if (point.dst(lastPoint) > _maxDistance) {
						_points.add(point);
						_linePath.appendPoint(point);
						updateSpeedAndProgress();
						
					}
				}
			} else {
				_points.clear();
				_linePath.points.clear();
				_collect = false;
				if (_plane.bounds().contains(_touchPoint.x, _touchPoint.y)) {
					_collect = true;
				} 
			}
		} else{
			_collect = false;
		}
		
		if (Gdx.input.justTouched()) {
			_collect = false;
		}
		
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//update plane
		//is path has not been set, or plane has reached the end of the path, keep moving plane
		if (_linePath.points.size() <= 1 || _progress + _speedOnPath >= 1 || _linePath.totalLength < 5) {

			float angle = _plane.rotation * (float) Math.PI /  180;
			
			_plane.x = (float) (_plane.x + _speed * Math.cos(angle));
			_plane.y = (float) (_plane.y + _speed * Math.sin(angle)); 
			
		} else {
			//increment progress with our calculated speedOnPath
			//this ensures the plane keeps moving at the speed set in _speed variable
			_progress += _speedOnPath;
			if (_linePath.points.size() > 1) _linePath.renderObjectAt(_plane, _progress);
			//set target rotation for ease/spring logic bellow
			_targetRotation = _linePath.angle;
			if (_targetRotation > _plane.rotation + 180) _targetRotation -= 360;
			if (_targetRotation < _plane.rotation - 180) _targetRotation += 360;
			
			//redraw the line so dashes/dots already transposed by plane are not redrawn. meaning, they are erased.
			_oldProgress = _progress;
			
			//ease and spring the rotation a bit so it looks nicer!
			_dr = _targetRotation - _plane.rotation;
			_ar = _dr * _rotationSpring;
			_vr += _ar;
			_vr *= _rotationDamping;
			_plane.rotation +=  _vr;
		}
		
		
		
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		//render
		GLCommon gl = Gdx.gl;
		gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		
		camera.update();
		 
			
		//draw line
		if (_linePath.totalLength > 100 &&  _linePath.points.size() != 0 && _points.size() != 0)  {
			
			float points  = _linePath.totalLength / _gap;
			float progressIncrement = 1/points;
			
			//spread the points evenly
			float p = 0f;
			Vector2 point;
			
			shapeRenderer.setProjectionMatrix(camera.combined);
			shapeRenderer.begin(ShapeType.Point);
			
			 
			while (p < 1 ) {
				//in order to draw the path, traverse it with a fixed progress and grab the points from that
				point = _linePath.getPointAtProgress(p);
				
				//check p against progress so we don't draw the dashes/dots the plane has moved past already
				if (point != null && p > _linePath.progress + 0.01) {
					shapeRenderer.point(point.x, point.y, 0);
				}
				p += progressIncrement;
			}
			shapeRenderer.end();
		}
		
		spriteBatch.setProjectionMatrix(camera.combined);
		spriteBatch.enableBlending();
		spriteBatch.begin();
		//draw plane
		_plane.skin = Assets.planeAnimation.getKeyFrame(_planeAnimationTime, true);
		//**draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation) 
		spriteBatch.draw(_plane.skin, _plane.x - _plane.width * 0.5f, _plane.y - _plane.height * 0.5f, _plane.width*0.5f, _plane.height*0.5f, _plane.width, _plane.height, 1, 1, _plane.rotation);
		_planeAnimationTime += Gdx.graphics.getDeltaTime();
		if (_planeAnimationTime > 10) _planeAnimationTime = 0;
		
		spriteBatch.end();
	}
		

	@Override
	public void resume() {}
	@Override
	public void resize(int arg0, int arg1) {}
	@Override
	public void dispose() {
		_linePath.dispose();
		_vectorPool.dispose();
	}
	@Override
	public void pause() {}
}

Now I use a SpriteBatch and a ShapeRenderer for the rendering. I set the point size in the class constructor and I draw with ShapeRenderer.point(x,y) method.

LinePath2D.java

package com.rengelbert.linedrawing;

import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.math.Vector2;

public class LinePath2D {
	
	public float angle;
	public float totalLength;
	public List points;
	public float progress;
	
	private PathPoint _first;
	private PathPointPool _pointPool;
	
	
	public LinePath2D () {
		points = new ArrayList();
		totalLength = 0f;
		angle = 0f;
		_pointPool = new PathPointPool();
	}
	
	public void appendPoint (Vector2 point) {
		insertPoint(point, points.size(), false);
	}
	
	public void insertMultiplePoints(List points, int index) {
		int len = points.size();
		for (int i = 0; i < len; i++) {
			insertPoint(points.get(i), index + i, true);
		}
	}
	
	public Vector2 getPointAtProgress (float progress) {
		progress = Math.abs(progress);
		
		Vector2 point = new Vector2();
		if (progress > 1) progress = 1;
		PathPoint pp = _first;
		if (pp.next == null) return null;
		if (pp.next.progress < 0) return null;
		
		while (pp.next != null && pp.next.progress < progress) {
			pp = pp.next;
		}
		
		if (pp != null) {
			angle = pp.angle;
			float pathProg = (progress - pp.progress) / (pp.length / totalLength);
			point.x = pp.x + pathProg * pp.xChange;
			point.y = pp.y + pathProg * pp.yChange;
			
			return point;
			
		}
		return null;
	}
	
	public void renderObjectAt(Plane target, float progress) {
		
		if (progress > 1) {
			progress -= (int) progress;
		} else if (progress < 0) {
			progress -= (int) progress - 1;
		}
		
		if (_first == null) {
			return;
		}
		
		this.progress = progress;
		
		PathPoint pp = _first;
		while (pp.next != null && pp.next.progress < progress) {
			pp = pp.next;
		}
		
		if (pp != null) {
			angle = pp.angle;
			float pathProg = (progress - pp.progress) / (pp.length / totalLength);
			float px = pp.x + pathProg * pp.xChange;
			float py = pp.y + pathProg * pp.yChange;
			target.x = px;
			target.y = py;		
		}
	}
	
	public void dispose () {
		points.clear();
		_pointPool.dispose();
	}
	
	
	public List getPoints() {
		return points;
	}
	
	public void setPoints(List value) {
		
		points.clear();
		insertMultiplePoints(value, 0);
	}
	
	
	private void insertPoint(Vector2 point, int index, boolean skipOrganize)  {
		
		PathPoint p = _pointPool.getObject();
		p.setPoint(point);
		
		if (points.size() == 0) {
			points.add(p);
		} else {
			points.add(index, p);
		}
		
		if (!skipOrganize) {
			organize();
		}
	}
	
	private void organize() {
		totalLength = 0;
		int last = points.size() - 1;
		if (last == -1) {
			_first = null;
		} else if (last == 0) {
			_first = points.get(0);
			_first.progress = _first.xChange = _first.yChange = _first.length = 0;
			return;
		}
		PathPoint pp;
		for (int i = 0; i <= last; i++) { 
			if (points.get(i) != null) {
				pp = points.get(i);
				pp.x = pp.x;
				pp.y = pp.y;
				if (i == last) {
					pp.length = 0;
					pp.next = null;
				} else {
					pp.next = points.get(i + 1);
					pp.xChange = pp.next.x - pp.x;
					pp.yChange = pp.next.y - pp.y;
					pp.length = (float) Math.sqrt(pp.xChange * pp.xChange + pp.yChange * pp.yChange);
					totalLength += pp.length;
				}
			}
		}
		_first = pp = points.get(0);
		float curTotal = 0f;
		while (pp != null) {
			pp.progress = curTotal / totalLength;
			curTotal += pp.length;
			pp = pp.next;
		}
		updateAngles();
	}
	
	private void updateAngles() {
		PathPoint pp = _first;
		while (pp != null) {
			pp.angle = (float) Math.atan2(pp.yChange, pp.xChange ) * (180 / (float) Math.PI);
			pp = pp.next;
		}
		
	}	
}

Assets.java

package com.rengelbert.linedrawing;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class Assets {
	
	public static Texture planes;
	public static TextureRegion planeFrame1;
	public static TextureRegion dash;
	public static TextureRegion dot;
	public static Animation planeAnimation;
	
	
	public static Texture loadTexture (String file) {
		return new Texture(Gdx.files.internal(file));
	}

	public static void load () {
		planes = loadTexture("data/planeSprites.png");
		planeFrame1 =  new TextureRegion (planes, 14, 2, 63, 64);
		dash =  new TextureRegion (planes, 2, 2, 5, 2);
		dot =  new TextureRegion (planes, 9, 2, 3, 3);
		
		planeAnimation = new Animation (0.2f, 
				planeFrame1,
				new TextureRegion (planes, 2, 68, 63, 64)
				);
	}
	
}

PathPoint.java

package com.rengelbert.linedrawing;

import com.badlogic.gdx.math.Vector2;

public class PathPoint {
	
	public float x;
	public float y;
	public float progress;
	public float xChange;
	public float yChange;
	public Vector2 point;
	public float length;
	public float angle;
	public PathPoint next;
	
	public PathPoint (float x, float y) {
		this.x = x;
		this.y = y;
		progress = -1;
	}
	
	public void setPoint (Vector2 point) {
		this.x = point.x;
		this.y = point.y;
		progress = -1;
	}
	
}

Plane.java

package com.rengelbert.linedrawing;

import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;

public class Plane {
	
	public float x = 0;
	public float y = 0;
	public int width = 0;
	public int height = 0;
	public float rotation = 0f;
	
	public TextureRegion skin;
	
	
	public Plane (float x, float y) {
		this.x = x;
		this.y = y;
		skin = null;
	}
	

	public void setSkin (TextureRegion texture) {
		this.skin = texture;
		width = skin.getRegionWidth();
		height = skin.getRegionHeight();
	}
	
	public Rectangle bounds () {
		return new Rectangle (
				x - width * 0.5f,
				y - height * 0.5f,
				width,
				height
				);
	}
	
	public void update (float dt) {}
	
}

PathPointPool.java

package com.rengelbert.linedrawing;

import java.util.ArrayList;
import java.util.List;

public class PathPointPool  {
	
	private List _pool;
	private int _poolIndex = -1;
	
	public PathPointPool () {
		_pool = new ArrayList(500);
		for (int i = 0; i < 500; i++) {
			_pool.add(new PathPoint(0, 0));
		}
	}
	
	public PathPoint getObject () {
		_poolIndex++;
		
		if (_poolIndex >= _pool.size()) {
			_poolIndex = 0;
		}
		
		return _pool.get(_poolIndex);
	}
	
	public void dispose () {
		_pool.clear();
	}

}