/** * 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.1 */ package loon.action.map; import loon.action.map.colider.Tile; import loon.action.map.colider.TileHelper; import loon.geom.RectBox; import loon.geom.RectI; import loon.geom.Vector2f; import loon.utils.CollectionUtils; import loon.utils.IntMap; import loon.utils.MathUtils; import loon.utils.ObjectMap; import loon.utils.TArray; public class Field2D implements Config { private final static float angular = MathUtils.cos(MathUtils.PI / 4); private Vector2f _offset = new Vector2f(); private RectBox _rect = null; public Object Tag; private String name = "Field2D"; private Tile tileImpl; public static int angle(Vector2f source, Vector2f target) { int nx = target.x() - source.x(); int ny = target.y() - source.y(); int r = MathUtils.sqrt(nx * nx + ny * ny); float cos = nx / r; int angle = MathUtils.floor(MathUtils.acos(cos) * 180 / MathUtils.PI); if (ny < 0) { angle = 360 - angle; } return angle; } public static int getDirection(Vector2f source, Vector2f target, int dirNumber) { int angleValue = angle(source, target); return getDirection(source, target, angleValue, dirNumber); } public static int getDirection(Vector2f source, Vector2f target, float angleValue, int dirNumber) { if (dirNumber == 4) { if (angleValue < 90) { return Config.RIGHT; } else if (angleValue < 180) { return Config.DOWN; } else if (angleValue < 270) { return Config.LEFT; } else { return Config.UP; } } else if (dirNumber == 6) { if (angleValue > 337 || angleValue < 23) { return Config.TRIGHT; } else if (angleValue > 270) { return Config.UP; } else if (angleValue > 202) { return Config.LEFT; } else if (angleValue > 157) { return Config.TLEFT; } else if (angleValue > 90) { return Config.DOWN; } else { return Config.RIGHT; } } else if (dirNumber == 8) { if (angleValue > 337 || angleValue < 23) { return Config.TRIGHT; } else if (angleValue > 292) { return Config.UP; } else if (angleValue > 247) { return Config.TUP; } else if (angleValue > 202) { return Config.LEFT; } else if (angleValue > 157) { return Config.TLEFT; } else if (angleValue > 112) { return Config.DOWN; } else if (angleValue > 67) { return Config.TDOWN; } else { return Config.RIGHT; } } return Config.EMPTY; } public static int getDirection(Vector2f source, Vector2f target) { if (source.x - target.x > 0) { if (source.y - target.y > 0) { return Config.LEFT; } else if (source.y - target.y < 0) { return Config.DOWN; } else { return Config.TLEFT; } } else if (source.x - target.x < 0) { if (source.y - target.y > 0) { return Config.UP; } else if (source.y - target.y < 0) { return Config.RIGHT; } else { return Config.TRIGHT; } } else { if (source.y - target.y > 0) { return Config.TUP; } else if (source.y - target.y < 0) { return Config.TDOWN; } else { return Config.EMPTY; } } } public static int getDirection(float angle) { float tup = MathUtils.sin(angle) * 0 + MathUtils.cos(angle) * -1; float tright = MathUtils.sin(angle) * 1 + MathUtils.cos(angle) * 0; float tleft = MathUtils.sin(angle) * -1 + MathUtils.cos(angle) * 0; float tdown = MathUtils.sin(angle) * 0 + MathUtils.cos(angle) * 1; if (tup > angular) { return TUP; } if (tright > angular) { return TRIGHT; } if (tleft > angular) { return TLEFT; } if (tdown > angular) { return TDOWN; } return EMPTY; } private static Vector2f vector2; final static private ObjectMap<Vector2f, Integer> directions = new ObjectMap<Vector2f, Integer>(9); final static private IntMap<Vector2f> directionValues = new IntMap<Vector2f>(9); static { directions.put(new Vector2f(0, 0), Config.EMPTY); directions.put(new Vector2f(1, -1), Config.UP); directions.put(new Vector2f(-1, -1), Config.LEFT); directions.put(new Vector2f(1, 1), Config.RIGHT); directions.put(new Vector2f(-1, 1), Config.DOWN); directions.put(new Vector2f(0, -1), Config.TUP); directions.put(new Vector2f(-1, 0), Config.TLEFT); directions.put(new Vector2f(1, 0), Config.TRIGHT); directions.put(new Vector2f(0, 1), Config.TDOWN); directionValues.put(Config.EMPTY, new Vector2f(0, 0)); directionValues.put(Config.UP, new Vector2f(1, -1)); directionValues.put(Config.LEFT, new Vector2f(-1, -1)); directionValues.put(Config.RIGHT, new Vector2f(1, 1)); directionValues.put(Config.DOWN, new Vector2f(-1, 1)); directionValues.put(Config.TUP, new Vector2f(0, -1)); directionValues.put(Config.TLEFT, new Vector2f(-1, 0)); directionValues.put(Config.TRIGHT, new Vector2f(1, 0)); directionValues.put(Config.TDOWN, new Vector2f(0, 1)); } private TArray<Vector2f> result; private int[][] data; private int[] limit; // default size private int tileWidth = 32; private int tileHeight = 32; private int width, height; public Field2D(Field2D field) { cpy(field); } public Field2D(String fileName, int tw, int th) { set(TileMapConfig.loadAthwartArray(fileName), tw, th); } public Field2D(int[][] data) { this(data, 0, 0); } public Field2D(int[][] data, int tw, int th) { this.set(data, tw, th); } public void cpy(Field2D field) { this.set(CollectionUtils.copyOf(field.data), field.tileWidth, field.tileHeight); } public Tile getTile(int x, int y) { return tileImpl.at(x, y); } public void set(int[][] data, int tw, int th) { this.setMap(data); this.setTileWidth(tw); this.setTileHeight(th); this.width = data[0].length; this.height = data.length; if (tileImpl == null) { this.tileImpl = new TileHelper(tileWidth, tileHeight); } else { this.tileImpl.setWidth(tileWidth); this.tileImpl.setHeight(tileHeight); } } public void setSize(int width, int height) { this.width = width; this.height = height; } public void setTile(int tw, int th) { this.tileWidth = tw; this.tileHeight = th; } public int getWidth() { return width; } public int getHeight() { return height; } public int pixelsToTilesWidth(float x) { return MathUtils.floor(x / tileWidth); } public int pixelsToTilesWidth(int x) { return MathUtils.floor(x / tileWidth); } public int pixelsToTilesHeight(float y) { return MathUtils.floor(y / tileHeight); } public int pixelsToTilesHeight(int y) { return MathUtils.floor(y / tileHeight); } public int tilesToWidthPixels(int tiles) { return tiles * tileWidth; } public int tilesToHeightPixels(int tiles) { return tiles * tileHeight; } public int tilesToWidthPixels(float tiles) { return (int) (tiles * tileWidth); } public int tilesToHeightPixels(float tiles) { return (int) (tiles * tileHeight); } public int getViewWidth() { return tilesToWidthPixels(width); } public int getViewHeight() { return tilesToWidthPixels(height); } public int getTileHeight() { return tileHeight; } public void setTileHeight(int tileHeight) { this.tileHeight = tileHeight; } public int getTileWidth() { return tileWidth; } public void setTileWidth(int tileWidth) { this.tileWidth = tileWidth; } public int[] getLimit() { return limit; } public void setLimit(int[] limit) { this.limit = limit; } public int getType(int x, int y) { try { return data[x][y]; } catch (Exception e) { return -1; } } public void setType(int x, int y, int tile) { try { this.data[x][y] = tile; } catch (Exception e) { } } public int[][] getMap() { return data; } public void setMap(int[][] data) { this.data = data; } public boolean isHit(Vector2f point) { int type = get(data, point); if (type == -1) { return false; } if (limit != null) { for (int i = 0; i < limit.length; i++) { if (limit[i] == type) { return false; } } } return true; } public boolean inside(float x, float y) { RectI rect = new RectI(0, 0, width * tileWidth, height * tileHeight); return rect.inside((int) x, (int) y); } public boolean isHit(int px, int py) { int type = get(data, px, py); if (type == -1) { return false; } if (limit != null) { for (int i = 0; i < limit.length; i++) { if (limit[i] == type) { return false; } } } return true; } public static int getDirection(int x, int y) { return getDirection(x, y, Config.EMPTY); } public static int getDirection(int x, int y, int value) { if (vector2 == null) { vector2 = new Vector2f(x, y); } else { vector2.set(x, y); } Integer result = directions.get(vector2); if (result != null) { return result; } else { return value; } } public static Vector2f getDirection(int type) { if (type > Config.TDOWN) { type = Config.TDOWN; } return directionValues.get(type); } private static void insertArrays(int[][] arrays, int index, int px, int py) { arrays[index][0] = px; arrays[index][1] = py; } public int[][] neighbors(int px, int py, boolean flag) { int[][] pos = new int[8][2]; insertArrays(pos, 0, px, py - 1); insertArrays(pos, 0, px + 1, py); insertArrays(pos, 0, px, py + 1); insertArrays(pos, 0, px - 1, py); if (flag) { insertArrays(pos, 0, px - 1, py - 1); insertArrays(pos, 0, px + 1, py - 1); insertArrays(pos, 0, px + 1, py + 1); insertArrays(pos, 0, px - 1, py + 1); } return pos; } public TArray<Vector2f> neighbors(Vector2f pos, boolean flag) { if (result == null) { result = new TArray<Vector2f>(8); } else { result.clear(); } int x = pos.x(); int y = pos.y(); result.add(new Vector2f(x, y - 1)); result.add(new Vector2f(x + 1, y)); result.add(new Vector2f(x, y + 1)); result.add(new Vector2f(x - 1, y)); if (flag) { result.add(new Vector2f(x - 1, y - 1)); result.add(new Vector2f(x + 1, y - 1)); result.add(new Vector2f(x + 1, y + 1)); result.add(new Vector2f(x - 1, y + 1)); } return result; } private int get(int[][] data, int px, int py) { try { if (px >= 0 && px < width && py >= 0 && py < height) { return data[py][px]; } else { return -1; } } catch (Exception e) { return -1; } } private int get(int[][] data, Vector2f point) { try { if (point.x() >= 0 && point.x() < width && point.y() >= 0 && point.y() < height) { return data[point.y()][point.x()]; } else { return -1; } } catch (Exception e) { return -1; } } public RectBox getRect() { if (_rect == null) { _rect = new RectBox(0, 0, getViewWidth(), getViewHeight()); } else { _rect.setSize(getViewWidth(), getViewHeight()); } return _rect; } public Tile getTileImpl() { return tileImpl; } public void setTileImpl(Tile tileImpl) { this.tileImpl = tileImpl; } public Vector2f getOffset() { return _offset; } public void setOffset(Vector2f offset) { this._offset = offset; } public int offsetXPixel(int x) { return x - _offset.x(); } public int offsetYPixel(int y) { return y - _offset.y(); } public void setName(String n) { this.name = n; } public String getName() { return this.name; } }