Wie kann man einen 3D-Gitter-basierten Sichtlinien-Algorithmus implementieren?

7

Ich erstelle ein Grid-basiertes Tactical RPG-Spiel in XNA.

Das Bild unten erklärt die Idee. Aber wenn Sie schon einmal Dwarf Fortress gespielt haben, versuche ich im Grunde, diese 3D-Sichtlinie zu erstellen, und Sie können meine Erklärung ignorieren.

Hier ist mein Beispiel

(Außerdem ist es mir egal, wie effizient der Algorithmus derzeit ist.)

Derzeit zeichne ich eine Bresenham-Linie zu jedem Quadrat innerhalb eines Radius, und jedes Quadrat, das ich besuche, überprüfe die Richtung, in die ich gehe, wenn ich auf Wände stoße.

Der folgende Code ist meine Überprüfung, ob eine Position sichtbar ist. sx, sy, szist die Änderung im Raster. Zum Beispiel, wenn die Linie nach Nordosten fährt , sx = 1, sy = -1, sz = 0. Wenn ich direkt nach oben gehe, wäre es sx=0, sy = 0, sz = 1;usw.

    private bool IsVisible(APoint Cur, int sx, int sy, int sz)
    {
        bool Visible = true;
        if (ValidCoordinates(Cur))
        {
            int newsx = -1;
            int newsy = -1;
            int newsz = -1;
            switch (sx)
            {
                case -1:
                    newsx = 3; //west
                    break;
                case 0:
                    newsx = -1;
                    break;
                case 1:
                    newsx = 1; //east
                    break;
            }

            switch (sy)
            {
                case -1:
                    newsy = 0;// north
                    break;
                case 0:
                    newsy = -1;
                    break;
                case 1:
                    newsy = 2; //south
                    break;
            }

            switch (sz)
            {
                case -1:
                    newsz = 4; // down
                    break;
                case 0:
                    newsz = -1;
                    break;
                case 1:
                    newsz = 5; // up
                    break;
            }
            if (ValidCoordinates(Cur.X + sx, Cur.Y + sy, Cur.Z + sz))
            {
                if (newsx != -1 && newsy == -1 && newsz == -1) // X only.
                {
                    if (TileArray[Cur.X + sx, Cur.Y + sy, Cur.Z + sz].AllowSight(newsx))
                        Visible = true;
                    else
                        Visible = false;
                }

                if (newsx == -1 && newsy != -1 && newsz == -1) // Y only.
                {
                    if (TileArray[Cur.X + sx, Cur.Y + sy, Cur.Z + sz].AllowSight(newsy))
                        Visible = true;
                    else
                        Visible = false;
                }

                if (newsx != -1 && newsy != -1 && newsz == -1) // X and Y only
                {
                    if (Visible && TileArray[Cur.X + sx, Cur.Y + sy, Cur.Z + sz].AllowSight(newsx))
                        Visible = true;
                    else
                        Visible = false;

                    if (Visible && TileArray[Cur.X + sx, Cur.Y + sy, Cur.Z + sz].AllowSight(newsy))
                        Visible = true;
                    else
                        Visible = false;
                }

            }
            return Visible;
        }
        return false;
    }

Die Funktion Sicht zulassen ist hier:

        public bool AllowSight(int i)
    {
        if (i == -1)
            return true;

        if (i >= 0 && i <= 3)
        {
            if (TileCreateCliff && HDifferenceUp > 0)
            {
                return false;
            }
        }

        if (i == 4)
        {
            if (TileVoid)
                return true;
            else
                return false;
        }
        if (i == 5)
        {
            if (TileVoid)
                return true;
            else
                return false;
        }
        return true;
    }

Dies funktioniert gut, wenn sich mein Charakter auf der Basisebene befindet, aber wenn ich in höhere Lagen oder nach unten schaue, bricht einfach alles zusammen.

Wie soll ich das umsetzen?

Razzek
quelle

Antworten:

6

Dies ist sehr ähnlich zu der Art und Weise, wie Sie in einem Würfel / Voxel-Spiel mit Schatten beleuchten .

Im Wesentlichen gehen Sie rekursiv durch alle Würfel innerhalb der Sichtweite des Charakters. Für jeden Luftwürfel führen Sie einen Strahlentest zwischen der Mitte dieses Würfels und den Augen Ihres Charakters durch. Ich habe auch einen Beitrag darüber geschrieben.

Geben Sie hier die Bildbeschreibung ein

Der Strahlentest kann ein tatsächlicher Strahlentest mit der Geometrie sein (wahrscheinlich schneller, komplexer) oder einfach einen Testpunkt in kleinen Schritten auf das Ziel zubewegen und kontinuierlich prüfen, ob sich Ihr Testpunkt an einer festen Position befindet (langsamer, aber sehr einfach zu erreichen) implementieren).

Selbst mit der einfachen Schrittmethode für einen Strahlentest konnte ich die Beleuchtung sehr schnell durchführen.

MichaelHouse
quelle
Vielen Dank, aber ich bin mir nicht sicher, wie ich diese Methode aus orthografischer Sicht in ein 2D-Spiel implementieren würde.
Razzek
1
Sie sagten, es sei ein 3D-Gitter? Dies verwendet ein 3D-Gitter. Solange Sie eine isSolidAt(x,y,z)Funktion haben, können Sie diese verwenden. Wie Sie die Welt zeichnen, spielt keine Rolle.
MichaelHouse