Tore erstellen - Öffnen/Schließen

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Da viele gefragt haben, wie man ein Tor auf Kommando öffnen und wieder
    schliesen lassen kann, ist hier ein Tutorial entstanden. Hier wird ein
    Schwenktor beschrieben. Dieses ist sehr viel schwerer als ein Schiebetor
    zu erstellen!


    Drehung in einem 2-Dimensionalen Raum
    Um ein Tor zu programmieren braucht man ein paar Mathematische
    Kenntnisse. Das Große Problem bei einem Tor ist, wenn man mit der
    Funktion SetObjectRot
    dreht, der Drehpunkt von den Objekt fast immer in der Mitte ist.
    Genauso wie bei unseren Tor (Objectid: Linkes_Tor:985 Rechtes_Tor:986).
    Wir nehmen für unser Beispiel blos 1ne Torhälfte wegen der Einfachheit.
    Wie gesagt, dass Objekt dreht sich um sein Mittelpunkt, bei der Skize
    rechts um den Punkt M. Wir gehen mal davon aus das wir unser Tor um 90°
    öffnen wollen. Die Folge davon wäre, dass das Tor am Ende wie die Gelb
    gestrichelte Linie dastehen würde. Das wäre natürlich nicht schön.


    Jetzt müssen wir eine Lösung finden wie wir den Objekt sagen können,
    dass es um den Punkt Z drehen soll. Schön wäre es wenn es eine Funktion
    geben würde wie zb: TurnObjectToPoint. Leider gibt es so
    eine Funktion nicht und wir müssen uns selber Gedanken machen wie wir
    das Objekt drehen lassen können um ein Punkt. Also ab ich im Netz etwas
    rumgewühlt und habe diese Formel gefunden:



    Sie sieht zwar auf den ersten Blick etwas komisch aus, ist aber richtig.
    Das ist eine Matrex-version, von der Drehung um einen Punkt mit den
    Koordinaten (0/0). Jetzt wirst du dich wundern: "Warum um den Punkt
    (0/0)? Wir wollen doch um einen Beliebigen Punkt irgendwo drehen!" Das
    ist mir auch bekannt, deshalb müssen wir sie noch für unsere Zwecke
    anpassen:



    Nun habe ich die Matrex aufgelöst. Für x und y müssen wir jetzt unsern
    Vektor ZM einsetzten. Jetzt muss man nachdenken, wie man den Vektor ZM
    rausbekommt (Realschule: 7. Klassse). Natürlich Spitze minus Fus. Das
    heist wir müssen die x Koordinaten von M minus die x Koordinaten von Z
    und das ganze dann auchnoch für y. Am ende muss man natürlich noch die x
    und y Koordinaten von Z dazuzählen. Wenn man das alles richtig gemacht
    hat bekommt man den Punkt M'. Und so sieht die Formel dazu aus:




    Drehung in einem 3-Dimensionalen Raum (Nicht Wichtig)
    Ihr werde ich euch auchnoch die Formel für die Drehung im 3-Dimensionalen Raum vorstellen. Aber sie wird für das Toröffnen nicht gebraucht!.
    Also wer keine Lust auf weitere Mathematik hat kann den Teil getrost
    überspringen. Für die die irgenwas in 3 Dimensionen drehen wollen, ist
    diese Matrize hilfreich:

    Ab hier müsst ihr aber alleine zurechtkommen. Zum ersten braucht man ja
    wie gesagt die Formel nicht für das Tor und 2. wäre es viel zu
    langwierig um alle Details zu erklären und 3. ist die Formel ja auch
    fast selbsterklärend.



    Wir wollen ein Tor machen. Schon in San Andreas enthaltene Objekte kann
    man nicht nutzen! Dafür müssen wie ein geeignetes Objekt einfügen. z.b:


    975 - normales Tor
    985 - ein rechtes Torstück
    986 - ein linkes Torstück


    Wir brauchen für unser Test ein Linkes Torstück. Zudem gebe ich geignete Koordinaten für ein Spawn-Punkt an, damit man es schnellstmöglich testen kann und nicht lange suchen muss. Das alles kommt in public OnGameModInit()
    AddPlayerClass(0,962.4860,-1109.3821,23.6934,223.7676,0,0,0,0,0,0);
    Tor = CreateObject(985,952.55,-1107.5,24,0,0,270);


    Wie man schon sieht braucht man auserdem ein Paar Variabelen. Hier wird auf die Variabele Tor die Objekt-ID des Objektes gespeichert. Die Variabelen definierst du gleich hinter #include<a_samp>
    new Tor;
    new TimerOpen;
    new TimerClose;
    new Float:drehpunktx = 952.8;
    new Float:drehpunkty = -1111.5;
    forward TorOpen();
    forward TorClose();

    Also drehpunktx ist die x Koordinate des Drehpunktes, drehpunkty ist die y Koordinate das Drehpunktes. TimerOpen bekommt die Timer-ID damit man in auch wieder löschen kann, genauso wie Timer Close.
    Auserdem werden 2 Funktionen Resaviert. Du kannst sie natürlich umbenennen, musst sie aber im weiteren Verlauf auch immer umbenennen!


    Wir machen es jetzt so das man wärend des Spieles einfach /open oder /close eingibt, damit sich das Tor öffnet. Also ab in public OnPlayerCommandText(playerid, cmdtext[]) und das ergänzene:
    if (strcmp("/open", cmdtext, true, 10) == 0)
    {
    KillTimer(TimerOpen);
    KillTimer(TimerClose);
    TimerOpen = SetTimer("TorOpen", 50, 1);
    return 1;
    }
    if (strcmp("/close", cmdtext, true, 10) == 0)
    {
    KillTimer(TimerOpen);
    KillTimer(TimerClose);
    TimerOpen = SetTimer("TorClose", 50, 1);
    return 1;
    }
    Mann muss immer erst beide Timer beenden, weil es sonst passieren kann
    das 2 Timer Parallel gehen. Das wäre sehr schlecht, weil sich das Tor
    entweder doppelt so schnell dreht, oder beide Timer gegeneinader
    abreiten und keiner Gewinnt (Tor ruckelt hin und her, geht aber nicht
    auf und zu).
    Danach wird immer 1 Timer definiert, der das Tor alle 50 Millisekunden
    bewegt. Wer es schneller will muss die Zahl kleiner machen, wer es
    langsamer haben will der soll sie Größer machen. Also so:


    x = klein dann geht es schneller (aber größere Rechenleistung)
    x = groß dann geht es langsamer

  • Jetzt muss man den ganzen Teil hinzufügen:
    public TorOpen()
    {
    new Float:xrot; //Definition von Variabele.
    new Float:yrot;
    new Float:zrot;
    new Float:xpos;
    new Float:ypos;
    new Float:zpos;
    new Float:xposneu;
    new Float:yposneu;
    GetObjectRot(Tor,xrot,yrot,zrot); //Auslesen der Rotation
    GetObjectPos(Tor,xpos,ypos,zpos); //Auslesen der Position


    if (zrot==180) //Aschauen ob schon der Richtige Winkel erreicht ist
    {
    KillTimer(TimerOpen);
    }
    else //Wenn er nochnicht erreicht ist wird weitergedreht
    {
    SetObjectRot(Tor,xrot,yrot,zrot-1); //Schritt 1
    xpos = xpos-drehpunktx; //Schritt 2
    ypos = ypos-drehpunkty; //Schritt 2
    xposneu = (floatcos(-0.02)*xpos)+((-floatsin(-0.02))*ypos); //Schritt 3
    yposneu = (floatsin(-0.02)*xpos)+(floatcos(-0.02)*ypos); //Schritt 3
    xpos = xposneu+drehpunktx; //Schritt 4
    ypos = yposneu+drehpunkty; //Schritt 4
    SetObjectPos(Tor,xpos,ypos,zpos); //Schritt 5
    }
    }


    public TorClose()
    {
    new Float:xrot;
    new Float:yrot;
    new Float:zrot;
    new Float:xpos;
    new Float:ypos;
    new Float:zpos;
    new Float:xposneu;
    new Float:yposneu;
    GetObjectRot(Tor,xrot,yrot,zrot);
    GetObjectPos(Tor,xpos,ypos,zpos);
    if (zrot==270)
    {
    KillTimer(TimerClose);
    }
    else
    {
    SetObjectRot(Tor,xrot,yrot,zrot+1);
    xpos = xpos-drehpunktx;
    ypos = ypos-drehpunkty;
    xposneu = (floatcos(0.02)*xpos)+((-floatsin(0.02))*ypos);
    yposneu = (floatsin(0.02)*xpos)+(floatcos(0.02)*ypos);
    xpos = xposneu+drehpunktx;
    ypos = yposneu+drehpunkty;
    SetObjectPos(Tor,xpos,ypos,zpos);
    }
    }


    Fangen wir mal an. Die ersten 8 Zeilen sind blos da um Variabelen zu
    definieren. Mit den 2 Folgenden Zeilen werden die aktuellen Daten des
    Tores ausgelsen (Position und Rotation). Nun wird geschaut ob die
    Rotation übereinstimmt, wenn er übereinstimmt wird der Timer gelöscht
    und das Objekt bewegt sich nichtmehr. Sonst wird es weitergedreht.


    Achtung: Er fängt nicht ab 360 wieder von null an! Sondern
    weiter über 360! Also wenn du dein Objekt schon mit 270° hingestellt
    hast und es um 120° drehen willst, musst du den Endwinkel als 390°
    angeben!


    Wenn der Winkel noch nicht erreicht ist, werden diese 5 Schritte gemacht.






    • Als erstes wird das Objekt um 1° gedreht.
    • Nun wird der Vektor von Drehpunkt zu Mittelpunkt des Objektes
      berechnet. Diesen brauchen wir, weil unsere Formel rechts, blos Vektoren
      drehen kann, oder Drehungen um den 0 Punkt. Warum man als Winkel -0.02
      eingibt statt -1, weis ich selber nicht. Ich habe diesen Wert aus
      Experimenten gezogen.
    • Danach wird der Vektor wieder mit dem Drehpunkt addiert.
    • Zu guter letzt, wird das Objekt neu Positioniert.



    Das sind die 5 Wichtigen Schritte für das öffnen des Tores. Nun
    wollen wir es ja auch wieder schliesen, dafür ist der 2. Timer. Sie
    unterscheiden sich blos, dass er immer 1 DAZU addiert und das es nicht
    -0.02 sondern 0.02 heist bei der Drehung.



    Vereinfachte Form (Matrize3.jpg)


    Man kann es auch etwas leichter machen, dann spart man Zeilen. Dir
    ist vieleicht aufgefallen das wir nicht Matrize3.jpg sondern
    Matrize2.jpg verwendet haben. Wenn man Matritze3.jpg verwenden will, ist
    blos Schritt 2 und 4 mit in Schritt 3 drin, dann sieht es so aus:


    public TorOpen()
    {
    new Float:xrot;
    new Float:yrot;
    new Float:zrot;
    new Float:xpos;
    new Float:ypos;
    new Float:zpos;
    new Float:xposneu;
    new Float:yposneu;
    GetObjectRot(Tor,xrot,yrot,zrot);
    GetObjectPos(Tor,xpos,ypos,zpos);


    if (zrot==180)
    {
    KillTimer(TimerOpen);
    }
    else
    {
    SetObjectRot(Tor,xrot,yrot,zrot-1);
    xposneu = ((floatcos(-0.02)*(xpos-drehpunktx))+((-floatsin(-0.02))*(ypos-drehpunkty)))+drehpunktx;
    yposneu = ((floatsin(-0.02)*(xpos-drehpunktx))+(floatcos(-0.02)*(ypos-drehpunkty)))+drehpunkty;
    SetObjectPos(Tor,xposneu,yposneu,zpos);
    }
    }


    public TorClose()
    {
    new Float:xrot;
    new Float:yrot;
    new Float:zrot;
    new Float:xpos;
    new Float:ypos;
    new Float:zpos;
    new Float:xposneu;
    new Float:yposneu;
    GetObjectRot(Tor,xrot,yrot,zrot);
    GetObjectPos(Tor,xpos,ypos,zpos);
    if (zrot==270)
    {
    KillTimer(TimerClose);
    }
    else
    {
    SetObjectRot(Tor,xrot,yrot,zrot+1);
    xposneu = ((floatcos(0.02)*(xpos-drehpunktx))+((-floatsin(0.02))*(ypos-drehpunkty)))+drehpunktx;
    yposneu = ((floatsin(0.02)*(xpos-drehpunktx))+(floatcos(0.02)*(ypos-drehpunkty)))+drehpunkty;
    SetObjectPos(Tor,xposneu,yposneu,zpos);
    }
    }

    Dieser Code geht auch, aber du musst genauso die 2 Überschriften "Anweisungen Programmieren" und "Vorbereitung" durchführen.