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.
精彩评论