Tor
Aus SA-MP Wiki
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!
Inhaltsverzeichnis |
Mathematische Grundlagen
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.
Scripten
Vorbereitung
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 OnGameModeInit()
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!
Anweisungen Programmieren
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
Torbewegung
Ausführliche Form (Matrize2.jpg)
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.
Wort zum Ende
Ich hoffe, dass ich vielen mit diesem Tutorial helfen konnte. Du darfst dich nicht gleich entmutigen lassen! Bei mir ist häufig das Tor durch das Universum geflogen, aber nie wo es hinsollte. Die Hauptfehler sind, dass der Drehpunkt oder der Drehwinkel nich ganz korrekt sind (ist mir häufig passiert). Oder statt ein plus ein Minus steht, oder andersherum.
Wenn ihr den Mathematischen Teil nicht ganz versteht ist es nicht so schlimm, solang ihr noch wisst wo was hinkommt :-D. Wenn wirklich nichts mehr geht, meldet euch bitte hier entweder im Forum, oder einfach ein PM (PrivatMessage) mir schicken (Stratege993). Wenn ihr Verbesserungsforschläge etc. habt dann gibts oben ein Knopf Diskussion, da draufklicken. Oder ihr schreibt es mir ach per PM.
Stratege993 22:23, 20. Jun. 2008 (UTC)
© 2008 samp.breadfish
