AndEngineのカスタムドラッグ可能なバックグラウンド


AndEngineはAndroidの優れたOpenGLベースのゲームエンジンで、すべてのコードがJavaで記述されているのが特徴で、コード間の階層が非常に異なり、コンポーネントの粒度が非常に小さく、直接もたらす利点は非常に使いやすく、拡張も非常に楽であるが、AndroidのVMは最適化されているが、性能も一般的である.
AndEngineにはTMXマップのサポートが内蔵されており、1024*1024のjpg画像でテストしたことがあります.私のDell Venueでは45~50フレーム/秒の速度しか達成できませんが、シミュレータではさらに惨めです.この速度は明らかに本当のゲーム開発では受け入れられないので、改善に着手しました.
TMX地図は強力な機能を提供することができるため、まずそれはほとんど無限大の地図を分割することができて、その上層とオブジェクトを追加することができて、そのためそれを使うにはその遅さを我慢しなければならなくて、私の構想はいくつかの大きい地図を必要として、しかし地図の中で大量の層とオブジェクトを追加する場所をあまり必要としなくて、TMX地図を使うことを捨てて、自分で地図を切る.
原理は簡単で、AndEngineの大きな画像の切断を参考にして、直接コードをつけて、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;
	
	@Override
	protected void onInitDraw(final GL10 pGL) {
		super.onInitDraw(pGL);
		GLHelper.enableTextures(pGL);
		GLHelper.enableTexCoordArray(pGL);
	}
	
	@Override
	protected 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());
		}
	}
	
	@Override
	protected 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();
	}

	@Override
	protected 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;

/**
 *    <br/>
 *            Scene<br/>
 *         TMX      1024*1024    ,      <br/>
 *            ,    AndEngine     onSceneTouchEvent     SurfaceScrollDetector
 * @author 
 *
 */
public abstract class AbstractMultiSpriteBackgroundScene extends AbstractGameScene {

	public AbstractMultiSpriteBackgroundScene(int nLayerCount, BaseWeedongLayoutGameActivity gameActivity) {
		super(nLayerCount, gameActivity);
	}
	
	public AbstractMultiSpriteBackgroundScene(int nLayerCount, BaseWeedongLayoutGameActivity gameActivity, ILoadingScene loadingScene) {
		super(nLayerCount, gameActivity, loadingScene);
	}

	@Override
	protected 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++) {
				//      TextureOptions  TextureOptions.NEAREST        
				//    BILINEAR_PREMULTIPLYALPHA              
				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);
	}
	
	/**
	 *          ,                    
	 * @author 
	 * @return
	 */
	protected abstract String[][] getBackgroundFilePath();
}

AbstractMultiSpriteBackgroundScene実装のgetBackgroundFilePathメソッドを継承するのは簡単です.バックグラウンドマップをドラッグできるようにするには、AndEngineの例を参照してonSceneTouchEventメソッドを書き換え、SurfaceScrollDetectorを使用します.