Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing a Circular Timer (AndEngine)

I'm using AndEngine, and within that framework, I'd like to make a circular timer graphic. Specifically, I'd like to display the wait period for reuse of an ability. The idea is to dynamically fill the arc as the timer progresses. Something like this:

Graphics.fillArc()

The java.awt.Graphics object has a fillArc() method that seems perfect for me. In fact, the above graphic was drawn using fillArc(50,5,100,100,75,-40). Great! Now here's the problem:

AndEngine doesn't use Graphics() objects, it uses its own Shape implementation (for OpenGL) and there's no defined "Circle" shape, much less a circle shape with a fillArc() method.

Possible Solutions and Their Respective Problems

Looking around for a solution I ran into "Drawing a circle using Andengine". That Q&A is not of much use to me as the only answer "Indeed, you can't directly draw a circle" offers two alternatives: (1) "Rendering a quad with a circle texture" - this won't work for me as I need to dynamically modify the circle to produce the arcfill; and (2) "Rendering a circle that's actually a circle of connected triangles." Maybe option two would work, but there's no guidance there as to how to do that.

I also ran into "Creating circle in android andengine by box2d?". I suspect someone may be tempted to say, you can simply create a circle like this:

Body circleBody = PhysicsFactory.createCircleBody(pWorld, pSprite, BodyType.StaticBody, FixtureDef);

That really doesn't help me. I'm not looking to create a 2D physics body of a circle. I'm looking to display one.

Finally, I found this discussion, which is promising. In particular, there's a suggestion:

Use Canvas to draw [it] into a Bitmap, and load that Bitmap as a TextureSource.

Sounds reasonable, although I'm still unclear how to do that.


Update: My Cheating "Solution"

Rather than dwell on this, I decided to cheat (for the moment at least). I made a spritesheet that looks like this:

Cheating Timer Image

Rather than actually have the timer display the perfect fillArc(), I just pull the appropriate index of the sprite from the spritesheet based on rounding the proportion done (from 0 to 1) to the appropriate index on the spritesheet. Like this:

public void setTimer(float amount) {
    this.setCurrentTileIndex(Math.round(amount * 20));
}

For my purposes, this actually works just fine--I'm using the timers over about 2 seconds, so you really don't see the lack of detail. But maybe I'll get around to replacing this with the "proper" solution if someone posts it. Also, maybe this spritesheet will be useful for someone doing the same thing. Here's the version using transparency instead of a green background. (So it's white on the white background of stackoverflow, but it's there):

White on White Timer

like image 982
Cameron Fredman Avatar asked Feb 15 '13 21:02

Cameron Fredman


Video Answer


1 Answers

There is a third solution that requires a single texture and a custom object. So it's a trade off between your solutions, where one requires a lot of triangles and the other one a texture memory.

  1. You need only one image, i.e. the full circle in your "cheat sequence" above.
  2. Create a custom object consisting of 8 triangles (one 'fully drawn' triangle will represent 45° each).
  3. The progress determines:
    • How many of the triangles to draw. I.e.:
      • 100% ==> 360° ==> 8 full triangles
      • 50% ==> 180° ==> 4 full triangles
      • 37.5% ==> 135° ==> 3 full triangles
      • 25% ==> 90° ==> 2 full triangles
      • 20% ==> 72° ==> 1 full triangle and one triangle with one vertex moved so that it represents the remaining 27° (== 72° - 45°).

If you ask me this is the coolest solution, since it can be applied to any texture. =)

like image 108
Nicolas Gramlich Avatar answered Oct 25 '22 12:10

Nicolas Gramlich