Ergebnis 1 bis 12 von 12

Thema: NPC bewegt sich nach XY

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #8
    1. Tja, die "einfache" Methode wäre die, die ~Jack~ schon beschrieben hat. Stumpf abfragen wo das Zielfeld im Vergleich zum zu bewegenden Objekt ist und dieses in die entsprechenden Richtungen bewegen. Bringt nur leider nichts, sobald ein Hindernis in den Weg kommt. Für solche Fälle kann man dann die unschöne Gegenmaßnahme wählen und das Objekt 2 oder 3 mal randomiert bewegen, in der Hoffnung, dass das Hindernis recht klein ist. Sieht aber schlecht aus und funktioniert nur in sehr seltenen Fällen.
      Daher hast du nur 3 Möglichkeiten.
      1. Die Routen-Version wie oben beschrieben. (Schlecht)
      2. Eine Wegpunkt-Version. Dazu platzierst du auf der Map mehrere Wegpunkte in möglichst offenen Bereichen an denen sich dein Objekt entlang hangeln kann. Dazu ermittelst du als erstes den Wegpunkt der dem Objekt am nächsten ist und bewegst es dorthin (um anderen NPCs oder dem Helden auszuweichen ist hier die Zufallsbewegungs-Ausweich-Taktik durchaus angebracht). Hat es diesen erreicht hast du wiederum 2 Möglichkeiten:
        1. Jeder Wegpunkt hat eine Auswahl von festgelegten Routen zu anderen Wegpunkten. Du ermittelst nun also, welcher Wegpunkt dem Zielfeld am nächsten ist und wählst aus den Möglichkeiten des Wegpunktes den richtigen Weg aus (dieser kann auch über andere Wegpunkte führen, welche dann die Bewegung übernehmen). (Sehr umständliche Methode)
        2. Du ermittelst den nächsten Wegpunkt auf dem Weg zum Zielfeld und wendest die selbe Bewegungsabfrage wie oben beschrieben auf diesen Wegpunkt als neues Zielfeld an. Von diesem geht es dann weiter.
          Diese Methode würde so lange weiterlaufen, bis du einen Wegpunkt erreicht hast, dem das Zielfeld näher ist, als ein anderer Wegpunkt.

        Leider ist die Wegpunkt-Variante sehr umständlich und häufig auch unnütz, da man schon eine recht dichte Verteilung braucht um komplizierte Hindernisse vernünftig umgehen zu können. Daher kann ich davon eigentlich nur abraten...
      3. Pathfinding. Dies ist leider sehr kompliziert! Lachsen hat mal den A*-Algorithmus im Maker umgesetzt, der zwar scheinbar (so wie ich gehört habe) noch ein paar Schwächen hat (es kann angeblich zu Abstürzen kommen), bei meinen Test jedoch einwandfrei funktioniert hat. Wenn du Interesse daran hast kannst du entweder die Suchfunktion benutzen oder mir eine PN schreiben, ich glaub das Projekt verstaubt noch irgendwo auf meiner Festplatte...
        Wenn du es selbst umsetzten willst (gehe ich nicht davon aus, da du ja schon nach "einfacheren" Sachen gefragt hast) ist Google ein guter Freund. Da gibt es eine Menge Seiten wo man sich die Funktionsweise des relativ einfachen A*-Algorithmus erklären lassen kann.
    2. Ein "Kegel" macht die Sache natürlich kompliziert. Mal sehen. Als erstes solltest du berechnen, ob der Held vom "Gegner" überhaupt gesehen werden kann. Dies geht über eine einfache Variablenabfrage, in der Kontrolliert wird, ob der Gegner in die richtige Richtung schaut, und ob der Abstand nicht zu groß ist:
      Zitat Zitat
      <>Change Variable "Abstandsrechner X", set[(Hero) X-Coord.]
      <>Change Variable "Abstandsrechner Y", set [(Hero) Y-Coord.]
      <>Change Varibale "Abstandsrechner X" - [(Gegner 1) X-Coord.]
      <>Change Variable "Abstandsrechner Y" - [(Gegner 1) Y-Coord.]
      <>
      <>Fork Variable "Abstandsrechner X" <= 5
      <><>Fork Variable "Abstandsrechner X" >= -5
      <><><>Fork Variable "Abstandsrechner Y" <= 5
      <><><><>Fork Variable "Abstandsrechner Y" >= -5
      <><><><><>!Goto Label 1!
      <><><><>End:
      <><><>End:
      <><>End:
      <>End:
      <>
      <>!Goto Label 99! //Springe zum Ende, wenn in der obigen Fork nicht alle Bedingungen "wahr" wahren
      <>
      <>!Label 1! //Aus der Fork wird zu dieser Position gesprungen
      <>
      <>Fork Event (Gegner 1) - Face Up
      <><>Fork Variable "Abstandsrechner Y" < 0
      <><><>Fork Variable "Abstandsrechner X" >= "Abstandsrechner Y"
      <><><><>Change Variable "Abstandsrechner Y 2" = "Abstandsrechner Y"
      <><><><>Change Variable "Abstandsrechner Y 2" * -1
      <><><><>Fork Variable "Abstandsrechner X" <= "Abstandsrechner Y 2"
      <><><><><>!Goto Label 42! //Gehe zum "Held wurde entdeckt Code"
      <><><><>End:
      <><><>End:
      <><>End:
      <>Else:
      <>Note: -------------------------------------------------
      <>Fork Event (Gegner 1) - Face Down //Änderung zu oben werden markiert
      <><>Fork Variable "Abstandsrechner Y" > 0
      <><><>Fork Variable "Abstandsrechner X" <= "Abstandsrechner Y"
      <><><><>Change Variable "Abstandsrechner Y 2" = "Abstandsrechner Y"
      <><><><>Change Variable "Abstandsrechner Y 2" * -1
      <><><><>Fork Variable "Abstandsrechner X" >= "Abstandsrechner Y 2"
      <><><><><>!Goto Label 42! //Gehe zum "Held wurde entdeckt Code"
      <><><><>End:
      <><><>End:
      <><>End:
      <>Else:
      <>Note: -------------------------------------------------
      <>Fork Event (Gegner 1) - Face Left
      <><>Fork Variable "Abstandsrechner X" < 0
      <><><>Fork Variable "Abstandsrechner Y" >= "Abstandsrechner X"
      <><><><>Change Variable "Abstandsrechner X 2" = "Abstandsrechner X"
      <><><><>Change Variable "Abstandsrechner X 2" * -1
      <><><><>Fork Variable "Abstandsrechner Y" <= "Abstandsrechner X 2"
      <><><><><>!Goto Label 42! //Gehe zum "Held wurde entdeckt Code"
      <><><><>End:
      <><><>End:
      <><>End:
      <>Else:
      <>Note: -------------------------------------------------
      <>Fork Event (Gegner 1) - Face Right
      <><>Fork Variable "Abstandsrechner X" > 0
      <><><>Fork Variable "Abstandsrechner Y" <= "Abstandsrechner X"
      <><><><>Change Variable "Abstandsrechner X 2" = "Abstandsrechner X"
      <><><><>Change Variable "Abstandsrechner X 2" * -1
      <><><><>Fork Variable "Abstandsrechner Y" >= "Abstandsrechner X 2"
      <><><><><>!Goto Label 42! //Gehe zum "Held wurde entdeckt Code"
      <><><><>End:
      <><><>End:
      <><>End:
      <>End:
      <>
      <>!Goto Label 99! //Sollten die Bedingungen von oben nicht "wahr" sein, wird von hier aus zum Ende gesprungen
      <>
      <>!Label 42! //Der "Held wurde entdeckt Code
      <>
      <>Change Switch "Held wurde entdeckt" -> ON
      <>
      <>!Label 99! //Von oben wird hier hin gesprungen
      <>
      <>Wait 0,1 //Oder so was in der Art
      <>
      Öhm, ja... Irgendwie ist das jetzt schon der ganze Code... Er ist nicht getestet, kann also sein das es zu Fehlern kommt ^^°.
      Aber was passiert da jetzt genau?
      Ich werde mal versuchen es am Beispiel "Gegner Face Up" zu erklären, aber als erstes zur Anfangs-Fork:
      Du hast ja angegeben, dass dein "Gegner" nur 5 Felder weit sehen kann. Dazu benutze ich die "Abstandsrechner"-Variablen. In diesen ist der relative Abstand zwischen Held und Objekt gespeichert. Dabei bedeuten die Werte folgendes:
      • "Abstandsrechner X" < 0
        Held links vom Gegner
      • "Abstandsrechner X" > 0
        Held rechts vom Gegner
      • "Abstandsrechner Y" < 0
        Held über dem Gegner
      • "Abstandsrechner Y" > 0
        Held unter dem Gegner

      Diese Werte sind natürlich kombinierbar, d.h. wenn beide Rechner > 0 sind, ist der Held rechts unter dem Gegner.
      Die Zahl die in der Variable gespeichert ist, gibt mir sozusagen die Anzahl Schritte an, die ich in jede Richtung bräuchte, um vom Helden zum Gegner zu kommen.
      Wenn ich jetzt also einen "Rahmen" ziehen will, muss ich lediglich die obigen 4 Bedingungen berücksichtigen:
      • Der Held darf maximal 5 Felder links vom Gegner sein ("Abstandsrechner X" >= -5)
      • Der Held darf maximal 5 Felder rechts vom Gegner sein ("Abstandsrechner X" <= 5)
      • Der Held darf maximal 5 Felder über dem Gegner sein ("Abstandsrechner Y" >= -5)
      • Der Held darf maximal 5 Felder unter dem Gegner sein ("Abstandsrechner Y" <= 5)

      Damit habe ich dann scho nmal eingeschränkt das der Held überhaupt in Sichtweite des Gegner ist. Ich habe also um ihn sozusagen einen "Kasten" erschaffen. Ist der Held innerhalb dieses Kastens, sind die obigen Bedingungen wahr und ich kann weiter abfragen. Sind sie dies nicht, kann ich mir den ganzen Rest sparen.
      Nun aber zum "ganzen Rest".
      Da du ja einen Kegel haben wolltest, konnte ich nicht einfach nur abfragen, ob der Gegner in Richtung des Helden schaut, ich musste diagonale Trennlinien ziehen. Um das besser zu verstehen muss man sich die Funktionsweise der Abstandsrechner-Variablen genauer ansehen:

      Das rote ist der Gegner mit Blickrichtung, türkis ist sein Sichtfeld, das helle Blau ist der Rand des Sichtfeldes. Lila sind zwei mögliche Heldenpositionen. Die hellblauen Striche geben an, wie man sich bewegen müsste um vom Gegner zum Helden zu kommen (daneben steht die Schrittzahl).
      In diesem Bild wird schnell deutlich, dass man sich - um im Sichtfeld zu bleiben - maximal so viele Schritte hoch wie zu den Seiten bewegen darf. Anders ausgedrückt heißt das, dass der Held maximal so viele Schritte neben dem Gegner stehen darf, wie er über ihm steht.
      Und genau das frage ich in den Forks unter "Face Up" ab.
      Ich weiß, dass der Gegner nach oben schaut. Also prüfe ich als erstes, ob der Held über dem Gegner steht (das ist wahr, solange der "Abstandsrechner Y" < 0 ist). Ist dies der Fall, muss ich nur noch prüfen, ob der Held nicht zu weit rechts oder links steht, um nicht mehr im Sichtfeld zu sein. Da ich nicht weiß auf welcher Seite vom Gegner er steht, prüfe ich genau wie beim Abstecken des Rahmens zuvor einfach alle Möglichkeiten. D.h. er darf maximal "Abstand von Gegner zu Held in Y-Richtung" Felder links vom Gegner sein und maximal "Abstand von Gegner zu Held in Y-Richtung" Felder rechts vom Gegner sein. Guck dir die Forks und die Umrechnung mit "* -1" noch mal genauer an, dann wirst du verstehen wie das funktioniert.

      Damit sollte eigentlich alles geklärt sein ^^°
    3. Tja, dazu gibt es auch wieder eine Menge Möglichkeiten...
      Ich denke mal, dein größtes Problem ist dabei die Sache mit dem zwischenschiebbaren Objekt. Da frage ich mich allerdings wie du das in deinem Spiel verdeutlichen willst. Ich meine, nehmen wir an das ist eine Laserschranke die dem Helden schadet. Wenn man ein Objekt dazwischenschiebt hilft das dem Helden ja kein Stück weiter, außer er klettert über das Objekt. Davon gehe ich aber mal nicht aus.
      Um dieses Problem zu umgehen dürfte eine solche "Schranke" nur von einer Seite ausgestrahlt werden und davon gehe ich hier auch aus.
      Um ein solches System umzusetzen brauchst du an sich nur 1 Event, das sich komplett selbst steuert und den Ausgangspunkt der Schranke (sowie dessen Blickrichtung). Ich sage einfach mal, das das in diesem Fall ein NPC mit Laseraugen ist (). Dieser soll frei bewegbar sein. Den grafischen Aspekt berücksichtige ich jedoch nicht. Damit musst du selbst fertig werden .
      Also zum Code. Damit die Sache funktioniert würde ich erstmal eine Abfrage per Koordinaten vorschlagen. Danach kommt dann noch ein Hilfsobjekt zum Einsatz, welches kontrolliert, ob ein Gegenstand zwischen Aussender und Held steht. Aber erst mal zur Variablenabfrage:
      Zitat Zitat
      <>Change Variable "Held X", set [(Hero) X-Coord.]
      <>Change Variable "Held Y", set [(Hero) Y-Coord.]
      <>Change Variable "Gegner X", set [(Aussender 1) X-Coord.]
      <>Change Variable "Gegner Y", set [(Aussender 1) Y-Coord.]
      <>
      <>Fork Event (Aussender 1) - Face Up
      <><>Fork Variable "Held X" = "Gegner X"
      <><><>Fork Variable "Held Y" < "Gegner Y"
      <><><><>Move Event (This Event): 'Face Up'
      <><><><>!Goto Label 1! //Springe zum Kontroll-Code
      <><><>End:
      <><>End:
      <>Else:
      <>Fork Event (Aussender 1) - Face Down
      <><>Fork Variable "Held X" = "Gegner X"
      <><><>Fork Variable "Held Y" > "Gegner Y"
      <><><><>Move Event (This Event): 'Face Down'
      <><><><>!Goto Label 1! //Springe zum Kontroll-Code
      <><><>End:
      <><>End:
      <>Else:
      <>Fork Event (Aussender 1) - Face Left
      <><>Fork Variable "Held Y" = "Gegner Y"
      <><><>Fork Variable "Held X" < "Gegner X"
      <><><><>Move Event (This Event): 'Face Left'
      <><><><>!Goto Label 1! //Springe zum Kontroll-Code
      <><><>End:
      <><>End:
      <>Else:
      <>Fork Event (Aussender 1) - Face Right
      <><>Fork Variable "Held Y" = "Gegner Y"
      <><><>Fork Variable "Held X" > "Gegner X"
      <><><><>Move Event (This Event): 'Face Right'
      <><><><>!Goto Label 1! //Springe zum Kontroll-Code
      <><><>End:
      <><>End:
      <>End:
      <>
      <>!Goto Label 99! //Sollten die obigen Bedingungen nicht wahr sein, springe direkt zum Ende des Codes
      <>
      <>!Label 1!
      <>
      <>Set Event Place (This Event) [Gegner X | Gegner Y]
      <>
      <>Change Variable "Zähler Variable", set 0
      <>!Label 2!
      <>
      <>Move Event (This Event): 'Move Speed Up; Move Speed Up; Move Speed Up; Forward' (Ignore if can't be moved)
      <>Wait 0,0
      <>Change Variable "Kontrolle X", set [(This Event) X-Coord.]
      <>Change Variable "Kontrolle Y", set [(This Event) Y-Coord.]
      <>Fork Event (This Event) - Face Up //Da das Event den Helden nicht erreichen kann, wird so getan als wäre es schone in Feld weiter
      <><>Change Variable "Kontrolle Y" - 1
      <>Else:
      <>Fork Event (This Event) - Face Down
      <><>Change Variable "Kontrolle Y" + 1
      <>Else:
      <>Fork Event (This Event) - Face Left
      <><>Change Variable "Kontrolle X" - 1
      <>Else:
      <>Fork Event (This Event) - Face Right
      <><>Change Variable "Kontrolle X" + 1
      <>End:
      <>Fork Variable "Kontroll X" = "Held X"
      <><>Fork Variable "Kontroll Y" = "Held Y"
      <><><>!Goto Label 42! //Zum "Held wurde getroffen" Code
      <><>End:
      <>End:
      <>Change Variable "Zähler Variable" + 1
      <>Fork Variable "Zähler Variable" < 10 //"Sichtweite" der Schranke
      <><>!Goto Label 2! //Zum Anfang der "Label-Schleife"
      <>End:
      <>
      <>!Goto Label 99! //Held wurde nicht erreicht, also zum Ende springen
      <>
      <>!Label 42! //"Held wurde getroffen" Code
      <>
      <>Change HP: (Full Party) dec. 10
      <>Flash Screen (255,0,0 | 0.1 secs)
      <>
      <>!Label 99!
      <>
      Hoffe das es einigermaßen verständlich ist... Erst fragt man die Richtung in der die Schranke schaut ab und prüft ob der Held überhaupt auf der Linie steht. Danach setzt man das Event selbst (muss auf "Same Level As Hero" stehen) auf die Position der Schranke und versucht den Helden zu erreichen. Gelingt dies, ist kein Hindernis im Weg, dementsprechend wird der Held getroffen. Dabei muss man jedoch beachten, dass das Event automatisch ein Feld vorm Helden stehen bleibt, da der Held ja selbst auch ein "Hindernis" ist, den es nicht passieren kann.


    Ich hoffe mal, dass du damit etwas anfangen kannst... (>6 Seiten in Word xD)

    mfg
    Phönix Tear

    Geändert von Phönix Tear (29.08.2007 um 18:23 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •