Jump to content
Unity Insider Forum
uwe@doerrweb.de

Raycast2d und LayerMask

Recommended Posts

Hallo,

ich bin neu hier, 60 Jahre alt und komme aus Hockenheim. Vor etwa 42 Jahren habe ich mit der Programmierung angefangen und in Unity bin ich quasi neu ^^. Ich hab da ein Problem, dass mich seit Tagen beschäftigt und finde keine Lösung, vielleicht kann mir jemand von euch helfen. Also nun zu meinem Problem:

Ich habe ein Spielfeld mit Bodenplatten aus einem Prefab erzeugt. Sie haben den Layer Boden. Auf dem Boden stehen Objekte mit dem Layer Objekt. Ein Objekt erzeugt nun einen Raycast

hit = Physics2D.Raycast(transform.position, transform.up,lm);

in lm ist die LayerMask Object mit lm = LayerMask.GetMask("Objekt"); übergeben. So wie ich die Beschreibung in Unity verstanden hatte, trifft der Raycast nur Gameobjekte mit diesem Layer. Funktioniert aber leider nicht, er trifft vor ihm die erste Bodenplatte. Ohne Bodenplatten funktioniert der Raycast, dann aber halt nichts sonst ^^. Ich habe alles versucht, was ich im Internet gefunden habe, in Filmen habe ich nur Beispiele gefunden, die keinen Boden oder keine Wand hatten, das geht bei mir aber auch.

Ist mein Unity kaputt? Oder gibt es doch eine Lösung? 

 

Gruß

Uwe

Share this post


Link to post
Share on other sites

Hast du ausschließlich 2D-Collider an den Objekten?
transform.up zeigt normalerweise in der "2D-Welt" nach oben (weil du sagtest du wolltest gegen den Boden raycasten der eigentlich unten sein sollte).

Die Layermask ist eine "Bitzahl" in der die aktuell verfügbaren Masken bit-codiert sind (siehe Layermanager von Unity der Settings pro Projekt hat). Man sollte also darauf achten, dass es den Layer noch gibt im Layermanager. Die können schnell mal verschwinden wenn man einen Custom-Layer angelegt hat und ein Projekt ohne Projektsettings importiert.

Share this post


Link to post
Share on other sites

Hallo, 

ja, nur 2D-Collider, 3-Collider erkennt er gar nicht. Der Linerenderer malt den Raycast so, wie er soll, wenn ich den Boden nicht erzeugen lasse. Die Layermask habe ich auch mit Bits versucht, ändert aber nichts. Aus lauter Verzweiflung habe ich eine leere Szene angelegt, um meine Blödheit zu prüfen, die Layermask hab ich Public gemacht, um einfacher testen zu können, egal was ich da auswähle und welchen Layer ich dem Gegner (Würfel) gebe, er trifft ihn immer.

So sieht der Testcode aus:

public class LaserSchuss : MonoBehaviour
{
    private LineRenderer lr;
    RaycastHit2D hit;
    public LayerMask lm;
    private void Start()
    {
        lr = GetComponent<LineRenderer>();
        lr.enabled = true;
        lr.useWorldSpace = true;
    }
     

    private void FixedUpdate()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            hit = Physics2D.Raycast(transform.position, transform.up,lm);
        }
        if (hit.collider)
        {
            print(hit.collider.name);
            lr.SetPosition(0, transform.position);
            lr.SetPosition(1, hit.point);
        }
    }
}

In der Szene ist unten ein Würfel, der als Kindobjekt den Laser hat, dieser Laser hat das Script und ist etwas vor dem Würfel, damit er sich nicht selbst trifft.. Oben und rechts ist je ein Würfel, denen ich irgendwelche LM`s geben kann. Ich habe mal 2 Bilder angehängt, im Ersten ist die Rotation 0,0,0 und er schießt nach oben und trifft den Würfel der den Layer Boden hat. Im zweiten Bild habe ich den Schützen auf 0,0,-90 rotiert und er trifft rechts, eigentlich dürfte er Keinen treffen :(.

Gruß

UweLaser1.thumb.png.a317c03b81da3654463d81f75180aac3.pngLaser2.thumb.png.052bfc5b074fa771de9c2d4c4cd6484b.png 

Share this post


Link to post
Share on other sites

Danke für die Hilfe! Ich hab Unity Version 2019.3.0f1.

Hier mit dem Boden, LM steht auf Objekt und die Mauer auf die er zielt hat den Layer Objekt, der Boden heißt Boden und hat den Layer Boden, also sollte er den nicht treffen...

 

Laser3.png

Share this post


Link to post
Share on other sites

Der 3. Parameter der Methode ist die Länge des Raycast und hier wurde in deiner Klasse die Mask übergeben. Die Mask stimmt so, habe ich noch einmal geprüft, aber besser man übergibt value (ansonsten funktioniert deine Klasse aber so wie sie soll):

hit = Physics2D.Raycast(transform.position, transform.up, 10f, lm.value); // 10 ist die Länge des Raycasts

 

  • Like 1

Share this post


Link to post
Share on other sites

Der Klassiker und ein hervorragendes Beispiel dafür, dass implizite Casts eine sehr schlechte Idee sind.

Nur kurz zur Erklärung, evtl auch für andere, die den Thread finden: Raycast erwartet keine LayerMask, sondern ein int, das als Bitmaske gelesen wird, also dessen Bits als eine Reihe von Booleans funktionieren. Jedes Bit der Zahl steht dabei für einen Layer, und bei 0 wird dieser Layer ignoriert. Deswegen gibt's auch nur bis zu 32 Layer: So viele Bits hat ein int. Unitys LayerMask-Struct hat einen impliziten Cast zu int, sodass man nicht "(int)lm" schreiben muss. Allerdings ist, wie @Zer0Cool richtig sagt, der dritte Parameter vom Typ float, und von float zu int gibt es ebenfalls einen impliziten Cast. Diese beiden Zeilen werden ohne Beanstandung kompiliert:

int foo = LayerMask.GetMask("Object");
float foo = LayerMask.GetMask("Object");

Somit akzeptiert Unity eine Layermask als Raycast-Distanz-Parameter, und man sucht such dumm und dusselig.

  • Like 2

Share this post


Link to post
Share on other sites

SUUUUPPPEEERR!!!!!

Wie kann ich dir Danken? Dafür habe ich Stunden über Stunden gegrübelt ^^. Unity hätte mir ja auch eine Fehlermeldung geben können....

Du hast mir wirklich sehr geholfen, ich wollte schon alle Platten vor dem Schuss in ein Array lesen und den Collider ausschalten :). Bis zum nächsten mal, bin ja noch nicht fertig ^^.

Vielen, vielen, vielen Dank!

Dir auch Danke, Sascha! Fürs dumm und dusselig suchen ^^.

 

Gruß Uwe

LaserGeht.png.ef9bd536e6ba5b46e75a8180c0c5531d.png

Share this post


Link to post
Share on other sites

Hallo,

jetzt funktioniert fast alles, so wie ich das möchte, danke nochmal. Jetzt bin ich auf ein neues Problem gestoßen, da hängt sich Unity auf und kann nur mit dem Taskmanager beendet werden ^^.

Kurz zur Funktion: Mit linkem Mausklick kann ich die Spiegel aus dem "Lager" nehmen und auf der Spielfläche absetzen, auch umsetzen. Mit Rechtsklick drehe ich die Spiegel. So sieht es ja gut aus:

LaserFunktioniert.png.89ad0247397312c2cb363e46ebd4a2a7.png

Die Mauer oder ein Spiegel nicht auf der weißen Fläche treffen wäre Game Over, was auch alles funktioniert.Wenn ich jetzt aber den letzten Spiegel nach links, anstatt nach rechts spiegeln lassen will, hängt sich Unity komplett auf ^^. Dafür muss ich eine neue Frage starten, oder?

Gruß

Uwe

Share this post


Link to post
Share on other sites
vor 9 Minuten schrieb uwe@doerrweb.de:

Dafür muss ich eine neue Frage starten, oder?

Gibt keinen wütenden Mob, wenn du's nicht tust, aber wäre schon gut :) Eins schon einmal vorweg: "Unity hängt sich auf" bedeutet eine Endlosschleife in deinem Code. Vermutlich ein unendlich oft gespiegelter Laser. Da solltest du in jedem Fall etwas Code posten.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...