Verbesserte Leistung der Klickerkennung in einem isometrischen Raster mit gestaffelten Spalten

9

Ich arbeite an einer isometrischen Spielengine und habe bereits einen Algorithmus zur Pixel-perfekten Klickerkennung entwickelt. Besuchen Sie das Projekt und beachten Sie, dass die Klickerkennung erkennen kann, auf welche Kante der Kachel geklickt wurde. Es prüft auch den Y-Index, um auf die am weitesten vorn liegende Kachel zu klicken.

Eine Erläuterung meines aktuellen Algorithmus:

Das isometrische Gitter besteht aus Fliesenbildern, die 100 * 65px groß sind. TileW=100, TileL=50, tileH=15

Die Karte wird durch ein dreidimensionales Array map[z][y][x] dargestellt.

Tile-Mittelpunkte (x,y) werden wie folgt berechnet:

%Vor%

Prototypfunktionen, die bestimmen, ob sich die Maus innerhalb eines bestimmten Bereichs auf der Kachel befindet:

%Vor%

Tile.prototype.allContainsMouse() gibt wahr zurück, wenn die Maus innerhalb von grün ist. Der rote Bereich wird abgeschnitten, indem geprüft wird, ob dx & gt; die Hälfte der Fliesenbreite

%Vor%

%Vor%

(Wenn die Maus links vom Mittelpunkt steht)

%Vor%

(Wenn sich die Maus rechts vom Mittelpunkt befindet)

Alle Methoden zusammenbringen, um als eine Einheit zu arbeiten:

  • Schleife durch die gesamte 3D-Karte [z] [y] [x] Array
  • Wenn allContainsMouse() wahr zurückgibt, ist map [z] [y] [x] die Kachel, auf der sich unsere Maus befindet.
  • Fügen Sie diese Kachel dem Array tilesUnderneathMouse array hinzu.
  • Gehe durch tilesUnderneathMouse array und wähle die Kachel mit der höchsten y . Es ist die am weitesten vorne liegende Kachel.

    %Vor%

  • //x, y, z are the position of the tile
    
    if(y%2===0) { x-=-0.5; }    //To accommodate the offset found in even rows
    this.centerX = (x*tileW) + (tileW/2);
    this.centerY = (y*tileL) - y*((tileL)/2) + ((tileL)/2) + (tileH/2) - (z*tileH);
    

(Ähnliches gilt für das Recht)

Endlich, meine Fragen:

# 1 Wie würden Sie dies erreichen, so dass es effizienter ist (nicht alle Kacheln durchlaufen) (pesudo code accepted)

# 2 Wenn Sie # 1 nicht beantworten können, welche Vorschläge haben Sie, um die Effizienz meiner Klickerkennung zu verbessern (Chunk Loading wurde bereits berücksichtigt)

Was ich mir gedacht habe:

Ich habe ursprünglich versucht, dieses Problem zu lösen, indem ich keine Kachel-Mittelpunkte verwendete, sondern die Mausposition (x, y) direkt in die Kachel x, y umwandelte. Meiner Meinung nach ist dies die am schwersten zu codierende, aber effizienteste Lösung. Auf einem quadratischen Gitter ist es sehr einfach, eine (x, y) Position in ein Quadrat auf dem Gitter zu konvertieren. In einem gestaffelten Spaltenraster behandeln Sie jedoch Offsets. Ich habe versucht, Offsets mit der a-Funktion zu berechnen, die einen x- oder y-Wert annimmt, und gebe den resultierenden Offset y oder x zurück. Der Zick-Zack-Graph von

Max Mastalerz 09.03.2016, 07:01
quelle

1 Antwort

4

Diese Antwort basiert auf:

Also hier geht es:

  1. Konvertierung zwischen Raster und Bildschirm

    Wie ich im Kommentar erwähnt habe, sollten Sie Funktionen erstellen, die zwischen Bildschirm- und Zellengitterpositionen konvertieren. etwas wie (in C ++ ):

    %Vor%

    Ich habe dein Layout benutzt (habe mi genommen, um meinen zu konvertieren, hoffentlich mache ich keinen dummen Fehler irgendwo):

    • rotes Kreuz repräsentiert Koordinaten, die von cell2scr(x,y,0,0,0) zurückgegeben werden
    • grünes Kreuz steht für Mauskoordinaten
    • aqua highlight repräsentiert die zurückgegebene Zellenposition

    Vorsicht, wenn Sie Integer-Arithmetik verwenden, müssen Sie daran denken, dass Sie die Präzision verlieren können, wenn Sie die Hälfte teilen oder multiplizieren. Verwenden Sie die volle Größe und teilen Sie das Ergebnis für solche Fälle durch 2 (verbringen Sie viel Zeit damit, das in der Vergangenheit herauszufinden).

    Die cell2scr ist ziemlich einfach. Die Bildschirmposition ist Pan-Offset + Zellenposition multipliziert mit ihrer Größe (Schritt). Die x -Achse benötigt eine Korrektur für gerade / ungerade Zeilen (das ist, wofür ((cy&1)*cxs2) ist) und y Achse wird um die z Achse ( ((cy&1)*cxs2) ) verschoben. Mein Bildschirm hat den Punkt (0,0) in der oberen linken Ecke, +x axis zeigt nach rechts und +y zeigt nach unten.

    Die scr2cell wird durch die algebraisch gelöste Bildschirmposition aus den Gleichungen von cell2scr gemacht, während z=0 angenommen wird, so dass nur der Gitterboden ausgewählt wird. Darüber hinaus wird nur die gerade / ungerade Korrektur hinzugefügt, wenn sich die Mausposition außerhalb des gefundenen Zellenbereichs befindet.

  2. Nachbarn scannen

    Das scr2cell(x,y,z,mouse_x,mouse_y) gibt nur die Zelle zurück, in der sich die Maus auf dem Boden befindet. Wenn Sie also Ihre aktuelle Auswahlfunktionalität hinzufügen möchten, müssen Sie die oberste Zelle an dieser Position und einige benachbarte Zellen scannen und die mit der geringsten Entfernung auswählen.

    Sie müssen nicht das gesamte Raster scannen / nur wenige Zellen um die zurückgegebene Position herum abbilden. Das sollte die Sache erheblich beschleunigen.

    Ich mache es so:

    Die Anzahl der Zeilen hängt von der Zellen z Achsengröße ( czs ), der maximalen Anzahl von z Schichten ( gzs ) und der Zellengröße ( cys ) ab. Der C ++ Code von mir mit Scan sieht so aus:

    %Vor%

    Dies wählt immer die oberste Zelle aus (am höchsten von allen möglichen), wenn es mit der Maus gespielt wird, fühlt es sich richtig an (zumindest für mich):

Hier ist die VCL / C ++ Quelle für meine isometrische Engine, die ich heute dafür kaputt gemacht habe:

%Vor%

Das Layout definiert nur die Achsenrichtungen des Koordinatensystems (für Ihre Verwendung #define isometric_layout_2 ). Dies verwendet Borlands VCL Graphics::TBitmap . Wenn Sie also nicht Borland verwenden, ändern Sie es in eine GDI Bitmap oder überschreiben Sie den gfx Teil in Ihre gfx < strong> API (relevant nur für draw() und resize() ). Auch TShiftState ist Teil von VCL es ist nur der Status von Maustasten und Sondertasten wie shift,alt,ctrl , also kannst du stattdessen bool oder sonst etwas verwenden (wird momentan nicht verwendet, da ich keine habe) klicke noch auf Funktionalität).

Hier mein Borland Fenstercode (Single-Form-App mit einem Timer), damit Sie sehen, wie Sie das verwenden:

%Vor%

[Edit1] Grafikansatz

Sehen Sie sich die einfache OpenGL GUI Framework-Benutzerinteraktionsempfehlung an? .

Die Hauptidee besteht darin, einen Schattenpuffer zu erstellen, in dem die ID der gerenderten Zelle gespeichert wird. Dies bietet eine pixelperfekte Sprite- / Zellenauswahl in O(1) nur mit wenigen Zeilen Code.

  1. Erstellen Sie einen Schattenbildschirmpuffer idx[ys][xs]

    Es sollte die gleiche Auflösung haben wie Ihre Kartenansicht und sollte in der Lage sein, den Wert (x,y,z) der Renderzelle innerhalb eines einzelnen Pixels (in Kartengitterzelleneinheiten) zu speichern. Ich benutze 32-Bit-Pixelformat, also wähle ich 12 Bits für x,y und 8 Bits für z

    %Vor%
  2. Löschen Sie vor dem Rendern der Karte diesen Puffer

    Ich verwende 0xFFFFFFFF als leere Farbe, damit es nicht mit der Zelle (0,0,0) kollidiert.

  3. beim Rendern von Kartenzellen-Sprites

    Immer wenn Pixel auf Bildschirmpuffer pyx[y][x]=color gerendert werden, rendern Sie auch Pixel in den Schattenbildschirmpuffer idx[y][x]=c Dabei ist c die codierte Zellenposition in Kartenrastereinheiten (siehe # 1 ).

  4. Beim Mausklick (oder was auch immer)

    Sie haben die Bildschirmposition der Maus mx,my . Wenn sie sich in Reichweite befindet, lesen Sie einfach den Schattenpuffer und erhalten Sie die ausgewählte Zellenposition.

    %Vor%

    Mit oben Codierung dieser Karte (Bildschirm):

    wird auch so gerendert, dass der Bildschirm wie folgt aussieht:

    Die Auswahl ist pixelgenau, egal ob Sie oben, seitlich klicken ...

    Die verwendeten Kacheln sind:

    %Vor%

    Und hier Win32 Demo:

Spektre 10.03.2016 13:32
quelle