2D-Spiel C # Click-to-Move-Beispiele?


7

Derzeit lerne ich, wie man XNA benutzt, indem man ein 2D-Spiel macht. Bisher geht es mir gut, aber ich möchte ein Click-to-Move implementieren, anstatt die Tasten zum Herumlaufen zu verwenden, aber ich habe keine Beispiele gefunden und weiß nicht, wie ich es angehen soll.

Ich weiß, dass XNA gut für Xbox-Steuerelemente und Tastaturen funktioniert, aber ich habe überhaupt nichts im Zusammenhang mit der Mausinteraktion gesehen. Außerdem macht mir Xbox nichts aus, da ich nichts anderes als ein PC-Spiel anstrebe.

Was ich also suche, sind einige Beispiele dafür, wie der Click-to-Move berechnet wird und ob das im Spiel angezeigte Maussymbol auch über das xna-Framework funktioniert oder ob Sie es selbst erstellen müssen, um das zu erstellen Die aktuelle Kachel leuchtet oder zeigt an, dass die Maus vorhanden ist oder ähnliches.


AKTUALISIEREN:

Das Bewegen mit der Maus ist nicht ganz dasselbe, man muss auch Hindernisse berücksichtigen, zumindest in meinem Fall, was ich vorhabe ...

Zum Beispiel möchte ich, dass die Klicks als gerades Gehen betrachtet werden, wodurch der Benutzer gezwungen wird, sich auf der Karte zu navigieren, anstatt den Benutzer per Klick automatisch zu navigieren. Wenn er beispielsweise an einer Wand vorbei klickt, geht er zur Wand und stoppt, anstatt zu finden Der Weg zur anderen Seite, wenn es einen gibt ... ein weiterer Zweifel, der mir bei Verwendung des Zustands von X und Y zum Beispiel in einem Bildlauffenster in den Sinn kommt, erkennt tatsächlich, wo sich die Maus befindet, oder es besteht die Notwendigkeit einer Welt- Bildschirmberechnung, um anzugeben, wo sich Punkt B befindet, auf den der Benutzer geklickt hat?


Vielen Dank für jede Hilfe und Ratschläge ...

PS: Könnte jemand vielleicht das Click-to-Move-Tag oder World-to-Screen hinzufügen?

PPS: Warum kann ich das C # -Tag nicht hinzufügen?


Mit C # und 2D neu markiert, sehen Sie nicht, warum Click-to-Move oder World-to-Screen als Tags erforderlich sind. Nur damit alles fokussiert werden kann, scheint es nicht so, als ob die zweite Frage, die Sie stellen, wirklich mit Ihrer ersten zusammenhängt. Bitte posten Sie das in einer separaten Frage.
Jesse Dorsey

Warum sollten Sie ein Bildlauffenster haben? Normalerweise ist das Fenster nur ein Ansichtsfenster in einen bestimmten Teil Ihrer Welt. Sie könnten definitiv eine lineare Gleichung von Punkt a nach Punkt b erstellen. Dann könnten Sie einige Kurvenfunktionen verwenden, um coole Dinge wie Beschleunigen am Anfang und Verlangsamen am Ende zu tun.
Michael Coleman

Ich habe es als Beispiel erwähnt, ich benutze kein Bildlauffenster. Möglicherweise haben Sie das falsch verstanden, forcing the user to navigate himself on the map instead of auto-navigating the user per clickwas im Grunde genommen der Fall ist, wenn der Benutzer auf eine bestimmte Stelle klickt, das Fenster bewegt, während sich der Spieler bewegt. Wenn der Spieler jedoch versucht, in ein Haus zu klicken, in dem die Tür beispielsweise geschlossen ist, geht es auf das Haus zu Gerade Linie und Halt am ersten Hindernis, was bedeutet, dass der Benutzer keinen automatisch navigierenden Klick hat, um sich zu bewegen, sondern klicken muss, um seinen eigenen Weg zu dem Ort zu finden, an den er gehen möchte.
Prix

Antworten:


6

Bearbeiten: Okay, ich habe gerade aus einem Ihrer Kommentare gelesen, dass Sie keine automatische Navigation wünschen. Betrachten Sie in diesem Fall nur den letzten Abschnitt in diesem Beitrag ("Walking that Path") mit dem einfachen Fall, dass die Liste nur die Stelle speichert, an der Ihre Maus geklickt hat, und sich selbst löscht, wenn ein Hindernis im Weg ist. Mir ist auch gerade aufgefallen, dass Sie Kacheln einmal in der Post erwähnt haben. In diesem Fall ist kein Sichtbarkeitsdiagramm erforderlich. Das Raster selbst kann zum Ausführen von A-Star verwendet werden. Wie auch immer, ich poste dies immer noch als allgemeinere Lösung für das 2D-Point-and-Click-Navigationsproblem.

Was Sie fragen, ist, wie Sie die Pfadfindung in einer 2D-Umgebung durchführen. Ich habe einen Artikel geschrieben, bevor ich eine Technik skizziere, mit der dieses Problem gelöst werden kann. Ich werde zunächst einen Link zum Artikel erstellen und dann eine kurze Erläuterung des Algorithmus hinzufügen.

http://www.david-gouveia.com/pathfinding-on-a-2d-polygonal-map/

Dies ist natürlich nicht der einzige Weg, dies zu lösen. Ich verwende ein Sichtbarkeitsdiagramm. Sie können auch ein Navigationsnetz verwenden. Oder ein Gitter. Das Sichtbarkeitsdiagramm hat den besonderen Vorteil, dass es immer den direktesten Pfad zwischen Punkten zurückgibt, ohne dass eine Pfadkorrektur erforderlich ist. Wenn Sie das Sichtbarkeitsdiagramm über einem Polygon erstellen, können Sie die begehbaren Bereiche genau angeben.

Konzept

Die Hauptidee hier ist, Ihren begehbaren Bereich als Polygon darzustellen und ein Sichtbarkeitsdiagramm unter Verwendung der konkaven Eckpunkte des Polygons zu erstellen. Wenn das Polygon Löcher enthält, verwenden Sie auch deren konvexe Eckpunkte.

Um ein Sichtbarkeitsdiagramm zu erstellen, müssen Sie jeden Knoten (oder in diesem Fall den Scheitelpunkt) des Diagramms mit jedem anderen Scheitelpunkt verbinden, den es "sehen" kann. Dazu benötigen Sie eine Sichtlinienprüfung. Der von mir verwendete basiert auf einem einfachen Liniensegment-Schnittpunkttest mit einigen zusätzlichen Überprüfungen.

Wenn Sie dann den Pfad zwischen zwei Positionen suchen möchten, fügen Sie diese vorübergehend zum Sichtbarkeitsdiagramm hinzu und führen einfach einen klassischen A * -Pfadfindungsalgorithmus darauf aus.

So sieht die gesamte Struktur aus:

Sichtbarkeitsgraph

Wo:

  • Die gelben Linien sind das Polgyon, das angibt, wo Sie gehen können.
  • Die weißen Kreise sind die Polygonscheitelpunkte, aus denen das Sichtbarkeitsdiagramm (Knoten) besteht.
  • Die violetten Linien verbinden Scheitelpunkte, die sich in Sichtweite zueinander befinden (Kanten).
  • Die hellblaue Linie ist ein Beispiel für die Suche nach einem Pfad zwischen zwei Orten (grüner Punkt und roter Punkt).
  • Die hellgrünen Linien sind temporäre Kanten, die dem Diagramm zusammen mit den Start- und Endknoten im Pfad (grüner Punkt und roter Punkt) hinzugefügt werden.

Implementierung

1) Vertretung

Um dies zu implementieren, müssen Sie zunächst eine Möglichkeit haben, ein Polygon für Ihren Boden darzustellen. Die folgende Klasse sollte ausreichen:

public class Polygon
{
    public class SimplePolygon
    {
        List<Vector2> Vertices;
    }

    List<SimplePolygon> Outlines;
    List<SimplePolygon> Holes;
}

2) Knoten auswählen

Dann müssen Sie einen Weg finden, um die Scheitelpunkte des Polygons zu durchlaufen und zu entscheiden, ob sie Knoten im Sichtbarkeitsdiagramm sein sollen. Das Kriterium dafür sind konkave Eckpunkte im Umriss und konvexe Eckpunkte in den Löchern. Ich benutze eine Funktion wie diese:

public static bool IsVertexConcave(IList<Vector2> vertices, int vertex)
{
    Vector2 current = vertices[vertex];
    Vector2 next = vertices[(vertex + 1) % vertices.Count];
    Vector2 previous = vertices[vertex == 0 ? vertices.Count - 1 : vertex - 1];

    Vector2 left = new Vector2(current.X - previous.X, current.Y - previous.Y);
    Vector2 right = new Vector2(next.X - current.X, next.Y - current.Y);

    float cross = (left.X * right.Y) - (left.Y * right.X);

    return cross < 0;
}

3) Kanten auswählen

Jetzt müssen Sie jedes Paar dieser Scheitelpunkte durchgehen und entscheiden, ob sie in Sichtweite sind oder nicht. Ich habe die folgende Methode als Ausgangspunkt für diese Prüfung verwendet:

static bool LineSegmentsCross(Vector2 a, Vector2 b, Vector2 c, Vector2 d)
{
    float denominator = ((b.X - a.X) * (d.Y - c.Y)) - ((b.Y - a.Y) * (d.X - c.X));

    if (denominator == 0)
    {
        return false;
    }

    float numerator1 = ((a.Y - c.Y) * (d.X - c.X)) - ((a.X - c.X) * (d.Y - c.Y));

    float numerator2 = ((a.Y - c.Y) * (b.X - a.X)) - ((a.X - c.X) * (b.Y - a.Y));

    if (numerator1 == 0 || numerator2 == 0)
    {
        return false;
    }

    float r = numerator1 / denominator;
    float s = numerator2 / denominator;

    return (r > 0 && r < 1) && (s > 0 && s < 1);
}

Musste aber auf ein paar andere Hacks zurückgreifen, um die Stabilität von Randfällen zu gewährleisten, so dass das Posten nicht in gutem Zustand ist. Ich versuche immer noch, eine saubere und stabile Lösung für das Problem zu finden.

4) Konstruieren Sie den Graphen und führen Sie einen A-Stern aus

Sie müssen ein Sichtbarkeitsdiagramm mit diesen Scheitelpunkten und Kanten erstellen und A * darauf ausführen. Um zu lernen, wie man ein Diagramm erstellt und A * anwendet, empfehle ich, den folgenden Artikel zu lesen:

http://blogs.msdn.com/b/ericlippert/archive/2007/10/02/path-finding-using-a-in-c-3-0.aspx

Möglicherweise möchten Sie all dies in einer einzigen Klasse zusammenfassen, damit Sie eine einfache Benutzeroberfläche verwenden können, z. B.:

public class Floor
{
    public Floor(Polygon polygon) 
    { 
        _polygon = polygon; 
        BuildGraph();
    }

    public IEnumerable<Vector> GetPath(Vector2 start, Vector2 end)
    {
       // Add start and end as temporary nodes and connect them to the graph
       // Run A* on the graph
       // Remove temporary nodes and edges
    }

    private Polygon _polygon;

    private Graph _graph;
}

Auf diese Weise müssen Sie nur eine Floor-Instanz erstellen und die GetPath-Methode darauf aufrufen, wenn Sie den Pfad zwischen zwei Speicherorten suchen müssen.

5) Diesen Weg gehen

Schließlich müssen Sie Ihren Charakter dazu bringen, den generierten Pfad zu gehen. Dafür braucht er einen internen Speicher, aber es ist nicht allzu schwer, das umzusetzen. Zum Beispiel:

  1. Fügen Sie dem Charakter eine Liste hinzu, um den Pfad zu speichern, dem er gerade folgt.
  2. Nehmen Sie bei jedem Aktualisierungszyklus den ersten Wert aus der Liste und bewegen Sie Ihren Charakter darauf zu.
  3. Wenn er nahe genug am Ziel ist, entfernen Sie das erste Element aus der Liste und wiederholen Sie den Vorgang.
  4. Wenn die Liste leer wird, hat er sein Ziel erreicht.

Tolle Antwort, ich werde mich nicht einmal darum kümmern zu antworten, weil ich denke, Sie haben alles abgedeckt, was ich sagen könnte. +1
Joshua Hedges

3

Nun ... Vergessen Sie beim Lernen nicht, dass Google in diesem Bereich Ihr wahrer Freund ist.

Schritt 1 besteht darin, den Mausspeicherort abzurufen - http://msdn.microsoft.com/en-us/library/bb197572.aspx

Schritt 2 besteht darin, das Sprite an Position A nach Position B zu verschieben, was grundlegende Physik / Bewegung umfasst - http://www.xnadevelopment.com/tutorials/thewizard/theWizard.shtml

Die Idee ist die gleiche, wenn Sie die Maus bewegen, um Ihr Ziel zu erreichen, auf das der Benutzer klickt. Sie fahren immer noch von Punkt A nach Punkt B.

Was Sie beschreiben, ist ein Implementierungsdetail, mit dem Sie bestimmen können, wie Sie damit umgehen möchten. Ich gehe davon aus, dass Sie mit einer Art Raster arbeiten. Die Fliesen auf diesen Gittern haben bestimmte Eigenschaften wie die Begehbarkeit. Versuchen Sie, Ihr Sprite einen Schritt näher in Richtung des Ziels zu bewegen. Wenn eine Kachel nicht begehbar ist, halten Sie an.

Wenn Sie möchten, dass Ihr Sprite tatsächlich zum Ziel gelangt, möchten Sie einen tatsächlichen Pfadfindungsalgorithmus implementieren, der die Lauffähigkeit Ihrer Kacheln analysiert.


Vielen Dank für den ersten Link, der hilft, aber der zweite nicht so sehr. Ich habe meine Frage mit ein paar anderen Punkten aktualisiert, wenn es Ihnen nichts ausmacht, sie zu überprüfen. Danke.
Prix
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.