Andengine is an excellent OpenGL-based game engine on Android. It features that all code is written in Java, and the layers of code are very different. The component granularity is very small, the direct advantage is that it is very easy to use and expand. However, although the android VM is optimized, the performance is also average.
Andengine has built-in support for tmx maps. I tested it with a jpgimage of 1024*1024. It can only reach 45 ~ On My Dell venue ~ The speed of 50 frames per second is even worse on the simulator. This speed is obviously unacceptable in real game development, so I started to improve it.
Because tmx maps provide powerful functions, they can divide almost infinite maps and add layers and objects. Therefore, to use tmx maps, you must tolerate its slowness, my idea is to add a large number of layers and objects to a map without using the tmx map and cut the map by myself.
The principle is very simple, that is, to refer to andengine's cutting of large images and directly add code, it is easy to understand with OpenGL.
Multispritelayer
package com.weedong.background;import javax.microedition.khronos.opengles.GL10;import javax.microedition.khronos.opengles.GL11;import org.anddev.andengine.collision.RectangularShapeCollisionChecker;import org.anddev.andengine.engine.camera.Camera;import org.anddev.andengine.entity.shape.RectangularShape;import org.anddev.andengine.entity.sprite.Sprite;import org.anddev.andengine.opengl.buffer.BufferObjectManager;import org.anddev.andengine.opengl.texture.region.TextureRegion;import org.anddev.andengine.opengl.util.GLHelper;import org.anddev.andengine.opengl.vertex.RectangleVertexBuffer;import org.anddev.andengine.util.MathUtils;import org.anddev.andengine.util.constants.Constants;import android.util.Log;public class MultiSpriteLayer extends RectangularShape {private Sprite[][] arySprite = null;public MultiSpriteLayer(Sprite[][] sprites) {super(0, 0, 0, 0, null);arySprite = sprites;int tiledWidth = (int)arySprite[0][0].getWidth();int tiledHeight = (int)arySprite[0][0].getHeight();this.mSharedVertexBuffer = new RectangleVertexBuffer(GL11.GL_STATIC_DRAW, true);BufferObjectManager.getActiveInstance().loadBufferObject(this.mSharedVertexBuffer);this.mSharedVertexBuffer.update(tiledWidth, tiledHeight);super.mWidth = tiledWidth * arySprite.length;final float width = super.mWidth;super.mBaseWidth = width;super.mHeight = tiledHeight * arySprite[0].length;final float height = super.mHeight;super.mBaseHeight = height;this.mRotationCenterX = width * 0.5f;this.mRotationCenterY = height * 0.5f;this.mScaleCenterX = this.mRotationCenterX;this.mScaleCenterY = this.mRotationCenterY;}private final float[] mCullingVertices = new float[2 * RectangleVertexBuffer.VERTICES_PER_RECTANGLE];private final RectangleVertexBuffer mSharedVertexBuffer;@Overrideprotected void onInitDraw(final GL10 pGL) {super.onInitDraw(pGL);GLHelper.enableTextures(pGL);GLHelper.enableTexCoordArray(pGL);}@Overrideprotected void onApplyVertices(final GL10 pGL) {if(GLHelper.EXTENSIONS_VERTEXBUFFEROBJECTS) {final GL11 gl11 = (GL11)pGL;this.mSharedVertexBuffer.selectOnHardware(gl11);GLHelper.vertexZeroPointer(gl11);} else {GLHelper.vertexPointer(pGL, this.mSharedVertexBuffer.getFloatBuffer());}}@Overrideprotected void drawVertices(GL10 pGL, Camera pCamera) {final float cameraMinX = pCamera.getMinX();final float cameraMinY = pCamera.getMinY();final float cameraWidth = pCamera.getWidth();final float cameraHeight = pCamera.getHeight();final Sprite[][] tmxTiles = arySprite;final int tileColumns = tmxTiles[0].length;final int tileRows = tmxTiles.length;final int tileWidth = (int)tmxTiles[0][0].getWidth();final int tileHeight = (int)tmxTiles[0][0].getHeight();final float scaledTileWidth = tileWidth * this.mScaleX;final float scaledTileHeight = tileHeight * this.mScaleY;final float[] cullingVertices = this.mCullingVertices;RectangularShapeCollisionChecker.fillVertices(this, cullingVertices);final float layerMinX = cullingVertices[Constants.VERTEX_INDEX_X];final float layerMinY = cullingVertices[Constants.VERTEX_INDEX_Y];/* Determine the area that is visible in the camera. */final float firstColumnRaw = (cameraMinX - layerMinX) / scaledTileWidth;final int firstColumn = MathUtils.bringToBounds(0, tileColumns - 1, (int)Math.floor(firstColumnRaw));final int lastColumn = MathUtils.bringToBounds(0, tileColumns - 1, (int)Math.ceil(firstColumnRaw + cameraWidth / scaledTileWidth));final float firstRowRaw = (cameraMinY - layerMinY) / scaledTileHeight;final int firstRow = MathUtils.bringToBounds(0, tileRows - 1, (int)Math.floor(firstRowRaw));final int lastRow = MathUtils.bringToBounds(0, tileRows - 1, (int)Math.floor(firstRowRaw + cameraHeight / scaledTileHeight));final int visibleTilesTotalWidth = (lastColumn - firstColumn + 1) * tileWidth;pGL.glTranslatef(firstColumn * tileWidth, firstRow * tileHeight, 0);for(int row = firstRow; row <= lastRow; row++) {final Sprite[] tmxTileRow = tmxTiles[row];for(int column = firstColumn; column <= lastColumn; column++) {final TextureRegion textureRegion = tmxTileRow[column].getTextureRegion();if(textureRegion != null) {textureRegion.onApply(pGL);pGL.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);}pGL.glTranslatef(tileWidth, 0, 0);}pGL.glTranslatef(-visibleTilesTotalWidth, tileHeight, 0);}pGL.glLoadIdentity();}@Overrideprotected void onUpdateVertexBuffer() {}}
Abstractmultispritebackgroundscene
Package COM. weedong. scene; import Org. anddev. andengine. entity. sprite. sprite; import Org. anddev. andengine. openGL. texture. texture; import Org. anddev. andengine. openGL. texture. textureoptions; import Org. anddev. andengine. openGL. texture. region. textureregion; import Org. anddev. andengine. openGL. texture. region. textureregionfactory; import COM. weedong. activity. baseweedonglayoutgameactivity; import COM. weedong. background. multispritelayer; /*** abstract class <br/> * scene of a background composed of multiple genie <br/> * It features a background image that can support more than 1024*1024 as tmx does, fast <br/> * you can drag the background map, you can refer to the andengine example to override the onscenetouchevent method and use surfacescrolldetector * @ author **/public abstract class extends actgamescene {public parameters (INT nlayercount, baseweedonglayoutgameactivity gameactivity) {super, gameactivity);} public events (INT nlayercount, inclugameactivity, iloadingscene loadingscene) {super (nlayercount, gameactivity, loadingscene);} @ overrideprotected void onloadscene () {super. onloadscene (); initializebackground ();} private void initializebackground () {string [] [] arybackgroundfilepath = getbackgroundfilepath (); sprite [] [] arysprite = new sprite [arybackgroundfilepath. length] [arybackgroundfilepath [0]. length]; for (INT I = 0; I <arysprite. length; I ++) {for (Int J = 0; j <arysprite [0]. length; j ++) {// set textureoptions of all genie to textureoptions. nearest can reach the fastest speed // if it is set to bilinear_premultiplyalpha, a black line texture backgroundtexture = new texture (512,512, textureoptions. nearest); loadtextureandappendtocontainer (backgroundtexture); textureregion backgroundregion = textureregionfactory. createfromasset (backgroundtexture, mgameactivity, arybackgroundfilepath [I] [J], 0, 0); sprite eachsprite = new sprite (0, 0, backgroundregion ); arysprite [I] [J] = eachsprite;} multispritelayer layer = new multispritelayer (arysprite); layer. setcullingenabled (true); this. attachchild (layer); this. mgameactivity. mcamera. setbounds (0, layer. getwidth (), 0, layer. getheight (); this. mgameactivity. mcamera. setboundsenabled (true);}/*** subclass must implement this method, returns the path * @ author * @ return */protected abstract string [] [] getbackgroundfilepath ();}
It is easy to use. inherit abstractmultispritebackgroundscene to implement the getbackgroundfilepath method. To drag the background map, you can refer to the andengine example to override the onscenetouchevent method and use surfacescrolldetector.