Jump to content
Unity Insider Forum

Enemy detection mit Raycast in FOV inkl. Kopfbewegung


3ncrypt0

Recommended Posts

Hi zusammen,

ich möchte gerne für eine AI via Raycast eine Enemy Detection umsetzen - Das Ganze soll in einem fliegendem Objekt eingesetzt werden. Der Raycast soll sich über eine FOV erstrecken (links rechts). Damit auch oben und unten Objekte entdeckt werden können (da es ja ein fliegendes Objekt ist), habe ich meinem Flugzeug ein ChildObject hinzugefügt, welches kontinuierlich auf der X Achse zwischen -60° und 60° rotiert und somit eine Art Kopf simulieren soll.

Hierarchie:

MainObject (Rigidbody und ein paar Scripte)

     - Empty Object (Kopf) mit Script für Kopfbewegung und Raycast

 

Hier mal ein paar Snippets:

Das ist für die Kopfbewegung

void HeadShaking()
        {
            float angle = Mathf.Sin(Time.time) * 70; //tweak this to change frequency
            transform.rotation = Quaternion.AngleAxis(angle, Vector3.right);
        }

Und hier für Raycast:

Quaternion startingAngle = Quaternion.AngleAxis(-60, Vector3.up);
Quaternion stepAngle = Quaternion.AngleAxis(5, Vector3.up);

void EnemyDetection()
        {
            RaycastHit hit;
            var angle = transform.rotation * startingAngle;
            var direction = angle * Vector3.forward;
            var pos = transform.position;
            for (var i = 0; i < 24; i++)
            {
                Debug.DrawRay(pos, direction * this.enemyDetectionRange, Color.red);
                if (Physics.Raycast(pos, direction, out hit, this.enemyDetectionRange))
                {
                    var enemy = hit.collider.gameObject;
                    if(enemy.tag == "Player")
                    {
                        Debug.Log("Player entdeckt");
                    }
                }
                else
                {
                    Debug.Log("Weiter auf Waypoint Flug");
                }
                direction = stepAngle * direction;
            }
        }

 

Mein Problem ist, dass die Raycasts nicht in die Richtung der Kopfbewegung gucken - Sie erstrecken sich zwar nach links und recht und fahren auch hoch runter, dabei verschieben die sich aber immer wieder, es sei denn der "Kopf" hat auf der X Achse 0° erreicht. Drehe ich das MainObject, drehen die Raycasts sich nicht mit... Ich hab nun schon einiges ausprobiert aber komme zu keinem Ergebnis.

Setze ich das Script mit EnemyDetection() auf das MainObject und drehe dieses um die Y Achse, ist alles gut. Sobald ich aber das um die X Achse drehe, passieren komische Dinge..

Im Endeffect will ich ja nur ein FOV simulieren für die AI, damit die auch Gegner entdecken kann. Oder sollte man nicht auf Raycast setzen sondern eher auf Trigger Collider?

Die Raycast Function habe ich übrigens hier her: http://answers.unity3d.com/questions/457184/how-to-detect-all-gameobjectsie-enemies-in-field-o.html

VG

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe den Code nur kurz überflogen, aber ich würde folgendes ändern:

Quaternion startingAngle = Quaternion.AngleAxis(-60, transform.up);
Quaternion stepAngle = Quaternion.AngleAxis(5, transform.up);
...
var direction = angle * transform.forward;
...

Dabei ist "transform" das Transform deines Kopfes und dein Kopf sollte mit seiner Vorwärtsachse (blau) in Richtung Ziel schauen also nach "vorn", damit der obige Code funktioniert. Die Rotation des Kopfes habe ich mir nicht im Detail angeschaut, aber du rotierst damit im Worldspace und nicht um die lokale Achse des Kopfes. Ich würde den Kopf eher um seine seine lokale X-Achse (nicken) rotieren (transform.right)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Drehst du den Kopf auch mit?:

 transform.rotation = Quaternion.AngleAxis(angle, transform.right);

Weil ansonsten neigst ggf. den Kopf wenn sich dein Flugzeug im Raum bewegt anstatt mit dem Kopf zu "nicken".

Zudem scheint mir der Start noch falsch gesetzt der sollte denke ich so sein:

var direction = startingAngle * Vector3.forward;

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also noch einmal der komplette Code:

void HeadShaking()
        {
            float angle = Mathf.Sin(Time.time) * 70; //tweak this to change frequency
            transform.rotation = Quaternion.AngleAxis(angle, transform.right);
        }
Quaternion startingAngle = Quaternion.AngleAxis(-60, transform.up);
Quaternion stepAngle = Quaternion.AngleAxis(5, transform.up);

void EnemyDetection()
        {
            RaycastHit hit;
            var direction = startingAngle * transform.forward;
            var pos = transform.position;
            for (var i = 0; i < 24; i++)
            {
                Debug.DrawRay(pos, direction * this.enemyDetectionRange, Color.red);
                if (Physics.Raycast(pos, direction, out hit, this.enemyDetectionRange))
                {
                    var enemy = hit.collider.gameObject;
                    if(enemy.tag == "Player")
                    {
                        Debug.Log("Player entdeckt");
                    }
                }
                else
                {
                    Debug.Log("Weiter auf Waypoint Flug");
                }
                direction = stepAngle * direction;
            }
        }

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi,

Danke! Das hatte funktioniert - allerdings schien das nicht die beste Lösung zu sein - also grundlegend einer EnemyDetection. 

Ich hab es nun ein wenig anders gelöst:

void EnemyDetection(Transform player)
        {
            if (Vector3.Distance(transform.position, player.position) < distance)
            {
                var playerDir = (player.position - transform.position).normalized;

                if (Vector3.Dot(transform.forward, playerDir) > 0 && Vector3.Angle(transform.forward, playerDir) < arc)
                {
                    Debug.DrawLine(transform.position, transform.position + playerDir * distance, Color.red);

                    RaycastHit hitInfo;
                    if (Physics.Raycast(transform.position, player.transform.position - transform.position, out hitInfo) == true)
                    {
                        if (hitInfo.collider.gameObject.tag == "PlayerCollider" && !this.detected && player != null)
                        {
                            this.parent.GetComponent<AeroplaneAiControl>().SetTarget(hitInfo.collider.gameObject.transform);
                            this.detected = true;
                        }
                    }
                }
            }
            else if(Vector3.Distance(transform.position, player.position) > distance && this.detected)
            {
                this.parent.GetComponent<AeroplaneAiControl>().SetTarget(this.currentWaypoint.transform);
            }
        }

Ich prüfe erst den Abstand zwischen meinem Player und der AI, kommen sich beide relativ nah, prüfe ich ob der Player sich in einem bestimmten Winkel vor der AI befindet, dann feuer ich einen Raycast und prüfe ob es wirklich mein Player ist und ob ich diesen erreiche oder ob andere Gegenstände dazwischen sind.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, daß halte ich auch für die bessere Lösung, die 1. Lösung feuert mir zu viele Raycasts ab, wobei du dir die 2. Prüfung mit dem arc eigentlich auch schenken kannst, da du über das Skalarprodukt "eigentlich" den Winkel indirekt schon hast (für 2 normalisierte Vektoren gilt ϕ=arccos(a⋅b)).

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...