/** * Copyright 2008 - 2010 * * 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.5 */ package loon.action.sprite; import loon.LObject.State; import loon.LRelease; import loon.LSystem; import loon.Screen; import loon.action.ActionBind; import loon.action.ActionControl; import loon.geom.PointI; import loon.geom.RectBox; import loon.opengl.GLEx; import loon.utils.CollectionUtils; import loon.utils.IArray; import loon.utils.LayerSorter; import loon.utils.MathUtils; import loon.utils.TArray; /** * 精灵精灵总父类,用来注册,控制,以及渲染所有精灵精灵(所有默认【不支持】触屏的精灵,被置于此。不过, * 当LNode系列精灵和SpriteBatchScreen合用时,也支持触屏.) * */ public class Sprites implements IArray, LRelease { private final static TArray<Sprites> SPRITES_CACHE = new TArray<Sprites>(8); public final static int allSpritesCount() { int size = 0; for (int i = 0, len = SPRITES_CACHE.size; i < len; i++) { size += SPRITES_CACHE.get(i).size(); } return size; } public static interface SpriteListener { public void update(ISprite spr); } protected ISprite[] _sprites; private int viewX; private int viewY; private boolean _isViewWindowSet = false, _visible = true; private SpriteListener sprListerner; private final static LayerSorter<ISprite> spriteSorter = new LayerSorter<ISprite>(false); private int capacity = 128; private int _size; private int _width, _height; private Screen _screen; public Sprites(Screen screen, float width, float height) { this(screen, (int) width, (int) height); } public Sprites(Screen screen, int w, int h) { this._screen = screen; this._visible = true; this._width = w; this._height = h; this._sprites = new ISprite[capacity]; SPRITES_CACHE.add(this); } public Sprites(Screen screen) { this(screen, LSystem.viewSize.getWidth(), LSystem.viewSize.getHeight()); } /** * 设定指定对象到图层最前 * * @param sprite */ public void sendToFront(ISprite sprite) { if (this._size <= 1 || this._sprites[0] == sprite) { return; } if (_sprites[0] == sprite) { return; } for (int i = 0; i < this._size; i++) { if (this._sprites[i] == sprite) { this._sprites = CollectionUtils.cut(this._sprites, i); this._sprites = CollectionUtils.expand(this._sprites, 1, false); this._sprites[0] = sprite; this.sortSprites(); break; } } } /** * 设定指定对象到图层最后 * * @param sprite */ public void sendToBack(ISprite sprite) { if (this._size <= 1 || this._sprites[this._size - 1] == sprite) { return; } if (_sprites[this._size - 1] == sprite) { return; } for (int i = 0; i < this._size; i++) { if (this._sprites[i] == sprite) { this._sprites = CollectionUtils.cut(this._sprites, i); this._sprites = CollectionUtils.expand(this._sprites, 1, true); this._sprites[this._size - 1] = sprite; this.sortSprites(); break; } } } /** * 按所在层级排序 * */ public void sortSprites() { spriteSorter.sort(this._sprites); } /** * 扩充当前集合容量 * * @param capacity */ private void expandCapacity(int capacity) { if (_sprites.length < capacity) { ISprite[] bagArray = new ISprite[capacity]; System.arraycopy(_sprites, 0, bagArray, 0, _size); _sprites = bagArray; } } /** * 压缩当前集合容量 * * @param capacity */ private void compressCapacity(int capacity) { if (capacity + this._size < _sprites.length) { ISprite[] newArray = new ISprite[this._size + 2]; System.arraycopy(_sprites, 0, newArray, 0, this._size); _sprites = newArray; } } /** * 查找指定位置的精灵对象 * * @param x * @param y * @return */ public ISprite find(int x, int y) { ISprite[] snapshot = _sprites; for (int i = snapshot.length - 1; i >= 0; i--) { ISprite child = snapshot[i]; RectBox rect = child.getCollisionBox(); if (rect != null && rect.contains(x, y)) { return child; } } return null; } /** * 查找指定名称的精灵对象 * * @param name * @return */ public ISprite find(String name) { ISprite[] snapshot = _sprites; for (int i = snapshot.length - 1; i >= 0; i--) { ISprite child = snapshot[i]; String childName = child.getName(); if (name.equals(childName)) { return child; } } return null; } /** * 在指定索引处插入一个精灵 * * @param index * @param sprite * @return */ public boolean add(int index, ISprite sprite) { if (sprite == null) { return false; } if (index > this._size) { index = this._size; } if (index == this._size) { return this.add(sprite); } else { if (sprite.getWidth() > getWidth()) { setViewWindow(viewX, viewY, (int) sprite.getWidth(), _height); } if (sprite.getHeight() > getHeight()) { setViewWindow(viewX, viewY, _width, (int) sprite.getHeight()); } System.arraycopy(this._sprites, index, this._sprites, index + 1, this._size - index); this._sprites[index] = sprite; if (++this._size >= this._sprites.length) { expandCapacity((_size + 1) * 2); } sortSprites(); sprite.setState(State.ADDED); } boolean result = _sprites[index] != null; return result; } public void addAt(ISprite child, float x, float y) { if (child != null) { child.setLocation(x, y); add(child); } } public ISprite getSprite(int index) { if (index < 0 || index > _size || index >= _sprites.length) { return null; } return _sprites[index]; } /** * 返回位于顶部的精灵 * * @return */ public ISprite getTopSprite() { if (_size > 0) { return _sprites[0]; } return null; } /** * 返回位于底部的精灵 * * @return */ public ISprite getBottomSprite() { if (_size > 0) { return _sprites[_size - 1]; } return null; } /** * 顺序添加精灵 * * @param sprite * @return */ public boolean add(ISprite sprite) { if (contains(sprite)) { return false; } if (sprite.getWidth() > getWidth()) { setViewWindow(viewX, viewY, (int) sprite.getWidth(), _height); } if (sprite.getHeight() > getHeight()) { setViewWindow(viewX, viewY, _width, (int) sprite.getHeight()); } if (this._size == this._sprites.length) { expandCapacity((_size + 1) * 2); } boolean result = (_sprites[_size++] = sprite) != null; sortSprites(); sprite.setState(State.ADDED); return result; } /** * 顺序添加精灵 * * @param sprite * @return */ public void append(ISprite sprite) { add(sprite); } /** * 返回一组拥有指定标签的精灵 * * @param tags * @return */ public TArray<ISprite> findTags(Object... tags) { TArray<ISprite> list = new TArray<ISprite>(); final int size = this._size; for (Object tag : tags) { for (int i = size - 1; i > -1; i--) { if (this._sprites[i] instanceof ISprite) { ISprite sp = (ISprite) this._sprites[i]; if (sp.getTag() == tag || tag.equals(sp.getTag())) { list.add(sp); } } } } return list; } /** * 返回一组没有指定标签的精灵 * * @param tags * @return */ public TArray<ISprite> findNotTags(Object... tags) { TArray<ISprite> list = new TArray<ISprite>(); final int size = this._size; for (Object tag : tags) { for (int i = size - 1; i > -1; i--) { if (this._sprites[i] instanceof ISprite) { ISprite sp = (ISprite) this._sprites[i]; if (!tag.equals(sp.getTag())) { list.add(sp); } } } } return list; } /** * 返回一组指定名的精灵 * * @param names * @return */ public TArray<ISprite> findNames(String... names) { TArray<ISprite> list = new TArray<ISprite>(); final int size = this._size; for (String name : names) { for (int i = size - 1; i > -1; i--) { if (this._sprites[i] instanceof ISprite) { ISprite sp = (ISprite) this._sprites[i]; if (name.equals(sp.getName())) { list.add(sp); } } } } return list; } /** * 返回一组没有指定名的精灵 * * @param names * @return */ public TArray<ISprite> findNotNames(String... names) { TArray<ISprite> list = new TArray<ISprite>(); final int size = this._size; for (String name : names) { for (int i = size - 1; i > -1; i--) { if (this._sprites[i] instanceof ISprite) { ISprite sp = (ISprite) this._sprites[i]; if (!name.equals(sp.getName())) { list.add(sp); } } } } return list; } /** * 检查指定精灵是否存在 * * @param sprite * @return */ public boolean contains(ISprite sprite) { if (sprite == null) { return false; } if (_sprites == null) { return false; } for (int i = 0; i < _size; i++) { if (_sprites[i] != null && sprite.equals(_sprites[i])) { return true; } } return false; } /** * 删除指定索引处精灵 * * @param index * @return */ public ISprite remove(int index) { ISprite removed = this._sprites[index]; if (removed != null) { removed.setState(State.REMOVED); // 删除精灵同时,删除缓动动画 if (removed instanceof ActionBind) { ActionControl.get().removeAllActions((ActionBind) removed); } } int size = this._size - index - 1; if (size > 0) { System.arraycopy(this._sprites, index + 1, this._sprites, index, size); } this._sprites[--this._size] = null; if (size == 0) { _sprites = new ISprite[0]; } return removed; } /** * 清空所有精灵 * */ public void removeAll() { clear(); this._sprites = new ISprite[0]; } /** * 删除指定精灵 * * @param sprite * @return */ public boolean remove(ISprite sprite) { if (sprite == null) { return false; } if (_sprites == null) { return false; } boolean removed = false; for (int i = _size; i > 0; i--) { ISprite spr = _sprites[i - 1]; if ((sprite == spr) || (sprite.equals(spr))) { spr.setState(State.REMOVED); // 删除精灵同时,删除缓动动画 if (spr instanceof ActionBind) { ActionControl.get().removeAllActions((ActionBind) spr); } removed = true; _size--; _sprites[i - 1] = _sprites[_size]; _sprites[_size] = null; if (_size == 0) { _sprites = new ISprite[0]; } else { compressCapacity(2); } return removed; } } return removed; } /** * 删除指定名称的精灵 * * @param name * @return */ public boolean removeName(String name) { if (name == null) { return false; } if (_sprites == null) { return false; } boolean removed = false; for (int i = _size; i > 0; i--) { ISprite spr = _sprites[i - 1]; if ((name.equals(spr.getName()))) { spr.setState(State.REMOVED); // 删除精灵同时,删除缓动动画 if (spr instanceof ActionBind) { ActionControl.get().removeAllActions((ActionBind) spr); } removed = true; _size--; _sprites[i - 1] = _sprites[_size]; _sprites[_size] = null; if (_size == 0) { _sprites = new ISprite[0]; } else { compressCapacity(2); } return removed; } } return removed; } /** * 删除指定范围内精灵 * * @param startIndex * @param endIndex */ public void remove(int startIndex, int endIndex) { if (endIndex - startIndex > 0) { for (int i = startIndex; i < endIndex && i < _sprites.length; i++) { ISprite spr = _sprites[i]; if (spr != null) { spr.setState(State.REMOVED); // 删除精灵同时,删除缓动动画 if (spr instanceof ActionBind) { ActionControl.get().removeAllActions((ActionBind) spr); } } } } int numMoved = this._size - endIndex; System.arraycopy(this._sprites, endIndex, this._sprites, startIndex, numMoved); int newSize = this._size - (endIndex - startIndex); while (this._size != newSize) { this._sprites[--this._size] = null; } if (_size == 0) { _sprites = new ISprite[0]; } } public PointI getMinPos() { PointI p = new PointI(0, 0); for (int i = 0; i < _size; i++) { ISprite sprite = _sprites[i]; p.x = MathUtils.min(p.x, sprite.x()); p.y = MathUtils.min(p.y, sprite.y()); } return p; } public PointI getMaxPos() { PointI p = new PointI(0, 0); for (int i = 0; i < _size; i++) { ISprite sprite = _sprites[i]; p.x = MathUtils.max(p.x, sprite.x()); p.y = MathUtils.max(p.y, sprite.y()); } return p; } /** * 清空当前精灵集合 * */ public void clear() { for (int i = 0; i < _sprites.length; i++) { ISprite removed = _sprites[i]; if (removed != null) { removed.setState(State.REMOVED); // 删除精灵同时,删除缓动动画 if (removed instanceof ActionBind) { ActionControl.get().removeAllActions((ActionBind) removed); } } _sprites[i] = null; } _size = 0; } /** * 刷新事务 * * @param elapsedTime */ public void update(long elapsedTime) { boolean listerner = (sprListerner != null); for (int i = _size - 1; i >= 0; i--) { ISprite child = _sprites[i]; if (child.isVisible()) { child.update(elapsedTime); if (listerner) { sprListerner.update(child); } } } } /** * 单纯渲染精灵 * * @param g */ public void paint(final GLEx g, final float minX, final float minY, final float maxX, final float maxY) { float spriteX; float spriteY; float spriteWidth; float spriteHeight; for (int i = 0; i < this._size; i++) { ISprite spr = this._sprites[i]; if (spr != null && spr.isVisible()) { spriteX = minX + spr.getX(); spriteY = minY + spr.getY(); spriteWidth = spr.getWidth(); spriteHeight = spr.getHeight(); if (spriteX + spriteWidth < minX || spriteX > maxX || spriteY + spriteHeight < minY || spriteY > maxY) { continue; } spr.createUI(g); } } } public void paintPos(final GLEx g, final float offsetX, final float offsetY) { for (int i = 0; i < this._size; i++) { ISprite spr = this._sprites[i]; if (spr != null && spr.isVisible()) { spr.createUI(g, offsetX, offsetY); } } } /** * 创建UI图像 * * @param g */ public void createUI(final GLEx g) { createUI(g, 0, 0); } /** * 创建UI图像 * * @param g */ public void createUI(final GLEx g, final int x, final int y) { if (!_visible) { return; } float minX, minY, maxX, maxY; if (this._isViewWindowSet) { g.setClip(x, y, this._width, this._height); minX = this.viewX; maxX = minX + this._width; minY = this.viewY; maxY = minY + this._height; } else { minX = x; maxX = x + this._width; minY = y; maxY = y + this._height; } g.translate(x - this.viewX, y - this.viewY); for (int i = 0; i < this._size; i++) { ISprite spr = this._sprites[i]; if (spr != null && spr.isVisible()) { int layerX = spr.x(); int layerY = spr.y(); float layerWidth = spr.getWidth() + 1; float layerHeight = spr.getHeight() + 1; if (layerX + layerWidth < minX || layerX > maxX || layerY + layerHeight < minY || layerY > maxY) { continue; } spr.createUI(g); } } g.translate(-(x - this.viewX), -(y - this.viewY)); if (this._isViewWindowSet) { g.clearClip(); } } /** * 设定精灵集合在屏幕中的位置与大小 * * @param x * @param y * @param width * @param height */ public void setViewWindow(int x, int y, int width, int height) { this._isViewWindowSet = true; this.viewX = x; this.viewY = y; this._width = width; this._height = height; } /** * 设定精灵集合在屏幕中的位置 * * @param x * @param y */ public void setLocation(int x, int y) { this._isViewWindowSet = true; this.viewX = x; this.viewY = y; } public SpriteControls createSpriteControls() { SpriteControls controls = null; if (_sprites != null) { controls = new SpriteControls(_sprites); } else { controls = new SpriteControls(); } return controls; } public SpriteControls findNamesToSpriteControls(String... names) { SpriteControls controls = null; if (_sprites != null) { TArray<ISprite> sps = findNames(names); controls = new SpriteControls(sps); } else { controls = new SpriteControls(); } return controls; } public SpriteControls findNotNamesToSpriteControls(String... names) { SpriteControls controls = null; if (_sprites != null) { TArray<ISprite> sps = findNotNames(names); controls = new SpriteControls(sps); } else { controls = new SpriteControls(); } return controls; } public SpriteControls findTagsToSpriteControls(Object... o) { SpriteControls controls = null; if (_sprites != null) { TArray<ISprite> sps = findTags(o); controls = new SpriteControls(sps); } else { controls = new SpriteControls(); } return controls; } public SpriteControls findNotTagsToSpriteControls(Object... o) { SpriteControls controls = null; if (_sprites != null) { TArray<ISprite> sps = findNotTags(o); controls = new SpriteControls(sps); } else { controls = new SpriteControls(); } return controls; } public ISprite[] getSprites() { return CollectionUtils.copyOf(this._sprites, this._size); } public int size() { return this._size; } public int getHeight() { return _height; } public int getWidth() { return _width; } public boolean isVisible() { return _visible; } public void setVisible(boolean visible) { this._visible = visible; } public SpriteListener getSprListerner() { return sprListerner; } public void setSprListerner(SpriteListener sprListerner) { this.sprListerner = sprListerner; } public Screen getScreen() { return _screen; } @Override public boolean isEmpty() { return _size == 0 || _sprites == null; } @Override public void close() { this._visible = false; for (ISprite spr : _sprites) { if (spr != null) { spr.close(); } } clear(); SPRITES_CACHE.remove(this); } }