Jump to content
Unity Insider Forum

Nav Mesh Agent


Deadfish

Recommended Posts

Guten tag,

habe mal eine Frage zum Nav Mesh Agent,
baue grade an meinen Ai Script folgendes geht schon.
Sichtfeld Radius des Sichtfeldes Zufällige Bewegungen, erkennen des Gegner durch Raycast im Sichtfeld.

Jetzt möchte ich aber gerne das er vom "playerTarget" bei bestimmten Situationen weg rennt.

Agent.SetDestination (playerTarget.position); ist ja zum Spieler aber gibt es noch die Möglichkeit vom Spieler weg gezielt vom Spieler weg?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Nicht getesteter Code, es wird ein zufälliges Target 100 Meter von Spieler entfernt gewählt (auf Höhe des Spielers):
 

  // playerTarget ist das Transform des Spielers
  Vector2 newRandomPosition = Random.insideUnitCircle * 100 + new Vector2(playerTarget.position.x, playerTarget.position.z);
  Vector3 newAgentPosition = new Vector3(newRandomPosition.x, playerTarget.position.y, newRandomPosition.y);
  Agent.SetDestination(newAgentPosition);

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke erstmal ein bisschen habe ich verändert:

Vector3 newRandomPosition = Random.insideUnitSphere * wert + new Vector3(playerTarget.position.x, playerTarget.position.z);
Vector3 newAgentPosition = new Vector3(newRandomPosition.x, playerTarget.position.y, newRandomPosition.y);


die variable Wert float = 10 bei 100 hat er sich so gut wie nicht bewegt:

aber jetzt sieht zwar auch gut aus, aber er kommt direkt zu mir und geht nicht von mir weg :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

Sollte eigentlich gehen, 100 Meter war tatsächlich etwas zu weit ... der Code funktioniert allerdings nur zu 100% sicher, wenn Spieler und Gegner auf ebener Fläche stehen, ansonsten kann es sein, das der Agent unter den Navmesh oder in die Luft geschickt wird. Mit dem Debug.DrawLine kannst du nun auch die Position sehen, wo der Agent hinlaufen sollt, wenn er das nicht tut, liegt das Problem woanders (Einstellungen im Navmesh / Hinderniss etc).
 

        Transform playerTarget = transform;
        float wert = 10f;
        Vector3 newRandomPosition = Random.insideUnitSphere * wert + new Vector3(playerTarget.position.x, playerTarget.position.z);
        Vector3 newAgentPosition = new Vector3(newRandomPosition.x, playerTarget.position.y, newRandomPosition.y);
        Debug.DrawLine(transform.position, newAgentPosition);
        Agent.SetDestination(newAgentPosition);

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Durch den Draw konnte ich mir mal anschauen was ich Falsch mache, der hat immer Pausenlos eine neue Route berechnet habe den jetzt in eine Void gemacht und mit
    InvokeRepeating("PlayerdontTarget", 1.0f,2f);
gesagt er soll alle 2 Sekunden einen anderen Weg berechnen.

Danke es geht aber er geht bei ca 3 von 10 Ergebnissen immer noch in Richtung Spieler.

[Danke nochmal das er ein paar mal auf mich zu rennt ist glaub ich nicht zu Ändern aber sonst funktioniert es Top :D ]

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, der Code oben war in Endeffekt nur dafür gedacht, wenn der Gegner bereits direkt am Spieler steht.
So, dann hier aber mal die ultimative "Flieh"-Methode, dafür komm ich dann aber in die Credits ;)

Du kannst nun bestimmen, ob der Gegner auf direktestem Wege vom Gegner weglaufen soll (randomPath = false), oder ob er eine zufällige Richtung abgewand vom Spieler einschlagen soll. Ebenfalls kannst du nun eine minimale und eine maximale Wegstrecke einstellen, die er sich Wegbewegen soll.
Die Transforms für den Spieler und den Gegner sind hier noch als Public Variablen der Klasse geführt zum besseren Testen, aber du solltest sie noch als Parameter in die "Flee"-Methode legen.
Wenn er einen Zufallspfad bestimmen muss, dann testet er einige Zufallsrichtungen durch, bis die Richtung stimmt, könnte man ggf. noch etwas performanter machen. Nach meinen Messungen ruft er bei einer Zufallspfadberechnung die "Random.insideUnitCircle" im Durchschnitt 2x Mal auf, also das sollte zu verkraften sein (ich hatte mal 10000x Durchläufe gemacht).

Du könnest die Methode noch verbessern, indem du nun noch "NavMesh.SamplePosition" einbaust. Diese Methode gibt dir einen gültigen (erreichbaren) Pfad im Navmesh zurück, wenn du ihr die Position von der "Flee"-Methode übergibst.
 

        bool foundAgentPosition = false;
        Vector3 newAgentPosition;
        NavMeshHit hit;
        Vector3 randomPoint = Flee(25f, 50f, true);
        if (NavMesh.SamplePosition(randomPoint, out hit, 5.0f, NavMesh.AllAreas))
        {
            newAgentPosition = hit.position;
            foundAgentPosition = true;
        }

        if (foundAgentPosition)
        {
            agent.SetDestination(newAgentPosition);
        }
        else
        {
            // Wenn er hier reinläuft wurde kein Pfad im Navmesh gefunden in einem Bereich 
            // 5 Meter um die berechnete Position der Flee-Methode
            // In diesem Fall z.b. die Flee-Methode nochmals aufrufen ...
        }


 

using UnityEngine;
using System.Collections;

public class SimpleAI : MonoBehaviour
{

    public Transform player;
    public Transform enemy;

    void Start()
    {
        Vector3 newAgentPosition = Flee(25f,50f, true);
        Debug.DrawLine(enemy.position, newAgentPosition);
        Debug.Log(enemy.position + " --- " + newAgentPosition);
        Debug.Log((enemy.position - newAgentPosition).magnitude);
        Debug.Break();
    }

    Vector3 Flee(float minfleeDistance, float maxfleeDistance, bool randomPath)
    {
        Vector2 randomDirection;
        Vector2 fleeDirection;
        float direction;

        Vector2 directionFromPlayer = new Vector2(enemy.position.x, enemy.position.z) - new Vector2(player.position.x, player.position.z);
        directionFromPlayer.Normalize();

        if (randomPath)
        {
            // Determine a direction that is pointing away from the player
            do
            {
                randomDirection = Random.insideUnitCircle;
                direction = Vector2.Dot(directionFromPlayer, randomDirection);
            } while (direction < 0);
            randomDirection = randomDirection * maxfleeDistance;

            // Add the minfleeDistance
            float currentDistance = randomDirection.magnitude;
            if (currentDistance < minfleeDistance)
            {
                float minFleeFactor = minfleeDistance / currentDistance;
                randomDirection = randomDirection * minFleeFactor;
            }

            fleeDirection = randomDirection;
        }
        else
        {
            fleeDirection = directionFromPlayer * Random.Range(minfleeDistance, maxfleeDistance);
        }
        return (new Vector3(enemy.position.x + fleeDirection.x, enemy.position.y, enemy.position.z + fleeDirection.y));
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Vielleicht nochmal ein kleiner Nachtrag, für alle die sowas nutzen:

Vielleicht die Logik so ausrichten, das der Path mit Abhängigkeit nach anderen Größen berechnet wird (z.B Aktuelle Distanz usw.)

Z.B. kann man wunderbar Die "Distance-Check" und den "Path-Check" zusammen kombinieren. Allerdings funktioniert das nur z.B. mit Spieltypen wo die Player sich nicht soo schnell bewegen.

if(NextUpdate>0)
			NextUpdate-=Time.deltaTime;
		else
			UpdateAgent();


		void UpdateAgent()
		{

			Distance = Vector3.Distance (transform.position, Target.position);	

			agent.SetDestination (Target.position);

			if (Distance < 10)
			{
				NextUpdate = 0.5f;
			}
			if (Distance > 10)
			{
				NextUpdate = 1.0f;
			}
			if (Distance > 30)
			{
				NextUpdate = 3.0f;
			}
			if (Distance > 50)
			{
				NextUpdate = 6.0f;
			}

	
		}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 18 Stunden schrieb Sascha:

Aaaaah!!1eins

Wenn Distance == 10 ist, kommt man in einen Zustand, aus dem man nicht mehr raus kommt :P

Außerdem: Warum nicht einfach


nextUpdate = distance * 0.1f;

 

Ja :D

Haha manchmal macht man sich die Welt unnötig schwer...

Nur verstehe nicht warum man dann aus diesem Zustand nicht rauskommt :o

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Lonely World:

Nur verstehe nicht warum man dann aus diesem Zustand nicht rauskommt :o

Hmm... du hast Recht, das stimmt gar nicht. Ich meinte, dass NextUpdate <= 0 bleibt und im nächsten Frame direkt nochmal die Funktion ausgelöst wird. Ich hatte da so eine Fallgrube reininterpretiert, bei der NextUpdate dann immer <= 0 bleibt und alles für die Katz wäre. Allerdings wird Distance ja mit sehr hoher Wahrscheinlichkeit nicht noch einmal genau 10 sein, sodass dann wieder alles in Ordnung ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Sascha:

Hmm... du hast Recht, das stimmt gar nicht. Ich meinte, dass NextUpdate <= 0 bleibt und im nächsten Frame direkt nochmal die Funktion ausgelöst wird. Ich hatte da so eine Fallgrube reininterpretiert, bei der NextUpdate dann immer <= 0 bleibt und alles für die Katz wäre. Allerdings wird Distance ja mit sehr hoher Wahrscheinlichkeit nicht noch einmal genau 10 sein, sodass dann wieder alles in Ordnung ist.

 

Ja das ist mir dann auch bewusst geworden :rolleyes:

Mir ging es auch eher um das Prinzip, dass man ein bisschen Managment einbaut, dass man die Funktion "kontrolliert" aufruft :)

Aber gut - dafür gibts ja einen eigenen Forumbereich ;)

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...