Jump to content
Unity Insider Forum

Bei einem Zussammenstoss, soll der Spieler Schaden nehmen


Joscupe

Recommended Posts

Hallo ich wollte ein Script programmieren der immer wenn der Spieler (Player im Script) mit einem Gegner 'Zussammenstösst' dann soll er 1 Lebenspunkt verlieren. Durch die Unity Dokumentation (https://docs.unity3d.com/ScriptReference/Collision-gameObject.html) habe ich das versucht:

public class enemies : MonoBehaviour
{

    public float health = 10;

    void OnCollisionEnter(Collision collision)
    {
        Debug.Log("Es gab einen Zussammenstoss");
        if (collision.gameObject.name == "player")
        {
            health -= 1;
            Debug.Log("Dein Leben:" + health);

           
        }
    }
}

Ich habe den Script an den Gegner angefügt, jedoch als ich es ausprobierte (Ich verschiebte den Spieler Manuell mit den X/Y Pfeilern) funktionierte es nicht. Zuerst dachte ich dass es am Namen lieg (also an der if - Abfrage), deshalb versuchte ich dass es mir jedes mal wenn etwas mit dem Gegner zussammenstösst soll es etwas in der Console ausgeben. Ich teste es wieder gleich und es funktionierte auch nicht. Der Gegner ist ein roter Würfel und der Spieler eine blaue Kapsel. Meine Frage ist ob jemand weiss wie ich das lösen kann?

Joscupe

Link zu diesem Kommentar
Auf anderen Seiten teilen

Beide Objekte brauchen natürlich einen Collider, denn nur dann gibt es überhaupt Kollisionen mit anderen Objekten. Die Collider geben ja über ihre Form an, wo dein Objekt physikalisch gesehen anfängt und endet.

Damit aber die physikalischen Funktionen aufgerufen werden (OnCollisionEnter usw.) muss mindestens eines dieser Objekte einen Rigidbody haben.

Ein Rigidbody ist übersetzt ein "fester Körper". Er gibt dem Objekt überhaupt erst die Möglichkeit an etwas anderem abzuprallen oder es wenigstens zu bemerken (wie es bei einem Trigger wäre). Er kennt den Collider und dessen Flächen und rr erkennt wo und mit wem eine Berührung statt gefunden hat und nur duch ihn werden diese Funktionen überhaupt aufgerufen, die dann dir die Möglichkeit geben gewisse Informationen zu bekommen um damit dann etwas zu zun.

Ein Rigidbody muss also im Spiel sein. Entweder auf dem Player oder auf dem Gegner. Egal wer ihn hat, es werden bei beiden Objekten diese Funktionen aufgerufen, wenn sie im Script angelegt wurden. Natürlich dürfen auch beide einen RB haben.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Noch eine kurze andere Frage ich würde gerne dass meine Kamera dem Spieler folgt aber nur auf der X - Achse, die Y/Z - Achse sollte sich nicht bewegen. Ich versuchte dass:

public class CameraFollows : MonoBehaviour
{
    public GameObject player;
    void Update()
    {
        transform.position.x = player.transform.position.x;  
    }
}

Ich wollte das die Transform Positon x gleich ist wie die des Spielers, es zeigt mit jedoch immer einen Fehler jetzt weiss ich nicht genau wieso.

Joscupe

Link zu diesem Kommentar
Auf anderen Seiten teilen

Noch eine andere Frage wie kann ich einen Map generator machen (für einen Jump and Run) mit unterschiedlich 'langen' Prefabs ich hab nicht wircklich eine ahnung wie ich dass machen soll ich versuchte es mit diesem Skript:

public class mapGenerator : MonoBehaviour
{
    public GameObject[] map = new GameObject[4]; // 4 Prefabs 
    public GameObject player;
    public float xAxis = 0; // x - achsen wert ab dem die schleife läuft
    public float repeatX = 0; // Wert wie viel mal sich die for Schleife wiederholen soll

    void Update()
    {
        if (player.transform.position.x > (xAxis - 5))
        {
            repeatX += 20; // es soll 5 Prefabs generieren
            for (float x = 0; x < repeatX; x += 4) 
            {
                var mapCreator = map[Random.Range(0, map.Length)];
                Instantiate(mapCreator, new Vector3(x, 0, 0), Quaternion.identity);
                xAxis = x;
            }
        }
    }
}

Leider aber Erfolgloss. Ich dachte dass man die wie aneinander Reihen könnte jedoch sind sie in wircklichkeit zussammengequetscht.

Jetzt ist meine Frage wie ich das Programmieren könnte. Ich habe 4 Prefabs 3 davon sind 4 mal 0.64 beite Blöcke und einamal 3 0.64 breite Blöcke

Joscupe

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo, ich versuchte etwas neues um das Problem mit der Länge von den Prefabs zu lösen, ich gab jedem Prefab ein leeres Gameobject am Ende des Prefabs, ich nannte sie EndPosition. Jetzt wollte ich im Skript das er zuerst random einen der 4 Prefabs auswählt und den generiert von dem soll er dan die EndPostion bestimmen und noch ein Prefab generieren am ende des letzten Prefabs, sprinch an der Endposition. Ich machte diesen Script:

    void Update()
    {


        if( x < 1)
        {
            var randomPrefab = map[Random.Range(0, map.Length)];
            Instantiate(randomPrefab, endPosition, Quaternion.identity);
            //endPosition = randomPrefab.Find("EndPosition").position;
            EndObject = GameObject.Find("EndPosition");
            endPosition = EndObject.transform.position;
            Debug.Log(endPosition);
            Instantiate(randomPrefab, endPosition,Quaternion.identity);
            x += 1; 
        }
    }

er ermittelt zwar jeweils die EndPosition (oder glaube ich zumindestens) aber die Position ist dann völlig falsch z.b erstes Prefab von 0x 0y zu 2.56x 0y der zweite prefab wird jedoch dann irgendwie 56x -5y. Ich frage mich wo der Fehler liegen könnte.

Joscupe

 

Bearbeitet:

Mir wird immer dieser Fehler angezeigt;

NullReferenceException: Object reference not set to an instance of an object
mapGenerator.Update ()

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich versuchte jetzt eine letzte taktik aber irgendiwe werden die Prefabs ganz Falsch geladen.

    public GameObject[] map = new GameObject[4]; // 4 Prefabs 
    public GameObject player;
    public Vector3 endPosition = new Vector3(0,-15,0);
    public Vector3 positionOffset = new Vector3(0.64f,0,0);
    private int x = 0;
    public GameObject EndObject;
    void Update()
    {


        if( x < 1)
        {
            var randomPrefab = map[Random.Range(0, map.Length)];
            Instantiate(randomPrefab, endPosition, Quaternion.identity);
            EndObject = GameObject.Find("EndPosition");
            endPosition = EndObject.transform.position;
            endPosition.x = EndObject.transform.position.x / 15 ;
            endPosition.y = EndObject.transform.position.y / 15;
            Debug.Log(endPosition);
            Instantiate(randomPrefab, endPosition + positionOffset,Quaternion.identity);
            x += 1; 
        }
    }

Ich fand heraus das die X/Y Kooridnaten durch 15 gerechnet werden müssen damit die Original Koordinaten des EndObjects herauszufinden.

542890757_Screenshot2021-04-17183646.thumb.png.acf3a1d3bae9a69df918941bf96cc3aa.png

Laut dem Skript wollte ich nur 2 Prefabs anzeigen lassen, jedoch sind mehrere Prefabs da und dann noch zussammengedrückt. Weiss jemand wieso?

Joscupe

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstmal vorneweg:
Bitte mach für jedes Problem einen eigenen Thread auf.
Und das aus zwei Gründen. Zum einen soll es ja auch anderen Leuten helfen, die nach ähnlichen Problemen suchen. Haust du 3 verschiedene Sachen in einen Thread rein, gehen die 2 weiteren Sachen verloren. Die Überschrigt behandelt ja nur das erste Thema.
Außerdem wird nicht unbedingt darauf geantwortet, weil nicht jeder zu allem eine Antwort hat. Er hätte vielleicht ne Antwort zum Thema 2 aber eben nicht zur Überschrift, also guckt er nicht rein und wartest vergeblich.

Zu deinem Prefabproblem und den unterschiedlichen Längen.

Nutze ein GameObject Array, wo du all deine Prefabs rein tust. Die längeren Prefabs legst du in die letzten Plätze.
Wenn das Array 4 Plätze hat und die ersten 2 Plätze sind mit kurzen Prefabs und die letzten 2 Plätze mit langen Prefabs befüllt, dann kannst du über die Platznummer deine neuen X Positionen ermitteln.

So etwa.

public GameObject[] Prefab= new GameObject[4]; // dein Array wo die Prefabs drin liegen
Vector3 tilePosition = new Vector3(10,0,0); // einfach mal diese start Position gesetzt

// in der Update rufst du die Zufallsfunktion auf und übergibst ihr die momentane Setzposition für das nächste Tile
void Update(){
  if(irgendwas){ 
    SetARandomTile(tilePosition); // tilePosition ist die Position wo das neue Tile enstehen soll
  }
}

void SetARandomTile(Vector3 setPosition){ // die Tileposition wird hier meiner internen Variable setPosition übergeben
  // es gibt 4 Tiles zur Auswahl
  // auf Platz 0 und 1 sind kurze Tiles. Auf 2 und 3 sind lange Tiles
  int platz= Random.Range(0,4); // bei Int, also ganzen Zahlen immer einen mehr nehmen. Aus der 3 wird also eine 4
  float laenge = 4; // als Beispiel is das lange Teil einfach mal 4 Einheiten lang. Das nehmen wir einfach mal an.
  if( platz < 2){
    // das ausgewählte Objekt ist aber ein kurzes Teil,als müssen wir die gesetzte Länge anpassen.
    laenge=3; // jetzt die die Länge nur noch 3
  }
  Instantiate(Prefab[platz],setPosition,Quaternion.identity); // Jetzt wird das zufällige Prefab an der übergebenen Position gesetzt.
  setPosition.x+=laenge; // erst jetzt wird die setPosition mit der länge des Tiles verändert
  tilePosition=setposition; // jetzt die veränderte setPosition der tilePosition übergeben.
  // diese tilePosition würde beim nächsten Aufruf der Funktion zum setzen genutzt werden und danach wieder verändert werden. 
}

  


  
  

Das funktioniert jetzt nur, wenn du die genauen Längen der Prefabs kennst.

Wegen deiner Fehlermeldung:
Eine NullRefereceException bedeutet immer, dass eine Variable, die eigentlich eine Referenz auf ein Objekt haben sollte, leider keine Referenz hat. Der Variable wurde also nichts hinzugefügt, oder das Objekt, welches hinzugefügt wurde, ist evtl. ein Szenenobjekt welches im Verlauf des Spiels zerstört wurde.

Das könnte bei dir sein, dass in deinem GameObject Array ein Platz leer ist, dieser Platz aber angesprochen wird.
Sollte bei dir das Array größer sein als Objekte da sind, dann verkleinere es im Inspector entsprechend, oder aber frag nur so viele Plätze ab, wie auch befüllt sind.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das kann ich nicht sagen.
Da musst du jetzt selber mal schauen was da los ist. Und vorallem musst du für dich selber verstehen was da passiert.
Wenn dir 100% klar ist, was der Code da macht, dann pausierst du einfach mal deine szene und schaust, wo welches Tile instanziert wurde. Du brauchst es ja nur anklicken und schon siehst du im Inspector seine Werte. Und in der Szene siehst du ja auch wo es liegt.

Du kannst auch am Ende der Funktion einfach mal eine Textausgabe generieren. Z.B.

Debug.Log("neue Position wird "+tilePosition+" werden");

Ja und dann schaust du einfach ob die Positionsangabe so ist, wie du sie gerne hättest und ob das nachste Tile auch da zu sehen sein wird.

Probiers aus. Versuch die von uns gezeigten Beispiele zu verstehen und nicht nur einfach einzufügen. Das ist das A und O! Es sind nur Beispiele, die dir beim Verständnis helfen sollen. Die Situation in deinem Spiel braucht vielleicht etwas Anderes, aber wenn du verstanden hast was das Beispiel macht, dann kannst du mit dem Gelernten den nötigen Code für dein Spiel selber schreiben. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...