The score changes every frame. I like how it works because it's tons
of tiny increments. I actually just did the thing I talked about with
the reusable char[]. The only caveat is that I have to allocate a new
one when the length of the string changes, but that only happens when
the score has changed by a factor of 10 and I don't see scores going
over 6 digits long. I suppose it's possible someone could play the
game forever and score much higher but it's highly unlikely.
This is about as efficient as I will ever care to make such a thing.
If you want to _never_ allocate, you could make a char[][] where the
first dimension is the length of the second dimension arrays. That
would be char[1], char[2], char[3], char[4] and so on. That would
make it so that if your string size were 5 chars, you would say char[]
correctArray = myArrays[5]. I didn't both with that because a few
allocations are ok, just not one every tick of the loop.
This is ugly but if you need something like this, it does work:
I have a class called Util and I put this in it:
private final static int[] intSizeTable = { 9, 99, 999, 9999, 99999,
999999, 9999999, 99999999, 999999999,
Integer.MAX_VALUE };
private final static char[] DigitTens = { '0', '0', '0', '0', '0',
'0', '0', '0', '0', '0', '1', '1', '1', '1',
'1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2',
'2', '2',
'2', '2', '2', '3', '3', '3', '3', '3',
'3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4',
'4', '4',
'4', '4', '5', '5', '5', '5', '5', '5',
'5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6',
'6', '6',
'6', '7', '7', '7', '7', '7', '7', '7',
'7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8',
'8', '8',
'9', '9', '9', '9', '9', '9', '9', '9',
'9', '9', };
private final static char[] DigitOnes = { '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4',
'5', '6',
'7', '8', '9', '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5',
'6', '7',
'8', '9', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6',
'7', '8',
'9', '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', };
private final static char[] digits = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
// Requires positive x
private static int stringSize(int x) {
for (int i = 0;; i++) {
if (x <= intSizeTable[i]) {
return i + 1;
}
}
}
public static void getChars(int i, int index, char[] buf) {
if (i == Integer.MIN_VALUE) {
System.arraycopy("-2147483648".toCharArray(), 0, buf, 0,
buf.length);
}
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf[--charPos] = DigitOnes[r];
buf[--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16 + 3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf[--charPos] = digits[r];
i = q;
if (i == 0)
break;
}
if (sign != 0) {
buf[--charPos] = sign;
}
}
Then in my game code it looks like this (for my FPS counter):
int fps = this.fps;
int fpsStringLength = Util.getSize(fps);
if (fpsChars.length != fpsStringLength) {
// re-allocate
fpsChars = new char[fpsStringLength];
}
char[] fpsChars = this.fpsChars;
//copy the chars into the array
Util.getChars(fps, fpsStringLength, fpsChars);
StringBuffer fpsText = this.fpsText;
fpsText.delete(0, fpsText.length());
fpsText.append(fpsChars).append(FPS_TEXT);
canvas.drawText(fpsText, 0, fpsText.length(),
worldWidth - 60,
worldHeight + INFO_HEADER_HEIGHT - 20,
gameResources.fpsPaint);
That is SO MUCH more code than I ever wanted there but it's
ridiculously more efficient than it was before so I'm going to call it
good and move on.
Thanks for the help everyone!
On May 25, 5:19 pm, Jason Proctor <[email protected]> wrote:
> i'll suggest this again :-)
>
> when the score changes, convert to a string then, save it away, and
> draw that each frame. at least then, you're only doing an allocation
> when it changes.
>
> good enough?
>
>
>
> >My new method doesn't have problems with concatenating but no solution
> >so far has gotten around converting an integer into a String or
> >CharSequence. Any time you put an integer where a String should be,
> >java automatically uses Integer.toString(i) to build a String out of
> >it which allocates a char[] and also makes a new String.
>
> >So, besides ripping out stringSize and getChars from integer and
> >holding my own char[] for the converted int, is there a clean way to
> >handle that without new allocations?
>
> >On May 25, 4:29 pm, Jason Proctor <[email protected]> wrote:
> >> i think Mark is saying that you could redraw the score separately
> >> from the label, potentially saving an implicit new StringBuffer
> >> (stuff).toString () ?
>
> >> if score is a number, then it will need to make a new String anyway.
> >> but you could cache the string of the score until the score changes,
> >> so that drawing the score becomes drawing to strings as opposed to
> >> going through StringBuffer.
>
> >> hth
>
> >> >It's a surface view so the whole scene must be rendered every frame.
> >> >I could put it on the background I suppose but it's simple enough to
> >> >just redraw the text.
>
> >> >On May 25, 4:10 pm, Mark Murphy <[email protected]> wrote:
> >> >> Robert Green wrote:
> >> >> > I said StringBuffer but I meant "Implied" StringBuffer, you know:
>
> >> >> > canvas.drawText(score + POINTS_LABEL, x, y, paint);
>
> >> >> Why redraw POINTS_LABEL every time? Can't you rework your scoreboard
> >> to
> >> >> only draw that once?
>
> >> >> --
> >> >> Mark Murphy (a Commons
> >> >>Guy)http://commonsware.com|http://twitter.com/commonsguy
>
> >> >> Android App Developer Training:http://commonsware.com/training.html
>
> >> --
> >> jason.software.particle
>
> --
> jason.software.particle
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en
-~----------~----~----~----~------~----~------~--~---