/**
* Copyright 2008 - 2012
*
* 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.3.3
*/
package loon.action.sprite;
import java.util.LinkedList;
import loon.LSystem;
import loon.LTouch;
import loon.action.map.AStarFindHeuristic;
import loon.action.map.AStarFinder;
import loon.action.map.Config;
import loon.action.map.Field2D;
import loon.action.map.TileMap;
import loon.core.geom.ShapeUtils;
import loon.core.geom.Vector2f;
import loon.core.timer.LTimer;
import loon.utils.CollectionUtils;
import loon.utils.MathUtils;
public class MoveObject extends SpriteBatchObject {
private boolean allDirection;
private LinkedList<Vector2f> findPath = new LinkedList<Vector2f>();
private int startX, startY, endX, endY, moveX, moveY;
private int speed, touchX, touchY;
private int direction = EMPTY;
protected final static int BLOCK_SIZE = 32;
private boolean isComplete;
private LTimer timer;
private AStarFindHeuristic heuristic;
private int movingLength;
public MoveObject(float x, float y, Animation animation, TileMap map) {
this(x, y, 0, 0, animation, map);
}
public MoveObject(float x, float y, float dw, float dh,
Animation animation, TileMap map) {
super(x, y, dw, dh, animation, map);
this.timer = new LTimer(0);
this.isComplete = false;
this.allDirection = false;
this.speed = 4;
}
public void updateMove() {
synchronized (MoveObject.class) {
if (!getCollisionArea().contains(touchX, touchY)) {
if (findPath != null) {
findPath.clear();
}
findPath = AStarFinder
.find(heuristic,
tiles.getField(),
tiles.pixelsToTilesWidth(x()),
tiles.pixelsToTilesHeight(y()),
tiles.pixelsToTilesWidth(touchX
- tiles.getOffset().x),
tiles.pixelsToTilesHeight(touchY
- tiles.getOffset().y), allDirection);
} else if (findPath != null) {
findPath.clear();
}
}
}
public void pressedLeft() {
direction = LEFT;
}
public void pressedRight() {
direction = RIGHT;
}
public void pressedDown() {
direction = DOWN;
}
public void pressedUp() {
direction = UP;
}
public void releaseDirection() {
this.direction = EMPTY;
}
private boolean moveState() {
movingLength = 0;
switch (direction) {
case LEFT:
if (moveLeft()) {
return true;
}
break;
case RIGHT:
if (moveRight()) {
return true;
}
break;
case UP:
if (moveUp()) {
return true;
}
break;
case DOWN:
if (moveDown()) {
return true;
}
break;
default:
break;
}
return false;
}
private boolean moveLeft() {
int px = x();
int py = y();
int x = tiles.pixelsToTilesWidth(px);
int y = tiles.pixelsToTilesHeight(py);
int nextX = x - 1;
int nextY = y;
if (nextX < 0) {
nextX = 0;
}
if (tiles.isHit(nextX, nextY)) {
px -= speed;
if (px < 0) {
px = 0;
}
movingLength += speed;
setLocation(px, py);
if (movingLength >= tiles.getTileWidth()) {
x--;
px = x * tiles.getTileWidth();
setLocation(px, py);
return true;
}
} else {
px = x * tiles.getTileWidth();
py = y * tiles.getTileHeight();
setLocation(px, py);
}
return false;
}
private boolean moveRight() {
int px = x();
int py = y();
int x = tiles.pixelsToTilesWidth(px);
int y = tiles.pixelsToTilesHeight(py);
int nextX = x + 1;
int nextY = y;
if (nextX > tiles.getRow() - 1) {
nextX = tiles.getRow() - 1;
}
if (tiles.isHit(nextX, nextY)) {
px += speed;
if (px > tiles.getWidth() - tiles.getTileWidth()) {
px = tiles.getWidth() - tiles.getTileWidth();
}
movingLength += speed;
setLocation(px, py);
if (movingLength >= tiles.getTileWidth()) {
x++;
px = x * tiles.getTileWidth();
setLocation(px, py);
return true;
}
} else {
px = x * tiles.getTileWidth();
py = y * tiles.getTileHeight();
setLocation(px, py);
}
return false;
}
private boolean moveUp() {
int px = x();
int py = y();
int x = tiles.pixelsToTilesWidth(px);
int y = tiles.pixelsToTilesHeight(py);
int nextX = x;
int nextY = y - 1;
if (nextY < 0) {
nextY = 0;
}
if (tiles.isHit(nextX, nextY)) {
py -= speed;
if (py < 0) {
py = 0;
}
movingLength += speed;
setLocation(px, py);
if (movingLength >= tiles.getTileHeight()) {
y--;
py = y * tiles.getTileHeight();
setLocation(px, py);
return true;
}
} else {
px = x * tiles.getTileWidth();
py = y * tiles.getTileHeight();
setLocation(px, py);
}
return false;
}
private boolean moveDown() {
int px = x();
int py = y();
int x = tiles.pixelsToTilesWidth(px);
int y = tiles.pixelsToTilesHeight(py);
int nextX = x;
int nextY = y + 1;
if (nextY > tiles.getCol() - 1) {
nextY = tiles.getCol() - 1;
}
if (tiles.isHit(nextX, nextY)) {
py += speed;
if (py > tiles.getHeight() - tiles.getTileHeight()) {
py = tiles.getHeight() - tiles.getTileHeight();
}
movingLength += speed;
setLocation(px, py);
if (movingLength >= tiles.getTileHeight()) {
y++;
py = y * tiles.getTileHeight();
setLocation(px, py);
return true;
}
} else {
px = x * tiles.getTileWidth();
py = y * tiles.getTileHeight();
setLocation(px, py);
}
return false;
}
@Override
public int hashCode() {
if (tiles == null) {
return super.hashCode();
}
int hashCode = 1;
hashCode = LSystem.unite(hashCode, allDirection);
hashCode = LSystem.unite(hashCode, tiles.pixelsToTilesWidth(x()));
hashCode = LSystem.unite(hashCode, tiles.pixelsToTilesHeight(y()));
hashCode = LSystem.unite(hashCode,
tiles.pixelsToTilesWidth(touchX - tiles.getOffset().x));
hashCode = LSystem.unite(hashCode,
tiles.pixelsToTilesHeight(touchY - tiles.getOffset().y));
hashCode = LSystem.unite(hashCode, tiles.getWidth());
hashCode = LSystem.unite(hashCode, tiles.getHeight());
hashCode = LSystem.unite(hashCode, tiles.getTileWidth());
hashCode = LSystem.unite(hashCode, tiles.getTileHeight());
hashCode = LSystem.unite(hashCode,
CollectionUtils.hashCode(tiles.getMap()));
return hashCode;
}
public void onTouch(LTouch e) {
this.onTouch(e.x(), e.y());
}
public void onTouch(int x, int y) {
this.touchX = x;
this.touchY = y;
this.updateMove();
}
public int getTouchX() {
return touchX;
}
public int getTouchY() {
return touchY;
}
public void onPosition(LTouch e) {
this.onPosition(e.getX(), e.getY());
}
public void onPosition(float x, float y) {
if (findPath == null) {
return;
}
synchronized (findPath) {
if (findPath != null) {
findPath.clear();
}
}
this.setLocation(x, y);
}
private boolean isMoving;
@Override
public void update(long elapsedTime) {
if (timer.action(elapsedTime)) {
isMoving = moveState();
if (tiles == null || findPath == null) {
return;
}
if (isComplete()) {
return;
}
synchronized (findPath) {
if (endX == startX && endY == startY) {
if (findPath != null) {
if (findPath.size() > 1) {
Vector2f moveStart = findPath.get(0);
Vector2f moveEnd = findPath.get(1);
startX = tiles.tilesToPixelsX(moveStart.x());
startY = tiles.tilesToPixelsY(moveStart.y());
endX = moveEnd.x() * tiles.getTileWidth();
endY = moveEnd.y() * tiles.getTileHeight();
moveX = moveEnd.x() - moveStart.x();
moveY = moveEnd.y() - moveStart.y();
direction = Field2D.getDirection(moveX, moveY);
findPath.remove(0);
} else {
findPath.clear();
}
}
}
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;
}
Vector2f tile = tiles.getTileCollision(this, startX, startY);
if (tile != null) {
int sx = tiles.tilesToPixelsX(tile.x);
int sy = tiles.tilesToPixelsY(tile.y);
if (sx > 0) {
sx = sx - getWidth();
} else if (sx < 0) {
sx = tiles.tilesToPixelsX(tile.x);
}
if (sy > 0) {
sy = sy - getHeight();
} else if (sy < 0) {
sy = tiles.tilesToPixelsY(tile.y);
}
} else {
setLocation(startX, startY);
}
}
}
}
public long getDelay() {
return timer.getDelay();
}
public void setDelay(long d) {
timer.setDelay(d);
}
public int getDirection() {
return direction;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public boolean isComplete() {
return findPath == null || findPath.size() == 0 || isComplete;
}
public void setComplete(boolean c) {
this.isComplete = true;
}
public float getRotationTo(float x, float y) {
float r = MathUtils.atan2(x - x(), y - y());
return ShapeUtils.getAngleDiff(rotation, r);
}
@Override
public void dispose() {
super.dispose();
if (findPath != null) {
findPath.clear();
findPath = null;
}
}
public AStarFindHeuristic getHeuristic() {
return heuristic;
}
public void setHeuristic(AStarFindHeuristic heuristic) {
this.heuristic = heuristic;
}
public boolean isAllDirection() {
return allDirection;
}
public void setAllDirection(boolean allDirection) {
this.allDirection = allDirection;
}
public boolean isMoving() {
return isMoving;
}
}