开发者

How to draw String in real-time game with zero object allocation in Android?

I'm writing real-time game in Android and I'd like to do not allocate any object in main loop. The problem is String value for score.

I have class, that implements CharSequence and uses StringBuilder:

public class MyString implements CharSequence {

    protected String prefix;
    protected StringBuilder stringBuilder;

    public MyString(String prefix) {
        this.prefix = prefix;
        stringBuilder = new Strin开发者_如何学GogBuilder(prefix);
    }

    public void setValue(int value) {
        removeValue();
        stringBuilder.append(value);
    }

    public void setValue(float value) {
        removeValue();
        stringBuilder.append(value);
    }

    private void removeValue() {
        if (prefix == null) {
            stringBuilder.setLength(0);
        } else {
            stringBuilder.setLength(prefix.length());
        }
    }

    @Override
    public char charAt(int index) {
        return stringBuilder.charAt(index);
    }

    @Override
    public int length() {
        return stringBuilder.length();
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return null; // not necessary
    }

}

The usage of this class is:

Paint paint = new Paint();
MyString myString = new MyString("Your score: ");

// Main loop
while(true) {
    myString.setValue(Game.score);
    canvas.drawText(myString, 0, myString.length(), 0, 0, paint);
}

The problem is, that StringBuilder.append(int) creates String object (by String.valueOf(int)) every iteration.

What is your way to solve a problem like this?

My next thought was to convert int and float to array of chars and the setValue() methods would add this array into StringBuilder. The array would be stored in MyString class and it would be created only once and then would be reused. But I can't find way, how to convert float correctly into array of chars. The int is not problem.

Thank you for your help!


Here is some C# code that I wrote for exactly this purpose. It should be pretty simple to convert this to Java. The minDigits parameter causes zero-padding on the left -- You can skip that if you like.

// drawInteger doesn't allocate like string.Format()
int[] digitBuff = new int[10];
string[] digits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

void drawInteger(SpriteFont font, int i, int minDigits, Vector2 pos, Color colour) {
    Debug.Assert(i >= 0 && minDigits > 0 && minDigits <= digitBuff.Length);
    int index = 0;
    while (i > 0 || index < minDigits) {
        digitBuff[index] = i % 10;
        i /= 10;
        ++index;
    }
    while (index > 0) {
        --index;
        string digit = digits[digitBuff[index]];
        sb.DrawString(font, digit, pos, colour);
        pos.X += font.MeasureString(digit).X;
    }
}


You could try a blitting approach: Pre render your "Your Score: " as a drawable. Then make drables for each digit 0-9. In the main loop you can build your score field by drawing the numbers needed to another drawble. I am not sure this will be faster, but you will not need to create any new objects.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜