/**
*
* 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.component;
import java.util.Iterator;
import loon.LSystem;
import loon.action.ActionBind;
import loon.action.ArrowTo;
import loon.action.CircleTo;
import loon.action.ColorTo;
import loon.action.FadeTo;
import loon.action.FireTo;
import loon.action.JumpTo;
import loon.action.MoveTo;
import loon.action.RotateTo;
import loon.action.ScaleTo;
import loon.action.ShakeTo;
import loon.action.map.Field2D;
import loon.action.sprite.ISprite;
import loon.canvas.LColor;
import loon.event.SysInput;
import loon.geom.RectBox;
import loon.utils.MathUtils;
import loon.utils.TArray;
public abstract class ActorLayer extends LContainer {
private final static int min_size = 48;
private Field2D tmpField;
private boolean isBounded;
protected int cellSize;
CollisionChecker collisionChecker;
ActorTreeSet objects;
long elapsedTime;
private int tileSize = 32;
public ActorLayer(int x, int y, int layerWidth, int layerHeight,
int cellSize) {
this(x, y, layerWidth, layerHeight, cellSize, true);
}
public ActorLayer(int x, int y, int layerWidth, int layerHeight,
int cellSize, boolean bounded) {
super(x, y, layerWidth, layerHeight);
this.collisionChecker = new CollisionManager();
this.objects = new ActorTreeSet();
this.cellSize = cellSize;
this.initialize(layerWidth, layerHeight, cellSize);
this.isBounded = bounded;
}
private void initialize(int width, int height, int cellSize) {
this.cellSize = cellSize;
this.collisionChecker.initialize(cellSize);
}
public SysInput screenInput() {
return input;
}
public int getCellSize() {
return this.cellSize;
}
public void setCellSize(int cellSize) {
synchronized (collisionChecker) {
this.cellSize = cellSize;
this.collisionChecker.initialize(cellSize);
}
}
/**
* 让指定对象执行MoveTo事件
*
* @param field
* @param o
* @param flag
* @param x
* @param y
* @return
*/
public MoveTo callMoveTo(Field2D field, ActionBind o, boolean flag, int x,
int y) {
if (isClose) {
return null;
}
MoveTo move = new MoveTo(field, x, y, flag);
addActionEvent(move, o);
return move;
}
/**
* 让指定对象执行MoveTo事件
*
* @param field
* @param o
* @param x
* @param y
* @return
*/
public MoveTo callMoveTo(Field2D field, ActionBind o, int x, int y) {
return callMoveTo(field, o, true, x, y);
}
/**
* 让指定对象执行MoveTo事件
*
* @param o
* @param flag
* @param x
* @param y
* @param w
* @param h
* @return
*/
public MoveTo callMoveTo(ActionBind o, boolean flag, int x, int y, int w,
int h) {
if (isClose) {
return null;
}
if (tmpField == null) {
tmpField = createArrayMap(w, h);
}
MoveTo move = new MoveTo(tmpField, x, y, flag);
addActionEvent(move, o);
return move;
}
/**
* 让指定对象执行MoveTo事件
*
* @param o
* @param x
* @param y
* @param w
* @param h
* @return
*/
public MoveTo callMoveTo(ActionBind o, int x, int y, int w, int h) {
return callMoveTo(o, true, x, y, w, h);
}
/**
* 让指定对象执行MoveTo事件
*
* @param o
* @param x
* @param y
* @return
*/
public MoveTo callMoveTo(ActionBind o, int x, int y) {
return callMoveTo(o, x, y, tileSize, tileSize);
}
/**
* 让指定对象执行MoveTo事件
*
* @param o
* @param x
* @param y
* @param flag
* @return
*/
public MoveTo callMoveTo(ActionBind o, int x, int y, boolean flag) {
return callMoveTo(o, flag, x, y, tileSize, tileSize);
}
/**
* 让指定对象执行FadeTo事件
*
* @param o
* @param type
* @param speed
* @return
*/
public FadeTo callFadeTo(ActionBind o, int type, int speed) {
if (isClose) {
return null;
}
FadeTo fade = new FadeTo(type, speed);
addActionEvent(fade, o);
return fade;
}
/**
* 让指定对象执行FadeTo淡入事件
*
* @param o
* @param speed
* @return
*/
public FadeTo callFadeInTo(ActionBind o, int speed) {
return callFadeTo(o, ISprite.TYPE_FADE_IN, speed);
}
/**
* 让指定对象执行FadeTo淡出事件
*
* @param o
* @param speed
* @return
*/
public FadeTo callFadeOutTo(ActionBind o, int speed) {
return callFadeTo(o, ISprite.TYPE_FADE_OUT, speed);
}
/**
* 让指定对象执行RotateTo旋转事件
*
* @param o
* @param angle
* @param speed
* @return
*/
public RotateTo callRotateTo(ActionBind o, float angle, float speed) {
if (isClose) {
return null;
}
RotateTo rotate = new RotateTo(angle, speed);
addActionEvent(rotate, o);
return rotate;
}
/**
* 让指定对象执行JumpTo跳跃事件
*
* @param o
* @param j
* @param g
* @return
*/
public JumpTo callJumpTo(ActionBind o, int j, float g) {
if (isClose) {
return null;
}
JumpTo jump = new JumpTo(j, g);
addActionEvent(jump, o);
return jump;
}
/**
* 让指定角色根据指定半径以指定速度循环转动
*
* @param o
* @param radius
* @param velocity
* @return
*/
public CircleTo callCircleTo(ActionBind o, int radius, int velocity) {
if (isClose) {
return null;
}
CircleTo circle = new CircleTo(radius, velocity);
addActionEvent(circle, o);
return circle;
}
/**
* 向指定坐标以指定速度让指定角色做为子弹发射
*
* @param o
* @param x
* @param y
* @param speed
* @return
*/
public FireTo callFireTo(ActionBind o, float x, float y, float speed) {
if (isClose) {
return null;
}
FireTo fire = new FireTo(x, y, speed);
addActionEvent(fire, o);
return fire;
}
/**
* 让角色缩放指定大小
*
* @param o
* @param sx
* @param sy
* @return
*/
public ScaleTo callScaleTo(ActionBind o, float sx, float sy) {
if (isClose) {
return null;
}
ScaleTo scale = new ScaleTo(sx, sy);
addActionEvent(scale, o);
return scale;
}
/**
* 让角色缩放指定大小
*
* @param o
* @param s
* @return
*/
public ScaleTo callScaleTo(ActionBind o, float s) {
return callScaleTo(o, s, s);
}
/**
* 让指定角色做箭状发射(抛物线)
*
* @param o
* @param tx
* @param ty
* @return
*/
public ArrowTo callArrowTo(ActionBind o, float tx, float ty) {
if (isClose) {
return null;
}
ArrowTo arrow = new ArrowTo(tx, ty);
addActionEvent(arrow, o);
return arrow;
}
/**
* 渐变对象到指定颜色
*
* @param o
* @param start
* @param end
* @return
*/
public ColorTo callColorTo(ActionBind o, LColor start, LColor end) {
if (isClose) {
return null;
}
ColorTo color = new ColorTo(start, end, 1f);
addActionEvent(color, o);
return color;
}
/**
* 渐变对象到指定颜色
*
* @param o
* @param end
* @param duration
* @return
*/
public ColorTo callColorTo(ActionBind o, LColor end, float duration) {
if (isClose) {
return null;
}
ColorTo color = new ColorTo(o.getColor(), end, duration);
addActionEvent(color, o);
return color;
}
/**
* 渐变对象到指定颜色
*
* @param o
* @param start
* @param end
* @param duration
* @param delay
* @return
*/
public ColorTo callColorTo(ActionBind o, LColor start, LColor end,
float duration, float delay) {
if (isClose) {
return null;
}
ColorTo color = new ColorTo(start, end, duration, delay);
addActionEvent(color, o);
return color;
}
/**
* 振动指定对象
*
* @param o
* @param shakeX
* @param shakeY
* @return
*/
public ShakeTo callShakeTo(ActionBind o, float shakeX, float shakeY) {
if (isClose) {
return null;
}
ShakeTo shake = new ShakeTo(shakeX, shakeY);
addActionEvent(shake, o);
return shake;
}
/**
* 振动指定对象
*
* @param o
* @param shakeX
* @param shakeY
* @param duration
* @param delay
* @return
*/
public ShakeTo callShakeTo(ActionBind o, float shakeX, float shakeY,
float duration, float delay) {
if (isClose) {
return null;
}
ShakeTo shake = new ShakeTo(shakeX, shakeY, duration, delay);
addActionEvent(shake, o);
return shake;
}
/**
* 以指定瓦片大小创建数组地图
*
* @param tileWidth
* @param tileHeight
* @return
*/
public Field2D createArrayMap(int tileWidth, int tileHeight) {
if (isClose) {
return null;
}
tmpField = new Field2D(
new int[(int) (getHeight() / tileHeight)][(int) (getWidth() / tileWidth)],
tileWidth, tileHeight);
return tmpField;
}
/**
* 设定Layer对应的二维数组地图
*
* @param map
*/
public void setField2D(Field2D field) {
if (isClose) {
return;
}
if (field == null) {
return;
}
if (tmpField != null) {
if ((field.getMap().length == tmpField.getMap().length)
&& (field.getTileWidth() == tmpField.getTileWidth())
&& (field.getTileHeight() == tmpField.getTileHeight())) {
tmpField.set(field.getMap(), field.getTileWidth(),
field.getTileHeight());
}
} else {
tmpField = field;
}
}
/**
* 返回Layer对应的二维数据地图
*
* @param map
*/
@Override
public Field2D getField2D() {
return tmpField;
}
/**
* 添加角色到Layer(在Layer中添加的角色将自动赋予碰撞检查)
*
* @param object
* @param x
* @param y
*/
public void addObject(Actor object, float x, float y) {
if (isClose) {
return;
}
synchronized (objects) {
if (this.objects.add(object)) {
object.addLayer(x, y, this);
object.setState(State.ADDED);
this.collisionChecker.addObject(object);
object.addLayer(this);
}
}
}
/**
* 添加角色到Layer
*
* @param object
*/
public void addObject(Actor object) {
if (isClose) {
return;
}
addObject(object, object.x(), object.y());
}
/**
* 将指定角色于Layer前置
*
* @param actor
*/
void sendToFront(Actor actor) {
if (isClose) {
return;
}
if (objects != null) {
synchronized (objects) {
if (objects != null) {
objects.sendToFront(actor);
}
}
}
}
/**
* 将指定角色于Layer后置
*
* @param actor
*/
void sendToBack(Actor actor) {
if (isClose) {
return;
}
if (objects != null) {
synchronized (objects) {
if (objects != null) {
objects.sendToBack(actor);
}
}
}
}
/**
* 参考指定大小根据Layer范围生成一组不重复的随机坐标
*
* @param act
* @param count
* @return
*/
public RectBox[] getRandomLayerLocation(int nx, int ny, int nw, int nh,
int count) {
if (isClose) {
return null;
}
if (count <= 0) {
throw LSystem.runThrow("count <= 0 !");
}
int layerWidth = (int) getWidth();
int layerHeight = (int) getHeight();
int actorWidth = nw > min_size ? nw : min_size;
int actorHeight = nh > min_size ? nh : min_size;
int x = nx / actorWidth;
int y = ny / actorHeight;
int row = layerWidth / actorWidth;
int col = layerHeight / actorHeight;
RectBox[] randoms = new RectBox[count];
int oldRx = 0, oldRy = 0;
int index = 0;
for (int i = 0; i < count * 100; i++) {
if (index >= count) {
return randoms;
}
int rx = MathUtils.random(row);
int ry = MathUtils.random(col);
if (oldRx != rx && oldRy != ry && rx != x && ry != y
&& rx * actorWidth != nx && ry * actorHeight != ny) {
boolean stop = false;
for (int j = 0; j < index; j++) {
if (randoms[j].x == rx && randoms[j].y == ry && oldRx != x
&& oldRy != y && rx * actorWidth != nx
&& ry * actorHeight != ny) {
stop = true;
break;
}
}
if (stop) {
continue;
}
randoms[index] = new RectBox(rx * actorWidth, ry * actorHeight,
actorWidth, actorHeight);
oldRx = rx;
oldRy = ry;
index++;
}
}
return null;
}
/**
* 参考指定大小根据Layer范围生成一组不重复的随机坐标
*
* @param actorWidth
* @param actorHeight
* @param count
* @return
*/
public RectBox[] getRandomLayerLocation(int actorWidth, int actorHeight,
int count) {
if (isClose) {
return null;
}
return getRandomLayerLocation(0, 0, actorWidth, actorHeight, count);
}
/**
* 参考指定角色根据Layer范围生成一组不重复的随机坐标
*
* @param actor
* @param count
* @return
*/
public RectBox[] getRandomLayerLocation(Actor actor, int count) {
if (isClose) {
return null;
}
RectBox rect = actor.getRectBox();
return getRandomLayerLocation((int) rect.x, (int) rect.y, rect.width,
rect.height, count);
}
/**
* 参考指定Actor大小根据Layer生成一个不重复的随机坐标
*
* @param actor
* @return
*/
public RectBox getRandomLayerLocation(Actor actor) {
if (isClose) {
return null;
}
RectBox[] rects = getRandomLayerLocation(actor, 1);
if (rects != null) {
return rects[0];
}
return null;
}
/**
* 删除指定的角色
*
* @param object
*/
public void removeObject(Actor object) {
if (isClose) {
return;
}
if (objects.size() == 0) {
return;
}
synchronized (objects) {
if (this.objects.remove(object)) {
this.collisionChecker.removeObject(object);
}
if (object != null) {
object.setState(State.REMOVED);
removeActionEvents(object);
object.setLayer((ActorLayer) null);
}
}
}
/**
* 删除指定集合中的所有角色
*
* @param objects
*/
public void removeObjects(TArray<Actor> objects) {
if (isClose) {
return;
}
synchronized (objects) {
Iterator<Actor> iter = objects.iterator();
while (iter.hasNext()) {
Actor actor = iter.next();
this.removeObject(actor);
}
}
}
/**
* 删除指定集合中的所有角色
*
* @param flagName
*/
public void removeObject(String flagName) {
if (isClose) {
return;
}
synchronized (objects) {
Iterator<Actor> it = objects.iterator();
while (it.hasNext()) {
Actor actor = it.next();
if (actor == null) {
continue;
}
String flag = actor.getFlag();
if (flagName == null || flagName == flag
|| flagName.equals(flag)) {
if (this.objects.remove(actor)) {
this.collisionChecker.removeObject(actor);
}
actor.setState(State.REMOVED);
removeActionEvents(actor);
actor.setLayer((ActorLayer) null);
}
}
}
}
/**
* 获得含有指定角色碰撞的List集合
*
* @param actor
* @return
*/
public TArray<Actor> getCollisionObjects(Actor actor) {
if (isClose) {
return null;
}
return getCollisionObjects(actor.getFlag());
}
/**
* 刷新缓存数据,重置世界
*
*/
public void reset() {
if (isClose) {
return;
}
if (objects != null) {
synchronized (objects) {
if (objects != null) {
objects.clear();
objects = null;
}
if (collisionChecker != null) {
collisionChecker.dispose();
collisionChecker.clear();
collisionChecker = null;
}
this.collisionChecker = new CollisionManager();
this.objects = new ActorTreeSet();
}
}
}
/**
* 获得指定类所产生角色碰撞的List集合
*
* @param flag
* @return
*/
public TArray<Actor> getCollisionObjects(String flag) {
if (isClose) {
return null;
}
return this.collisionChecker.getObjects(flag);
}
/**
* 返回指定角色类在指定位置的List集合
*
* @param x
* @param y
* @param flag
* @return
*/
public TArray<Actor> getCollisionObjectsAt(float x, float y, String flag) {
if (isClose) {
return null;
}
return this.collisionChecker.getObjectsAt(x, y, flag);
}
/**
* 返回指定区域对应的单一Actor
*
* @param x
* @param y
* @return
*/
public Actor getOnlyCollisionObjectsAt(float x, float y) {
if (isClose) {
return null;
}
return objects.getOnlyCollisionObjectsAt(x, y);
}
/**
* 返回指定区域和标记对应的单一Actor
*
* @param x
* @param y
* @return
*/
public Actor getOnlyCollisionObjectsAt(float x, float y, Object tag) {
if (isClose) {
return null;
}
return objects.getOnlyCollisionObjectsAt(x, y, tag);
}
/**
* 角色对象总数
*
* @return
*/
public int size() {
if (isClose) {
return 0;
}
return this.objects.size();
}
public abstract void action(long elapsedTime);
@Override
public boolean isBounded() {
return this.isBounded;
}
Actor getSynchronizedObject(float x, float y) {
if (isClose) {
return null;
}
return objects.getSynchronizedObject(x, y);
}
TArray<Actor> getIntersectingObjects(Actor actor, String flag) {
if (isClose) {
return null;
}
return this.collisionChecker.getIntersectingObjects(actor, flag);
}
Actor getOnlyIntersectingObject(Actor object, String flag) {
if (isClose) {
return null;
}
return this.collisionChecker.getOnlyIntersectingObject(object, flag);
}
TArray<Actor> getObjectsInRange(float x, float y, float r, String flag) {
if (isClose) {
return null;
}
return this.collisionChecker.getObjectsInRange(x, y, r, flag);
}
TArray<Actor> getNeighbours(Actor actor, float distance, boolean d,
String flag) {
if (isClose) {
return null;
}
if (distance < 0) {
throw LSystem.runThrow("distance < 0");
} else {
return this.collisionChecker
.getNeighbours(actor, distance, d, flag);
}
}
int getHeightInPixels() {
return (int) (this.getHeight() * this.cellSize);
}
int getWidthInPixels() {
return (int) (this.getWidth() * this.cellSize);
}
int toCellCeil(float pixel) {
return MathUtils.ceil(pixel / this.cellSize);
}
int toCellFloor(float pixel) {
return MathUtils.floor(pixel / this.cellSize);
}
float getCellCenter(float c) {
float cellCenter = (c * this.cellSize) + this.cellSize / 2.0f;
return cellCenter;
}
TArray<Actor> getCollisionObjects(float x, float y) {
if (isClose) {
return null;
}
return collisionChecker.getObjectsAt(x, y, null);
}
void updateObjectLocation(Actor object, float oldX, float oldY) {
if (isClose) {
return;
}
this.collisionChecker.updateObjectLocation(object, oldX, oldY);
}
void updateObjectSize(Actor object) {
if (isClose) {
return;
}
this.collisionChecker.updateObjectSize(object);
}
Actor getOnlyObjectAt(Actor object, float dx, float dy, String flag) {
if (isClose) {
return null;
}
return this.collisionChecker.getOnlyObjectAt(object, dx, dy, flag);
}
ActorTreeSet getObjectsListInPaintO() {
if (isClose) {
return null;
}
return this.objects;
}
public int getTileSize() {
return tileSize;
}
public void setTileSize(int tileSize) {
this.tileSize = tileSize;
}
}