/** * 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 loon.LObject; import loon.LSystem; import loon.Screen; import loon.action.map.Config; import loon.action.map.TileMap; import loon.event.GameKey; import loon.geom.AABB; import loon.geom.RectBox; import loon.geom.Vector2f; import loon.opengl.BlendState; import loon.opengl.GLEx; import loon.physics.PBody; import loon.physics.PPhysManager; import loon.physics.PShape; import loon.physics.PWorldBox; import loon.utils.CollectionUtils; import loon.utils.MathUtils; import loon.utils.ObjectMap; import loon.utils.TArray; import loon.utils.timer.LTimerContext; /** * 该类为0.3.3版最新增加的Screen类,图形渲染使用单一的SpriteBatch,相较于使用GLEx,更适合多纹理渲染。 * */ public abstract class SpriteBatchScreen extends Screen implements Config { private float objX = 0, objY = 0; private SpriteBatch _batch; private TArray<ActionObject> objects; private TArray<ActionObject> pendingAdd; private TArray<ActionObject> pendingRemove; private TArray<TileMap> tiles = new TArray<TileMap>(10); private Vector2f offset = new Vector2f(); private LObject<?> follow; private TileMap indexTile; protected UpdateListener updateListener; private boolean usePhysics = false; private PPhysManager _manager; private PWorldBox _box; private boolean _useGLEx = false; private boolean _fixed = false; private float _dt = 1F / 60F; private RectBox _physicsRect; private ObjectMap<ActionObject, PBody> _bodys = new ObjectMap<ActionObject, PBody>( CollectionUtils.INITIAL_CAPACITY); private void limitWorld(boolean _fixed) { if (_fixed) { if (this._box == null) { this._box = new PWorldBox(_manager, 0f, 0f, getWidth(), getHeight()); } if (_physicsRect != null) { this._box.set(_physicsRect.x, _physicsRect.y, _physicsRect.width, _physicsRect.height); } this._box.build(); } else { if (_box != null) { this._box.removeWorld(); } } } public PPhysManager getPhysicsManager() { if (!usePhysics) { throw LSystem.runThrow("You do not set the physics engine !"); } return _manager; } public boolean isPhysics() { return usePhysics; } public void setPhysicsRect(float x, float y, float w, float h) { if (this._physicsRect == null) { this._physicsRect = new RectBox(x, y, w, h); } else { this._physicsRect.setBounds(x, y, w, h); } } public void setPhysics(boolean fix, PPhysManager man) { this._manager = man; this._fixed = fix; this.limitWorld(_fixed); this.usePhysics = true; } public void setPhysics(boolean fix, float scale, float gx, float gy) { if (_manager == null) { this._manager = new PPhysManager(scale, gx, gy); } else { this._manager.scale = scale; this._manager.gravity.set(gx, gy); } this._manager.setEnableGravity(true); this._manager.setStart(true); this._fixed = fix; this.limitWorld(_fixed); this.usePhysics = true; } public void setPhysics(boolean fix) { setPhysics(fix, 10F); } public void setPhysics(boolean fix, float scale) { if (_manager == null) { this._manager = new PPhysManager(scale); } else { this._manager.scale = scale; } this._manager.setEnableGravity(true); this._manager.setStart(true); this._fixed = fix; this.limitWorld(_fixed); this.usePhysics = true; } public float getTimeStep() { return this._dt; } public void setTimeStep(float dt) { this._dt = dt; } public abstract void onResume(); @Override public void resume() { if (usePhysics) { _manager.setStart(true); _manager.setEnableGravity(true); } onResume(); } public abstract void onPause(); @Override public void pause() { if (usePhysics) { _manager.setStart(false); _manager.setEnableGravity(false); } onPause(); } public boolean isFixed() { return _fixed; } public interface UpdateListener { public void act(ActionObject obj, long elapsedTime); } public SpriteBatchScreen() { super(); } public SpriteBatch getSpriteBatch() { return _batch; } protected void init() { this.objects = new TArray<ActionObject>(10); this.pendingAdd = new TArray<ActionObject>(10); this.pendingRemove = new TArray<ActionObject>(10); this._dt = 1 / LSystem.base().setting.fps; } public void commits() { if (isClose()) { return; } final int additionCount = pendingAdd.size; if (additionCount > 0) { for (int i = 0; i < additionCount; i++) { ActionObject object = pendingAdd.get(i); objects.add(object); } pendingAdd.clear(); } final int removalCount = pendingRemove.size; if (removalCount > 0) { for (int i = 0; i < removalCount; i++) { ActionObject object = pendingRemove.get(i); objects.remove(object); } pendingRemove.clear(); } } public ActionObject add(ActionObject object) { pendingAdd.add(object); return object; } public ActionObject remove(ActionObject object) { pendingRemove.add(object); if (usePhysics) { unbindPhysics(object); } return object; } public void removeTileObjects() { final int count = objects.size; final Object[] objectArray = objects.toArray(); for (int i = 0; i < count; i++) { ActionObject o = (ActionObject) objectArray[i]; pendingRemove.add(o); if (usePhysics) { unbindPhysics(o); } } pendingAdd.clear(); } public ActionObject findObject(float x, float y) { for (ActionObject o : objects) { if ((o.getX() == x && o.getY() == y) || o.getRectBox().contains(x, y)) { return o; } } return null; } public TileMap getIndexTile() { return indexTile; } public void setIndexTile(TileMap indexTile) { this.indexTile = indexTile; } public void follow(LObject<?> o) { this.follow = o; } public final void onLoad() { init(); if (_batch == null) { _batch = new SpriteBatch(3000); } _batch.setBlendState(BlendState.Null); onLoading(); } protected void onLoading() { } @Override public final void onLoaded() { // 最先绘制用户画面 setFristOrder(DRAW_USER_PAINT()); // 其次绘制精灵 setSecondOrder(DRAW_SPRITE_PAINT()); // 最后绘制桌面 setLastOrder(DRAW_DESKTOP_PAINT()); create(); } public abstract void create(); public void setOffset(TileMap tile, float sx, float sy) { offset.set(sx, sy); tile.setOffset(offset); } public final Vector2f getOffset() { return offset; } public void putTileMap(TileMap t) { tiles.add(t); } public void removeTileMap(TileMap t) { tiles.remove(t); } public void addTileObject(ActionObject o) { add(o); } public JumpObject addJumpObject(float x, float y, float w, float h, Animation a) { JumpObject o = null; if (indexTile != null) { o = new JumpObject(x, y, w, h, a, indexTile); } else if (tiles.size > 0) { o = new JumpObject(x, y, w, h, a, tiles.get(0)); } else { return null; } add(o); return o; } public MoveObject addMoveObject(float x, float y, float w, float h, Animation a) { MoveObject o = null; if (indexTile != null) { o = new MoveObject(x, y, w, h, a, indexTile); } else if (tiles.size > 0) { o = new MoveObject(x, y, w, h, a, tiles.get(0)); } else { return null; } add(o); return o; } public void removeTileObject(ActionObject o) { remove(o); } public PBody findPhysics(ActionObject o) { if (usePhysics) { PBody body = _bodys.get(o); return body; } else { throw LSystem.runThrow("You do not set the physics engine !"); } } public void unbindPhysics(ActionObject o) { if (usePhysics) { PBody body = _bodys.remove(o); if (body != null) { body.setTag(null); _manager.world.removeBody(body); } } } public PBody addPhysics(boolean fix, ActionObject o, float density) { return bindPhysics(fix, add(o), density); } public PBody addPhysics(boolean fix, ActionObject o) { return bindPhysics(fix, add(o), 1F); } public PBody addTexturePhysics(boolean fix, ActionObject o, float density) throws Exception { return bindTexturePhysics(fix, add(o), density); } public PBody addTexturePhysics(boolean fix, ActionObject o) throws Exception { return bindTexturePhysics(fix, add(o), 1F); } public PBody bindPhysics(boolean fix, ActionObject o, float density) { if (usePhysics) { PBody body = _manager.addBox(fix, o.getRectBox(), MathUtils.toRadians(o.getRotation()), density); body.setTag(o); _bodys.put(o, body); return body; } else { throw LSystem.runThrow("You do not set the physics engine !"); } } public PBody addCirclePhysics(boolean fix, ActionObject o, float density) { return bindCirclePhysics(fix, add(o), density); } public PBody addCirclePhysics(boolean fix, ActionObject o) { return bindCirclePhysics(fix, add(o), 1F); } public PBody bindCirclePhysics(boolean fix, ActionObject o) { return bindCirclePhysics(fix, add(o), 1F); } public PBody bindCirclePhysics(boolean fix, ActionObject o, float density) { if (usePhysics) { RectBox rect = o.getRectBox(); float r = (rect.width + rect.height) / 4; PBody body = _manager.addCircle(fix, o.x(), o.y(), r, MathUtils.toRadians(o.getRotation()), density); body.setTag(o); _bodys.put(o, body); return body; } else { throw LSystem.runThrow("You do not set the physics engine !"); } } public PBody bindTexturePhysics(boolean fix, ActionObject o, float density) throws Exception { if (usePhysics) { PBody body = _manager.addShape(fix, o.getAnimation() .getSpriteImage(), MathUtils.toRadians(o.getRotation()), density); if (body.size() > 0) { body.inner_shapes()[0].setPosition(o.x() / _manager.scale, o.y() / _manager.scale); } body.setTag(o); _bodys.put(o, body); return body; } else { throw LSystem.runThrow("You do not set the physics engine !"); } } public PBody bindTexturePhysics(boolean fix, ActionObject o) throws Exception { return bindTexturePhysics(fix, o, 1F); } public PBody bindPhysics(boolean fix, ActionObject o) { return bindPhysics(fix, o, 1F); } public PBody bindPhysics(PBody body, ActionObject o) { if (usePhysics) { body.setTag(o); _manager.addBody(body); _bodys.put(o, body); return body; } else { throw LSystem.runThrow("You do not set the physics engine !"); } } protected void updating(LTimerContext timer) { } @Override public void alter(LTimerContext timer) { if (!isOnLoadComplete()) { return; } if (usePhysics) { if (_dt < 0) { _manager.step(timer.getMilliseconds()); } else { _manager.step(_dt); } } if (follow != null) { if (usePhysics) { _manager.offset(follow.getX(), follow.getY()); } for (TileMap tile : tiles) { float offsetX = getHalfWidth() - follow.getX(); offsetX = MathUtils.min(offsetX, 0); offsetX = MathUtils.max(offsetX, getWidth() - tile.getWidth()); float offsetY = getHalfHeight() - follow.getY(); offsetY = MathUtils.min(offsetY, 0); offsetY = MathUtils .max(offsetY, getHeight() - tile.getHeight()); setOffset(tile, offsetX, offsetY); tile.update(elapsedTime); } } updating(timer); if (objects != null) { for (ActionObject o : objects) { if (usePhysics) { PBody body = _bodys.get(o); if (body != null) { PShape shape = body.inner_shapes()[0]; final float rotation = (shape.getAngle() * MathUtils.RAD_TO_DEG) % 360; AABB aabb = shape.getAABB(); o.setLocation(_manager.getScreenX(aabb.minX), _manager.getScreenY(aabb.minY)); o.setRotation(rotation); } } o.update(elapsedTime); if (updateListener != null) { updateListener.act(o, elapsedTime); } } } update(elapsedTime); commits(); } protected void drawing(GLEx g, SpriteBatch batch) { } @Override public final void draw(GLEx g) { if (isOnLoadComplete()) { if (_batch == null || _useGLEx) { for (TileMap tile : tiles) { tile.draw(g, _batch, offset.x(), offset.y()); } for (ActionObject o : objects) { objX = o.getX() + offset.x; objY = o.getY() + offset.y; if (intersects(objX, objY, o.getWidth(), o.getHeight()) || contains(objX, objY)) { o.draw(g, offset.x, offset.y); } } drawing(g, _batch); } else { synchronized (_batch) { try { _batch.begin(); before(_batch); for (TileMap tile : tiles) { tile.draw(g, _batch, offset.x(), offset.y()); } for (ActionObject o : objects) { objX = o.getX() + offset.x; objY = o.getY() + offset.y; if (intersects(objX, objY, o.getWidth(), o.getHeight()) || contains(objX, objY)) { o.draw(_batch, offset.x, offset.y); } } drawing(g, _batch); after(_batch); } finally { _batch.end(); } } } } } public abstract void after(SpriteBatch _batch); public abstract void before(SpriteBatch _batch); @Override public final void onKeyDown(GameKey e) { press(e); } public abstract void press(GameKey e); @Override public final void onKeyUp(GameKey e) { release(e); } public abstract void release(GameKey e); public abstract void update(long elapsedTime); public abstract void dispose(); public boolean isUseGLEx() { return _useGLEx; } public void setUseGLEx(boolean u) { this._useGLEx = u; } @Override public void close() { if (usePhysics) { _manager.setStart(false); _manager.setEnableGravity(false); _bodys.clear(); } if (_batch != null) { _batch.close(); _batch = null; } if (indexTile != null) { indexTile.close(); indexTile = null; } if (objects != null) { objects.clear(); objects = null; } if (pendingAdd != null) { pendingAdd.clear(); pendingAdd = null; } if (pendingRemove != null) { pendingRemove.clear(); pendingRemove = null; } updateListener = null; usePhysics = false; _manager = null; _box = null; _fixed = false; tiles.clear(); dispose(); } }