AndEngine进阶之创建高性能的文本精灵


在游戏开发中,最耗费性能的是显示文本,因为必须临时在内存中将文本生成bitmap,然后将bitmap绑定到OpenGL的纹理并渲染出来,AndEngine的作者估计是深入Java开发中缓存这个概念的重要性的影响,他对文本精灵作了一个精心的规划,分为不可变的文本精灵(Text)和可变的文本精灵(ChangeableText),并将生成文本bitmap并转换到纹理的职责委托给一个叫Font的类,Font类的实现很特别,它将要显示的字符串切分为单个的字符,通过canvas生成bitmap后缓存起来,然后在绑定纹理的时候合并,这样做的好处是当显示重复的字符时性能非常高,缺点是实现复杂导致若缓存池没有此字符时则性能稍低下。在实际使用中,当一个场景里已经存在很多精灵时,Text或ChangeableText的内容经常无法显示或者显示为一片空白区域。

         在IPhone,文本精灵分别是CCLabelTTF和CCLabelAtlas,作用相当于AndEngine的Text和ChangeableText,但实现机制完全不一样,CCLabelTTF是将要显示的字符串先生成一张整体的bitmap然后使用Opengl渲染,而CCLabelAtlas则要求预先传入制作好的文字序列图片以便缓存起来。因此我参考Cocos2d的做法增加了一个Label类,此类结合LoadingScene使用起来还靠谱,缺点是在运行时同时改变两个以上的Label的文字时会有时其中一个Label的文字无法显示。以下是代码:

UltraTextSource:

package com.weedong.opengl;

import org.anddev.andengine.opengl.texture.source.ITextureSource;
import org.anddev.andengine.util.HorizontalAlign;
import org.anddev.andengine.util.MathUtils;
import org.anddev.andengine.util.StringUtils;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Bitmap.Config;
import android.graphics.Paint.FontMetrics;
import android.util.FloatMath;
import android.util.Log;

/**
 * 性能较强的Font TextureSource
 * @author 
 *
 */
public class UltraFontTextureSource implements ITextureSource {
	private int mWidth;
	private int mHeight;
	private Bitmap mBitmap;
	
	public UltraFontTextureSource(String text, Typeface typeface, float fontSize, final int pColor, final boolean pAntiAlias, HorizontalAlign alignment) {
        initialize(text, alignment, fontSize, typeface, pAntiAlias, pColor);
    }

	public UltraFontTextureSource(String text, Typeface typeface, float fontSize, final int pColor, final boolean pAntiAlias) {
		this(text, typeface, fontSize, pColor, pAntiAlias, HorizontalAlign.LEFT);
	}
	
	public UltraFontTextureSource(String text, Typeface typeface, float fontSize, final int pColor) {
		this(text, typeface, fontSize, pColor, true);
	}
	
	private void initialize(String text, HorizontalAlign alignment, float fontSize, Typeface typeface, final boolean pAntiAlias, final int pColor) {
		Paint textPaint = new Paint();
        textPaint.setTypeface(typeface);
        textPaint.setTextSize(fontSize);
        textPaint.setColor(pColor);
        textPaint.setAntiAlias(pAntiAlias);

        FontMetrics fontMetrics = textPaint.getFontMetrics();
		int lineHeight = (int) FloatMath.ceil(Math.abs(fontMetrics.ascent) + Math.abs(fontMetrics.descent));
		int lineGap = (int)(FloatMath.ceil(fontMetrics.leading));
		String[] aryLines = StringUtils.split(text, '\n', null);
		int lineCount = aryLines.length;
		
		int nMaxLineWidth = getMaxLineWidth(textPaint, aryLines);
		int nMaxLineHeight = lineCount * lineHeight + (lineCount - 1) * lineGap;

        int width = MathUtils.nextPowerOfTwo(nMaxLineWidth);
        int height = MathUtils.nextPowerOfTwo(nMaxLineHeight);

        mWidth = width;
        mHeight = height;
        Bitmap.Config config = Bitmap.Config.ARGB_8888;
        Bitmap bitmap = Bitmap.createBitmap(width, height, config);
        Canvas canvas = new Canvas(bitmap);
        bitmap.eraseColor(0);
        Log.i("UltraFont", "font width:" + bitmap.getWidth() + ",height:" + bitmap.getHeight());
        mBitmap = bitmap;

        int centerOffsetHeight = (height - nMaxLineHeight) / 2;
        int centerOffsetWidth = (width - nMaxLineWidth) / 2;

        switch (alignment) {
            case LEFT:
                centerOffsetWidth = 0;
                break;
            case CENTER:
                //centerOffsetWidth = (effectiveTextWidth - textWidth) / 2;
                break;
            case RIGHT:
                centerOffsetWidth = width - nMaxLineWidth;
                break;
        }
        
        float originalY = -fontMetrics.ascent + centerOffsetHeight;
        for(int i = 0; i < aryLines.length; ++i) {
        	canvas.drawText(aryLines[i], centerOffsetWidth, originalY + i * (lineHeight + lineGap), textPaint);
        }
		
	}
	
	private int getMaxLineWidth(Paint paint, String[] aryLines) {
		int maximumLineWidth = 0;
		Rect getStringWidthTemporaryRect = new Rect();
		
		for (int i = aryLines.length - 1; i >= 0; i--) {
			paint.getTextBounds(aryLines[i], 0, aryLines[i].length(), getStringWidthTemporaryRect);
			maximumLineWidth = Math.max(maximumLineWidth, getStringWidthTemporaryRect.width());
		}
		return maximumLineWidth;
	}

	@Override
	public int getHeight() {
		return mHeight;
	}

	@Override
	public int getWidth() {
		return mWidth;
	}

	@Override
	public Bitmap onLoadBitmap(Config pBitmapConfig) {
		return mBitmap;
	}
	
	public ITextureSource clone() {
		return null;
	}
}

Label:

package com.weedong.sprite;

import org.anddev.andengine.entity.Entity;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.region.TextureRegion;

import android.graphics.Typeface;

import com.weedong.opengl.UltraFontTextureSource;
import com.weedong.scene.AbstractBaseScene;
import com.weedong.utils.TextureUtils;

/**
 * 文本精灵
 * @author 
 *
 */
public class Label extends Entity {
	private Sprite mSprite;
	private Typeface mFace;
	private float mFontSize;
	private int mColor;
	private AbstractBaseScene mScene;
	
	public Label(final float pX, final float pY, AbstractBaseScene scene, String text, Typeface face, float fontSize, int color) {
		this.mFace = face;
		this.mFontSize = fontSize;
		this.mColor = color;
		this.mScene = scene;
		TextureRegion region = TextureUtils.createFontTextureRegion(scene, text, face, fontSize, color);
		mSprite = new Sprite(pX, pY, region);
		this.attachChild(mSprite);
	}
	
	public Sprite getSprite() {
		return mSprite;
	}
	
	public float getX() {
		return mSprite.getX();
	}
	
	public float getY() {
		return mSprite.getY();
	}
	
	public float getWidth() {
		return mSprite.getWidth();
	}

	public float getHeight() {
		return mSprite.getHeight();
	}
	
	public void setText(final String text, final Typeface typeface, final float fontSize, final int pColor) {
		UltraFontTextureSource font = new UltraFontTextureSource(text, typeface, fontSize, pColor);
		Texture texture = mSprite.getTextureRegion().getTexture();
		texture.clearTextureSources();
		texture.addTextureSource(font, 0, 0);
	}
	
	public void setText(String text) {
		setText(text, mFace, mFontSize, mColor);
	}
	
	public void setText(String text, int pColor) {
		setText(text, mFace, mFontSize, pColor);
	}
}



你可能感兴趣的:(String,null,iPhone,Class,float,alignment)