PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Objekt zuerst zum Spieler, dann auf den Boden setPos-en


Wolkenbeisser
10.09.2014, 23:09
Hallo zusammen

Ich könnte wieder einmal zu einem Code-Schnipsel Unterstützung gebrauchen.

AUSGANGSLAGE:
- Spielbare Einheit mit dem Namen AL1 auf der Karte
- Kleiner Rasenmäher mit dem Namen Stao_AL1 auf der Karte
- Nach dem (Base-) Respawn wird die Einheit AL1 zum Rasenmäher Stao_AL1 gebeamt
- Ziel: Respawn soll nicht exakt beim Todesort sein

Mit einem Auslöser (jeder/mehrfach/vorhanden) setze ich den Rasenmäher 70m hinter die Einheit AL1, sobald diese sich 100m von Stao_AL1 entfernt hat. Somit hat AL1 quasi seinen persönlichen Respawnpunkt im Schlepptau. Dieser Auslöser funktioniert bereits. Er ist so aufgebaut:

BED: this and vehicle AL1 in thislist and vehicle AL1 distance Stao_AL1 > 100

AKT: Stao_AL1 setPos [(getPos vehicle AL1 select 0) -70, (getPos vehicle AL1 select 1) +0, (getPos vehicle AL1 select 2) +0]


PROBLEM:
Am Boden und in Fahrzeugen funktioniert der obige Auslöser perfekt. Leider jedoch nicht, wenn AL1 aus 1000m Höhe aus dem Heli springt und vergisst die Reissleine zu ziehen. Er schlägt dann ein, und der Rasenmäher Stao_AL1 ist wie geplant 70m hinter ihm. Leider ist 'hinter ihm' im Falle eines senkrechen Falles 'über ihm' :(.

Resultat: AL1 respawnt in 70m Höhe, fällt runter und stirbt. Dann respawnt er wieder in 70m Höhe, fällt runter und stirbt. Dann respawnt er wieder, usw... ewiges Fegefeuer sozusagen... :ugly:

LÖSUNGSANSATZ:
Offenbar gibt es im Arma3 den Befehl SetPosATL (above Terrain Level). Die Frage ist nur: Wie muss ich den obigen Auslöser anpassen, dass der Rasenmäher Stao_AL1 nicht nur 70m hinter AL1, sondern gleichzeitig auch immer 'auf Grund' ist (es wäre auch egal, wenn er gleich unter AL1 ist, während der senkrechten Bewegung)?

Ich kämpfe derzeit mit den verschiedenen 'this selec 0,1 und 2' - und habe deshalb bisher noch keinen Plan, wie der Auslöser aussehen muss. Vielleicht hat sogar jemand eine Idee, wie man die Aktivierungszeile des Auslösers noch besser machen kann...

Jedenfalls jetzt schon vielen Dank für die Hilfe.

Nokman
11.09.2014, 10:05
Stao_AL1 setPos [(getPos vehicle AL1 select 0) -70, (getPos vehicle AL1 select 1) +0, (getPos vehicle AL1 select 2) +0]

änderst du auf
Stao_AL1 setPos [(getPos vehicle AL1 select 0) -70, (getPos vehicle AL1 select 1),0]

Dadurch wird die Position immer auf denn Boden genommen und nicht in der Luft da du die Höhe des Spielers gespeichert hattest kommt er dahin zurück. Zusätzlich brauchst du das +0 nicht zu schreiben

Wenn du getposatl verwendest musst du bei setpos dann auch setposatl verwenden (ausser du willst denn Effekt der falschen Höhe erzielen) In einen Falle ist aber der Getpos befehl mit Setpos voll und ganz ausreichend

Was nun auch noch ist du Ziehst im Grunde denn spawn nicht hinter dir her Sondern Schiebst ihn 70m weiter auf der x achse was auch je nach bewegung Vor, neben oder hinter dir sein kann

Wolkenbeisser
11.09.2014, 15:56
Danke für die Antwort Nokman.

Der 'Schleppspawn' sollte theoretisch immer rückwärts auf der Strecke liegen, die der Spieler zurückgelegt hat. Da ich aber nicht weiss, wie man eine solche 'Spur' speichern könnte, begnüge ich mich zurzeit damit den Respawnpunkt auf der X-Achse abzulegen.

Solange der Spieler sich nicht seitwärts oder rückwärts bewegt (sprich, solange er die Taste "W" benutzt), ist dieser Punkt dann schon in etwa "dort, wo der Spieler herkommt".

Trotzdem: Falls jemand eine bessere Methode wüsste, bin ich dankbarer Abnehmer dafür.

Vienna
11.09.2014, 18:39
Versuche einmal diesen Code. z.B. mit einem Auslöser starten.

Beim Übergabewert 100 wird in 50m Abständen in zwei Variable die Position des Spielers gespeichert. Unter 100 sollte der Wert nicht liegen.

Respawn 50 bis 100 Meter entfernt der letzten Position:

temp = 100 spawn
{
sleep1;
if (!local player) exitwith {};
private ["_posX","_pos1","_pos2"];
_posX = [getPos player select 0,getPos player select 1];
_pos1 = _posX;
_pos2 = _posX;
while {true} do
{
waitUntil {alive player};
if (_posX distance _pos1 > _posX distance _pos2)then{_posX=_pos1}else{_posX=_pos2};
player setPos _posX;
while {alive player} do
{
waitUntil {sleep 0.5; !alive player or _pos1 distance getPos player > _this/2};
if (alive player) then
{
_pos2 = [getPos player select 0,getPos player select 1]
};
waitUntil {sleep 0.5; !alive player or _pos2 distance getPos player > _this/2};
if (alive player) then
{
_pos1 = [getPos player select 0,getPos player select 1]
}
};
_posX = [getPos player select 0,getPos player select 1]
}
};

Wolkenbeisser
11.09.2014, 20:14
Danke für den Code Vienna. Ich werde das sobald wie möglich ausprobieren.

Übrigens: Der Zufall wollte es, dass ich beim Testen m.o.w. immer von West nach Ost unterwegs war. Darum war mein bisheriger Schlepp-Respawn immer hinter dem Spieler. Hätte ich mich beim Testen auch mal von Ost nach West bewegt, hätte ich herausgefunden, dass der Schlepp-Respawn plötzlich vor mir liegt... :(

Somit ist meine bisherige Methode hinfällig. Ich versuche es nun mit Vienna's Code.

@ Vienna, noch eine Frage: Ich vermute bei Deinem Code reicht ein Auslöser für alle Spieler, da der Schlepprespawn hier offenbar für jeden Spieler lokal durchgeführt wird, oder? Das 'if (!local Player) exitwith...' lässt darauf schliessen. Stimmt's?

Wolkenbeisser
11.09.2014, 21:27
Ok, Vienna's Code funktioniert... fast. Ich glaube mit einem anderen Auslöser funke ich noch ein wenig dazwischen (dazu gleich mehr).

Das Tolle an Vienna's Code ist, dass ich folgende Dinge nicht mehr brauche:

- Marker respawn_west
- Rasenmäher, welche als Hinbeampunkt für die Spieler verwendet wurden
- Ausl. um respawn_west, welche jeden Spieler zu seinem Rasenmäher beamte

Im Moment ist es aber noch so, dass mit Vienna's Code die Spieler nicht mehr in den Heli gebeamt werden, der sie ins Zielgebiet bringt. Grund dafür, dürfte wohl das hier sein:

------------------
Damit im Heli wirklich nur diejenigen Spielfiguren sitzen, die durch menschliche Spieler besetzt werden (die anderen müssen an einem bestimmten Punkt auf der Karte stehen bleiben!), benutze ich folgenden Code in der Init-Zeile jeder spielbaren Figur: temp = [this,Tarnheli1] spawn {private "_time", _time = 60; while {_time > time} do {if (player == _this select 0) then {player moveInCargo (_this select 1); if (player != vehicle player) then {_time = 0}}; sleep 1}}; this allowDamage false; this addRating 50000; null = [this] execVM "inventar\inventar_Tester1.sqf"
------------------

Nun passiert folgendes:
a) Wenn ich Vienna's Code mit einem Auslöser starte dessen BED auf 'true' steht, werden die Spieler nicht mehr in den Heli gebeamt (oder grad sofort wieder raus).

b) Schreibe ich hingegen ins BED-Feld des Auslösers 'vehicle player != Tarnheli1' dann sind die Spieler zwar wieder im Heli, werden aber sofort nach dem rausspringen auf den Boden ge-setPos-ed.

Ich muss also eine Möglichkeit finden, dass Vienna's Code erst startet, wenn keine spielbare Einheit mehr im Tarnheli ist und zugleich einen normalen Fallschirmsprung zulässt.

Da ich den Schlepp-Respawn (ich taufe Dein Ding hiermit so, Vienna) auch in anderen Missionen verwenden möchte, würde ich dessen Start jedoch gerne in einem separaten Auslöser (mittels wahrmachen einer Variable?) initiieren.

Wie könnte ich das Problem lösen?

Vienna
11.09.2014, 23:55
Es reicht ein Auslöser mit dem Code für alle Spieler.

Die fett gedruckte Zeile wurde so abgeändert, dass die Umstellung des Spielers nur durchgeführt wird, wenn er nicht in einem fahrbaren Objekt ist.

temp = 100 spawn
{
sleep1;
if (!local player) exitwith {};
private ["_posX","_pos1","_pos2"];
_posX = [getPos player select 0,getPos player select 1];
_pos1 = _posX;
_pos2 = _posX;
while {true} do
{
waitUntil {alive player};
if (_posX distance _pos1 > _posX distance _pos2)then{_posX=_pos1}else{_posX=_pos2};
if(player == vehicle player) then {player setPos _posX};
while {alive player} do
{
waitUntil {sleep 0.5; !alive player or _pos1 distance getPos player > _this/2};
if (alive player) then
{
_pos2 = [getPos player select 0,getPos player select 1]
};
waitUntil {sleep 0.5; !alive player or _pos2 distance getPos player > _this/2};
if (alive player) then
{
_pos1 = [getPos player select 0,getPos player select 1]
}
};
_posX = [getPos player select 0,getPos player select 1]
}
};

Wolkenbeisser
12.09.2014, 10:22
Hmm, ich wollte eigentlich schon, dass der Respawnpunkt auch dann mitgezogen wird, wenn der Spieler in einem Fahr-/Flugzeug sitzt. Gleichzeitig sollten HALO-Sprünge aber trotzdem möglich bleiben.... wobei... das bringt mich auf eine neue Idee: Könnte man es evtl. auch so einrichten, dass der Spieler...

- So respawnt, wie in Vienna's letztem Post, wenn er zu Fuss unterwegs ist
- Sobald er in einem Vehicel sitzt/stirbt, aber mit 'moveInCargo' in das Vehicel zurückgesetzt wird (sofern es noch, bzw. wieder lebt, sonst zum letzten 'zuFussRespawnpunkt').

Falls das nicht geht, werde ich den Schlepprespawn so einrichten, dass er erst zündet, wenn der Spieler im Auslöserbereich ist (player in thislist). So kann ich den Auslöser nachträglich (nach dem HALO-Sprung) ins 'Spielgebiet' schieben, wodurch der Spieler erst dann in den Auslöserbereich gerät. Bis dies soweit ist verwende ich den normalen Todespunkt-Respawn.

Was haltet ihr davon?

Vienna
12.09.2014, 12:47
Hmm, ich wollte eigentlich schon, dass der Respawnpunkt auch dann mitgezogen wird, wenn der Spieler in einem Fahr-/Flugzeug sitzt. ...
Daran hat sich doch nichts geändert! Die beiden Respawn-Positionen werden unabhängig davon gespeichert, ob der Spieler "Vehicle" ist oder nicht.


Was geschieht im Code, wenn der Spieler gestorben ist?
...
1. waitUntil {alive player};
2. if (_posX distance _pos1 > _posX distance_pos2)then{_posX=_pos1}else{_posX=_pos2};
3. if(player == vehicle player) then {player setPos _posX};
...

1. In dieser Zeile wird gewartet bis der Spieler nach dem Tod wieder neu erstellt wurde (einmal ohne Warten beim Start des Codes, wenn der Spieler lebt).

2. Hier wird die weitest entfernte der beiden Respawn-Positionen zur Todes-Position gewählt (beim Start des Codes sind es die momentane Position des Spielers). Die Respawn-Position steht dann in Variabler _posX.

3. Diese Zeile stellt sicher, dass die Versetzung nur dann erfolgt, wenn der Spieler nicht in einem Fahrzeug ist. So wird z.B. verhindert, dass der Spieler beim Spielstart aus dem Heli entfernt wird!

Wolkenbeisser
12.09.2014, 14:36
Ahaaaa, ich glaube, jetzt hab' ich's verstanden. Kontrolle, ob ich's begriffen habe - Vienna will mir sagen:

Wenn der Spieler im Fahrzeug getötet wird (z.B. Kopfschuss durch die Windschutzscheibe) dann befindet er sich in dem Moment wo er wieder 'alive' wird trotzdem nicht in einem Vehicel. Somit findet die Versetzung zum Schleppspawnpunkt wie geplant statt. Er wird einfach nicht versetzt, während er in einem Vehicel sitzt.

Alles klar, werde das ausprobieren, sobald ich dazu komme. Vielen Dank schon mal für die Ergänzung, Vienna. :daumen:

Wolkenbeisser
12.09.2014, 20:45
Ok, alles klar. Vienna's Schlepp-Respawn funktioniert tadellos. :D :D :D

Nochmals herzlichen Dank!

Vienna
13.09.2014, 17:28
So tadellos wird das auf Dauer nicht klappen. z.B. wenn die beide Respawn-Positionen über Wasser liegen oder du an beiden Positionen immer gleich getötet wirst.

Hier eine bessere Lösung mit einem Skript, wo ich versucht habe dem vorzubeugen. Anweisung für die Anwendung im Skript-Kopf.

schleppRespawn.sqf Skript nur einmal aufrufen!

// 10 Respawn-Positionen im Bewegungsbereich des Spielers [Vienna 13.08.2014]
//
// Es ist zu beachten, dass sich der Spieler beim Skriptstart nicht über Wasser befindet!
//
// Aufruf: [<a>,<b>,<c>] execVM "schleppRespawn.sqf"
// <a> in Meter der Abstand bis zum Setzen der nächsten Position.
// <b> in Meter der maximale Abstand beim Respawn.
// <c> in Sekunden die Zeit, innerhalb der bei zwei Respawns eine
// Rückstellung an die Skriptstart-Position erfolgt.
//
// Beispiel für Auslöser: temp = [50,400,60] execVM "schleppRespawn.sqf";
//
// SKRIPT NUR EINMAL AUFRUFEN!

//Lokal nur für Spieler.
sleep 1;
if (!local player) exitwith {};

private ["_anzahl","_abstand","_maxAbst","_zeit","_minZeit","_i","_j","_index","_posX","_startPos","_positionen","_distanzen","_temp","_wahl"];

//Parameter
_abstand = _this select 0; //Abstand der Positionen
_maxAbst = _this select 1; //maximaler Abstand beim Respawn
_minZeit = _this select 2; //Zeitbereich innerhalb der bei 2 Toden die Rückstellung zur _startPos erfolgt

//Anzahl der Positionsspeicherungen
_anzahl = 10;
//Schleifenzähler für die Positionen
_j = 0;
//Positionen initialisieren
_startPos = [getPos player select 0,getPos player select 1]; //Position beim Skriptstart
_posX = _startPos;
_positionen = [];
for "_i" from 0 to _anzahl -1 do {_positionen =_positionen + [_startPos]};

//Endlosschleife ================================================== =============
while {true} do
{
//warten auf lebenden Spieler
waitUntil {alive player};
_zeit = Time; //Referenzzeit
//wenn Spieler nicht in Fahr-/Flugobjet, dann zur Respawn-Position versetzen.
if (player == vehicle player) then {player setPos _posX};
//falls Position im Wasser, dann zur _startPos
if (surfaceIsWater position player) then {player setPos _startPos};

//Schleife solange Spieler lebt ----------------------------------------------
while {alive player} do
{
//Respawn-Positionen in Array _positionen speichern
if (_j==0) then {_index = _anzahl-1} else {_index = _j-1};
//vorherige Position zum Vergleich
_temp = _positionen select _index;
//Vergleichsposition rückstellen wenn Abstand über _maxAbst
if (_temp distance getPos player > _maxAbst) then
{
_temp = [getPos player select 0,getPos player select 1];
_positionen set [_index,_temp]
};
//warten bis Spieler tot oder Bedingung für neue Position-Speicherung erfüllt
waitUntil {sleep 0.5; !alive player or _temp distance getPos player > _abstand};
if (alive player) then
{
_positionen set [_j,[getPos player select 0,getPos player select 1]];
_j = _j + 1;
if (_j == _anzahl) then {_j = 0}
}
};//Schleifenende nach Spielertod -------------------------------------------

//Todesposition speichern
_posX = [getPos player select 0,getPos player select 1];
//Respawn-Position festlegen
_distanzen = [];
//Distanzen der Positionen zur Todesposition speichern
{_distanzen = _distanzen + [_posX distance _x]}forEach _positionen;
//zufällige Wahl aus den Distanzen
for "_i" from 1 to _anzahl*5 do
{
_wahl = (_distanzen select (floor(random _anzahl)));
if (_wahl < _maxAbst and _wahl > _abstand) exitwith {} //wenn innerhalb des Bereichs, dann fertig.
};
//Respawn-Position aus _positionen entnehmen und in _posX speichern
{if (_posX distance _x == _wahl) exitwith {_posX = _x}} forEach _positionen;
//zwei Tode im Zeitbereich?
if (time < _zeit + _minZeit) then {_posX = _startPos}//wenn ja, dann zur _startPos
}
//Skriptende ================================================== =================

Wolkenbeisser
13.09.2014, 18:13
Nach dem neuen Script respawne ich etwa bei jedem 4 - 5 Versuch wieder an der Startposition. Wenn ich mit dem Auto aber vorher 2 Km gefahren bin, habe ich ein Problem. Bis ich meine Kameraden zu Fuss eingeholt habe, ist die Mission zu Ende.

Mit dem Auto bin ich übrigens einfach querfeldein. Auf der ganzen Strecke gab es nur Steine, Bäume Gras und diese kleinen Steinmäuerchen, die es überall gibt. Keine anderen Einheiten, kein Wasser, keine Häuser. Keine Ahnung, warum ich so oft wieder am Start stehe. Leider bin ich zu wenig gut im Scripten, als dass ich wüsste, an welchem Zahnrad man hier drehen müsste...

Ich teste mal noch ein wenig weiter (habe aber heute leider nicht mehr so viel Zeit)...

---
Nachtrag: Ich glaube, ich weiss jetzt, wieso ich immer wieder am Start stand. Ich habe natürlich nicht immer die 60 Sekunden abgewartet. Muss das bei Gelegenheit mal testen mit 5 Sekunden oder so....

Vienna
14.09.2014, 00:37
Zum Testen mit einem Fahrzeug sind die 60 Sekunden natürlich zu lange.

Die Zeit beginnt nach der Respawn-Zeit zu laufen und ist nur für einen "Notausstieg" zur Startposition gedacht. Wenn man das weiß, dann reicht generell eine 10 Sekunden Einstellung dafür.

Diese Rückstellung zum Start erfolgt auch wenn ein Respawn im Wasser erfolgen würde.

Wolkenbeisser
14.09.2014, 16:21
A und C sind mir klar. A legt eine neue Position an, wenn die Distanz zur letzten Position grösser 50m ist. C setzt mich zurück an die startposition, wenn ich innerhalb der Zeit C 2x respawne. Aber wie genau ist B zu verstehen"?

---
Nachtrag: B dürfte die maximale Distanz zwischen Respawnpunkt und Todespunkt sein. Wie auch immer: Auch dieses Script klappt wunderbar.

Merci, Vienna.