Wie kann ich einen zirkulären Fortschrittsbalken prozedural rendern?

7

Ich arbeite in Flash AS3, aber Pseudocode oder eine andere Sprache ist in Ordnung.

Wie kann ich einen kreisförmigen Fortschrittsbalken erstellen? Ähnlich wie bei den Schiffsbars in Pax Britanica können Sie sie hier im Screenshot sehen .

Gibt es eine offensichtliche Lösung, die mir hier fehlt, abgesehen davon, dass sie Frame für Frame erstellt werden?

Ich suche das Äquivalent zum Dehnen eines Rechtecks ​​für einen regulären Fortschrittsbalken oder zum Verwenden einer einfachen Maske (falls es eine solche Lösung gibt).

(Außerdem kann ich dies nicht mit einem Kreis oder einem Fortschrittsbalken versehen, da es an Wiederholungen mangelt, wenn jemand dies könnte. Das wäre großartig.)

Adrian Seeley
quelle

Antworten:

19

Zuerst erkläre ich das Prinzip, dann den Zeichnungsteil:

In meinem Beispiel gehe ich davon aus, dass Sie einen Fortschrittswert von 0 bis 100 (%) haben, obwohl alles andere ausreicht.

Auf einer geraden Linie wäre die aktuelle Position des Fortschrittsbalkens einfach dieser Fortschrittswert.

Auf einem Kreis erhalten Sie diese Position mit Trigonometrie. Jeder Punkt auf einem Kreis wird wie folgt angegeben:

point.x = r * cos(angle);
point.y = r * sin(angle); 

Dabei ist r der Radius des Kreises. Wie Sie sehen, ist der Winkel die einzige Variable in diesen Gleichungen. Das bedeutet, dass Sie Ihren Fortschritt irgendwie in den Winkel integrieren müssen.

Die Lösung ist einfach: Ein "Lauf" um den Kreis entspricht 2 * Pi (oder 360 Grad). Sie müssen diesen Abstand in 100 kleinere Teile aufteilen, damit bei einem Fortschrittswert von 100 der Wert innerhalb von cos () und sin () 2 * pi (oder 360 Grad) beträgt.

Sie erreichen dies, indem Sie einfach 2 * pi (oder 360 Grad) durch 100 teilen und mit dem Fortschritt multiplizieren:

float step = 2*pi/100;

point.x = r * cos(progress * step);
point.y = r * sin(progress * step);

Nun zum Zeichnungsteil.

Ich weiß nichts über Actionscript3 (oder Flash), daher kann ich Ihnen die genauen Verfahren nicht mitteilen, aber im Allgemeinen gibt es zwei Möglichkeiten, dies zu tun:

Erstens und (meiner Meinung nach einfacher von beiden): Zeichnen Sie den Teilkreis manuell als einfache Verbindung von farbigen Linien mit einer bestimmten Dicke (wenn Sie keine Textur darauf benötigen und eine einfache Farbe ausreicht), oder zeichnen Sie den Kreis als Verbindung von strukturierten Quads (wenn Sie eine Texturierung benötigen).

Zweitens: Sie zeichnen ein Bild, das Ihren vollständig geladenen Kreis darstellt, und laden es als Textur, legen es auf ein Quad und rendern es. Anschließend zeichnen Sie erneut manuell einen Teilkreis über dieses Quad und rendern nur den Teil des strukturierten Quad, auf dem der Kreis davor gerendert wird. In OpenGL können Sie dies beispielsweise problemlos mit dem Schablonenpuffer tun.

Wenn Sie wissen möchten, wie Sie die verschiedenen Punkte auf Ihrem Kreis berechnen, um daraus die erforderlichen Polygone / Linien zusammenzusetzen, können Sie sich die obigen Gleichungen noch einmal ansehen:

point.x = r * cos(angle);
point.y = r * sin(angle); 

Sie können diese in einer for-Schleife ausführen, die von 0 bis zu Ihrem aktuellen Fortschritt reicht, wenn es sich beispielsweise um einen Kreis handelt, der aus einer Reihe verbundener Punkte besteht (in C ++ - Syntax):

float granularity = 2*PI/required_granularity; //determines how smooth your circle will look
float step = 2*PI/100.0f;

list<Vector2> points; //list of all the calculated points
for(float angle=0; angle < progress*step; angle += granularity)
{
    Vector2 point(radius*cos(angle), radius*sin(angle));
    points.push_back(point); //adds the point to the list
}

Jetzt werden diese Punkte alle auf den Ursprung Ihres Koordinatensystems zentriert, sodass Sie sie an die Position verschieben müssen, an der sich Ihr Kreis befinden soll. Aber ich denke, Sie können das selbst herausfinden: P.

TravisG
quelle
4

Sieht so aus, als wollten Sie einen Bogen zeichnen. Ein Bogen, der dick ist. Ich habe diesen Artikel dafür in AS3 gefunden. Schauen Sie sich die Demo unten an.

MichaelHouse
quelle
1
Dies ist wahrscheinlich die Methode, die ich verwenden werde (nur weil sie AS3-spezifisch ist), aber ich habe die Antwort akzeptiert, die in jeder Sprache funktioniert, um den meisten Menschen bei der Suche zu helfen. Vielen Dank!
Adrian Seeley
1

Ich habe Folgendes nicht ausprobiert, aber es klingt so, als ob es funktionieren sollte.

Sie benötigen zwei Bilder:

  1. Machen Sie in der äußeren HUD-Grafik den Teil, den der Fortschritt anzeigen soll, transparent
  2. Ein einfarbiger Kreis bildet den Radius des Fortschrittsmessers ab. Schneiden Sie dann die untere Hälfte ab und machen Sie diese transparent (es könnte wirklich ein halbes Quadrat sein, da der HUD-Teil den Rest abdeckt).

Im Folgenden wird davon ausgegangen, dass sich Ihre 0% (und 100%) -Marke an der 9-Uhr-Position befindet.


Wenn Ihr Fortschritt 50% oder weniger beträgt:

  • Drehen und zeichnen Sie den Halbkreis so, dass der gewünschte Prozentsatz im oberen Bereich sichtbar ist
  • Führen Sie einen rechteckigen Schnitt des unteren Halbbereichs durch, um den linken Anfang des im unteren Bereich angezeigten Halbkreises zu entfernen
  • Zeichnen Sie die HUD-Grafik der obersten Ebene

Wenn Ihr Fortschritt> 50% ist:

  • Zeichnen Sie den Halbkreis so, dass er die gesamte obere Hälfte ausfüllt (50% -Marke). Sie sollten keine Rotation benötigen
  • Drehen Sie den Halbkreis und zeichnen Sie ihn erneut, um den verbleibenden Prozentsatz wiederzugeben
  • Wenn Sie beispielsweise 60% möchten, zeichnen Sie die erste Kopie, um 50% anzuzeigen, drehen Sie sie und zeichnen Sie die zweite Kopie, um weitere 10% anzuzeigen.
  • Zeichnen Sie die HUD-Grafik der obersten Ebene

Ich bin mir nicht sicher, wie ich das speziell (oder ob es überhaupt möglich ist) in AS3 machen soll. Ich hoffe das macht Sinn (oh, und funktioniert tatsächlich!).

Doug.McFarlane
quelle
0

Eine andere Methode, die ich sah, war die Verwendung von Shadern.

Sie benötigen nur ein Bild, das gesamte HUD-Bild, mit dem Fortschrittsbereich in einer Graustufenverlaufsgrafik. Beginnen Sie an der 0% -Position (z. B. 9 Uhr) mit reinem Weiß und gehen Sie an der 100% -Position allmählich zu Schwarz über.

Sie können kein Grau in Ihrem HUD-Bereich haben, auch kein Weiß oder Schwarz. Wenn Sie diese Farben verwenden müssen, wählen Sie eine andere reine Farbe für Ihre Verlaufsskala (eine Farbe, die nirgendwo anders verwendet wird).

Lassen Sie Ihr Programm dem Shader den Fortschrittswert im Bereich von '0.0' bis '1.0' übergeben (oder welche Skala Ihre Shader-Sprache für die Farbbereiche verwendet). Sie können dem Shader auch eine Fortschrittsbalkenfarbe (und die Farbe "Aus", wenn Sie dies wünschen) übergeben, wenn Sie möchten, dass sich die Farbe dynamisch ändert, z. B. wenn sie leer (oder voll) ist, um den Player zu warnen.

In Ihrem Shader bewerten Sie jedes Quellpixel. Wenn es rein grau ist (jedes R, G, B hat den gleichen Wert), ist dieses Pixel Teil der Fortschrittsanzeige. Wenn es nicht nur die Originalfarbe durchläuft. Wenn es sich um ein Fortschrittsmesspixel handelt, müssen Sie festlegen, ob es die Farbe "Ein" oder die Farbe "Aus" sein soll. Überprüfen Sie einfach die Pixelfarbe (sie ist rein grau, Sie müssen also nur die rote Komponente überprüfen), um festzustellen, ob sie über oder unter dem übergebenen Fortschrittswert liegt. Der Effekt ist, dass jede graue Farbe unterhalb des Fortschrittswerts eingeschaltet und die anderen ausgeschaltet werden.

Doug.McFarlane
quelle
3
OMG, Shader für einen
Kreisabschnitt