/**
* Copyright 2008 - 2011
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.1
*/
package loon.action;
import java.util.HashMap;
import java.util.LinkedList;
import loon.LSystem;
import loon.action.map.AStarFindHeuristic;
import loon.action.map.AStarFinder;
import loon.action.map.Config;
import loon.action.map.Field2D;
import loon.core.geom.Vector2f;
import loon.utils.CollectionUtils;
import loon.utils.MathUtils;
public class MoveTo extends ActionEvent {
private final static HashMap<Integer, LinkedList<Vector2f>> pathCache = new HashMap<Integer, LinkedList<Vector2f>>(
LSystem.DEFAULT_MAX_CACHE_SIZE);
private Vector2f startLocation, endLocation;
private Field2D layerMap;
private boolean flag, useCache, synchroLayerField;
private LinkedList<Vector2f> pActorPath;
private int startX, startY, endX, endY, moveX, moveY;
private int direction, speed;
private AStarFindHeuristic heuristic;
private Vector2f pLocation = new Vector2f();
public MoveTo(final Field2D map, int x, int y, boolean flag) {
this.startLocation = new Vector2f();
this.endLocation = new Vector2f(x, y);
this.layerMap = map;
this.flag = flag;
this.speed = 4;
this.useCache = true;
this.synchroLayerField = false;
}
public MoveTo(final Field2D map, Vector2f pos, boolean flag) {
this(map, pos.x(), pos.y(), flag);
}
public void randomPathFinder() {
synchronized (MoveTo.class) {
AStarFindHeuristic afh = null;
int index = MathUtils.random(AStarFindHeuristic.MANHATTAN,
AStarFindHeuristic.CLOSEST_SQUARED);
switch (index) {
case AStarFindHeuristic.MANHATTAN:
afh = AStarFinder.ASTAR_EUCLIDEAN;
break;
case AStarFindHeuristic.MIXING:
afh = AStarFinder.ASTAR_MIXING;
break;
case AStarFindHeuristic.DIAGONAL:
afh = AStarFinder.ASTAR_DIAGONAL;
break;
case AStarFindHeuristic.DIAGONAL_SHORT:
afh = AStarFinder.ASTAR_DIAGONAL_SHORT;
break;
case AStarFindHeuristic.EUCLIDEAN:
afh = AStarFinder.ASTAR_EUCLIDEAN;
break;
case AStarFindHeuristic.EUCLIDEAN_NOSQR:
afh = AStarFinder.ASTAR_EUCLIDEAN_NOSQR;
break;
case AStarFindHeuristic.CLOSEST:
afh = AStarFinder.ASTAR_CLOSEST;
break;
case AStarFindHeuristic.CLOSEST_SQUARED:
afh = AStarFinder.ASTAR_CLOSEST_SQUARED;
break;
}
setHeuristic(afh);
}
}
public float[] getBeginPath() {
return new float[] { startX, startY };
}
public float[] getEndPath() {
return new float[] { endX, endY };
}
@Override
public void onLoad() {
if (layerMap == null || original == null) {
return;
}
if (!(original.x() == endLocation.x() && original.y() == endLocation
.y())) {
if (useCache) {
synchronized (pathCache) {
if (pathCache.size() > LSystem.DEFAULT_MAX_CACHE_SIZE * 10) {
pathCache.clear();
}
int key = hashCode();
LinkedList<Vector2f> final_path = pathCache.get(key);
if (final_path == null) {
final_path = AStarFinder
.find(heuristic,
layerMap,
layerMap.pixelsToTilesWidth(startLocation
.x()),
layerMap.pixelsToTilesHeight(startLocation
.y()),
layerMap.pixelsToTilesWidth(endLocation
.x()),
layerMap.pixelsToTilesHeight(endLocation
.y()), flag);
pathCache.put(key, final_path);
}
pActorPath = new LinkedList<Vector2f>();
pActorPath.addAll(final_path);
}
} else {
pActorPath = AStarFinder.find(heuristic, layerMap,
layerMap.pixelsToTilesWidth(startLocation.x()),
layerMap.pixelsToTilesHeight(startLocation.y()),
layerMap.pixelsToTilesWidth(endLocation.x()),
layerMap.pixelsToTilesHeight(endLocation.y()), flag);
}
}
}
public void clearPath() {
if (pActorPath != null) {
synchronized (pActorPath) {
pActorPath.clear();
pActorPath = null;
}
}
}
public static void clearPathCache() {
if (pathCache != null) {
synchronized (pathCache) {
pathCache.clear();
}
}
}
@Override
public int hashCode() {
if (layerMap == null || original == null) {
return super.hashCode();
}
int hashCode = 1;
hashCode = LSystem.unite(hashCode, flag);
hashCode = LSystem.unite(hashCode,
layerMap.pixelsToTilesWidth(original.x()));
hashCode = LSystem.unite(hashCode,
layerMap.pixelsToTilesHeight(original.y()));
hashCode = LSystem.unite(hashCode,
layerMap.pixelsToTilesWidth(endLocation.x()));
hashCode = LSystem.unite(hashCode,
layerMap.pixelsToTilesHeight(endLocation.y()));
hashCode = LSystem.unite(hashCode, layerMap.getWidth());
hashCode = LSystem.unite(hashCode, layerMap.getHeight());
hashCode = LSystem.unite(hashCode, layerMap.getTileWidth());
hashCode = LSystem.unite(hashCode, layerMap.getTileHeight());
hashCode = LSystem.unite(hashCode,
CollectionUtils.hashCode(layerMap.getMap()));
return hashCode;
}
@Override
public void start(ActionBind target) {
super.start(target);
startLocation.set(target.getX(), target.getY());
}
public LinkedList<Vector2f> getPath() {
return pActorPath;
}
public int getDirection() {
return direction;
}
public void setField2D(Field2D field) {
if (field != null) {
this.layerMap = field;
}
}
public Field2D getField2D() {
return layerMap;
}
@Override
public void update(long elapsedTime) {
if (layerMap == null || original == null || pActorPath == null) {
return;
}
synchronized (pActorPath) {
if (synchroLayerField) {
if (original != null) {
Field2D field = original.getField2D();
if (field != null && layerMap != field) {
this.layerMap = field;
}
}
}
if (endX == startX && endY == startY) {
if (pActorPath.size() > 1) {
Vector2f moveStart = pActorPath.get(0);
Vector2f moveEnd = pActorPath.get(1);
startX = layerMap.tilesToWidthPixels(moveStart.x());
startY = layerMap.tilesToHeightPixels(moveStart.y());
endX = moveEnd.x() * layerMap.getTileWidth();
endY = moveEnd.y() * layerMap.getTileHeight();
moveX = moveEnd.x() - moveStart.x();
moveY = moveEnd.y() - moveStart.y();
if (moveX > -2 && moveY > -2 && moveX < 2 && moveY < 2) {
direction = Field2D.getDirection(moveX, moveY,
direction);
}
}
pActorPath.remove(0);
}
switch (direction) {
case Config.TUP:
startY -= speed;
if (startY < endY) {
startY = endY;
}
break;
case Config.TDOWN:
startY += speed;
if (startY > endY) {
startY = endY;
}
break;
case Config.TLEFT:
startX -= speed;
if (startX < endX) {
startX = endX;
}
break;
case Config.TRIGHT:
startX += speed;
if (startX > endX) {
startX = endX;
}
break;
case Config.UP:
startX += speed;
startY -= speed;
if (startX > endX) {
startX = endX;
}
if (startY < endY) {
startY = endY;
}
break;
case Config.DOWN:
startX -= speed;
startY += speed;
if (startX < endX) {
startX = endX;
}
if (startY > endY) {
startY = endY;
}
break;
case Config.LEFT:
startX -= speed;
startY -= speed;
if (startX < endX) {
startX = endX;
}
if (startY < endY) {
startY = endY;
}
break;
case Config.RIGHT:
startX += speed;
startY += speed;
if (startX > endX) {
startX = endX;
}
if (startY > endY) {
startY = endY;
}
break;
}
synchronized (original) {
original.setLocation(startX + offsetX, startY + offsetY);
}
}
}
public Vector2f nextPos() {
if (pActorPath != null) {
synchronized (pActorPath) {
int size = pActorPath.size();
if (size > 0) {
pLocation.set(endX, endY);
} else {
pLocation.set(original.getX(), original.getY());
}
return pLocation;
}
} else {
pLocation.set(original.getX(), original.getY());
return pLocation;
}
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
@Override
public boolean isComplete() {
return pActorPath == null || pActorPath.size() == 0 || isComplete
|| original == null;
}
public boolean isUseCache() {
return useCache;
}
public void setUseCache(boolean useCache) {
this.useCache = useCache;
}
public boolean isSynchroLayerField() {
return synchroLayerField;
}
public void setSynchroLayerField(boolean syn) {
this.synchroLayerField = syn;
}
public AStarFindHeuristic getHeuristic() {
return heuristic;
}
public void setHeuristic(AStarFindHeuristic heuristic) {
this.heuristic = heuristic;
}
}