HX3 Foren

HX3 Foren (https://hx3.de/)
-   Editing & Scripting (https://hx3.de/editing-scripting-167/)
-   -   Random Markerwahl mit abnehmender Markerzahl (https://hx3.de/editing-scripting-167/random-markerwahl-abnehmender-markerzahl-21230/)

Wolkenbeisser 26.12.2011 22:26

Random Markerwahl mit abnehmender Markerzahl
 
Hallo zusammen

Ich hoffe, der Titel ist nicht zu unklar. Ich kämpfe zurzeit mit einem "random"-problem. Vielleicht weiss jemand von euch Abhilfe. Ich versuche folgendes zu erreichen:

1. Es gibt zu Beginn 10 Marker im Spiel mit den Namen "M1" bis "M10"

2. Ein Trigger startet das Script "Zufallsaufgabe.sqf", welches ein leeres Fahrzeug mit dem Namen "Springer" per Zufallsgenerator zu einem der 10 Marker setzt.

3. Sobald der Springer bei diesem Marker steht, wird der Marker gelöscht.

4. Irgendwann später wird der Trigger erneut gezündet und damit das Script neu gestartet. Nun soll der Springer zu einem der verbleibenden 9 Marker gebeamt werden. Auch dieser Marker wird nun gelöscht.

5. Das Szenario soll sich fortsetzen können, bis der Springer beim letzen verbleibenden Marker angekommen ist. Danach sollte das Script nicht mehr ausgeführt werden.

Meine bisherige Zufallsaufgabe.sqf sieht so aus:

Code:

if (isServer) then
{_markers = ["M1", "M2", "M3", "m4", "M5", "M6", "M7", "m8", "M9", "M10"];
  Springer setpos (getMarkerPos (_markers select (floor(random(count _markers)))));}

Dabei habe ich jedoch ein Problem:

Obwohl die Marker gelöscht werden, versucht das Script den Springer (wenn's der Zufallsgenerator will) an gelöschte Marker zu beamen. Dann landet der Springer im Nirwana, bis das Script erneut abläuft und hoffentlich einen Marker trifft, der noch nich "erledigt" wurde. Das ist nicht gewünscht. Es sollen nur noch die verbleibenden Marker verwendet werden.

P.S: Ausserdem bin ich mir nicht ganz sicher, ob ich das mit der Lokalität für ein gehostetes Coop-MP-Game so richtig gelöst habe.

Weiss jemand Hilfe? Wäre für jeden Tip dankbar.

TeTeT 26.12.2011 22:44

Du definierst _markers jedes Mal bei Aufruf von ZufallsAufgabe.sqf neu. Ich würde folgendes vorschlagen:

In Init.sqf
Code:

taskMarkers = ["M1", "M2", "M3", "m4", "M5", "M6", "M7", "m8", "M9", "M10"];
In ZufallsAufgabe.sqf
Code:

_taskMarker = taskMarkers call BIS_fnc_selectRandom;
taskMarkers = taskMarkers - [ _taskMarker ];

Dadurch werden die Aufgaben (Tasks) in einem globalen Array 'taskMarkers' gehalten. Nachdem eine Aufgabe ausgewaehlt wurde, wird sie aus dem globalen Array geloescht.

Eine alternative Methode wäre z.B. das Setzen von unsichtbaren Helipads (HeliHEmpty) und der dynamischen Abfrage welche noch vorhanden sind:

Code:

_objects = nearestObjects [player, ["HeliHEmpty", "HeliH"], 10000];
_taskLocation = _objects call BIS_fnc_selectRandom;

Das findet alle 'HeliHEmpty' 10000 Meter um den Spieler herum, muss ggf auf Kartengroesse angepasst werden. Die 'HeliHEmpty' kannst du dann nach belieben loeschen oder auch verschieben, zum Beispiel fuer Folgemissionen.

Wolkenbeisser 27.12.2011 09:12

Hi TeTeT

Vielen Dank für die Hilfe. Leider habe ich bis jetzt nicht kapiert, wie mir Deine Lösung hilft. Wie bewegt sich denn der Springer in Deinem Beispiel?

Vielleicht verstehen wir uns falsch? Ich möchte nicht, dass die Spieler irgendwelche Aufgaben auswählen. Ich möchte, dass zu zehn verschiedenen Zeitpunkten in meiner Mission (per Auslöser) eines von zehn möglichen Ereignissen eintritt. Dies in zufälliger Reihenfolge und nie eines zwei Mal.

Ein Beispiel:

Die Spieler fahren in Dorf XYZ, wo sie gemäss Briefing ein Ziel zerstören müssen. Sobald das Ziel zerstört ist, muss eines der zehn möglichen Ereignisse eintreffen (für die Spieler geschieht das überraschend und ohne Warnung). Danach müssen die Spieler weiter ziehen und z.B. ein Fahrzeug von A nach B bringen. Sobald das Fahrzeug am Punkt B angekommen ist, muss das nächste Ereignis stattfinden (wieder per Auslöser ausgelöst) und zwar eines der neun verbleibenden. Danach geht die Mission weiter. Und so soll sich das hinziehen, bis alle zehn möglichen Ereignisse stattgefunden haben.

Meine Idee (weil ich es nicht besser weiss), war es, am Kartenrand das Objekt "Springer" zufällig zu einem von zehn Markern springen zu lassen. Um jeden Marker habe ich dann einen Auslöser. Sobald dieser Auslöser das vorhandensein des Springers feststellt (Springer in thislist), löst er das mit ihm verknüpfte Ereignis aus.

Noch besser wäre wahrscheinlich die zufällige Auswahl aus einem Set von 10 vorgegebenen Variablen. Wobei auch hier bei der nächsten Runde nur noch eine Zufällige der verbleibenden 9 ausgewählt werden sollte.

P.S: Bei dem ganzen Vorhaben mus natürlich sichergestellt sein, dass nur der Server die Zufälle festlegt, so dass für alle Spieler dieselbe zufällige Variable/Marker gewählt wird.

TeTeT 27.12.2011 11:06

Zitat:

Zitat von Wolkenbeisser (Beitrag 399599)
Hi TeTeT

Vielen Dank für die Hilfe. Leider habe ich bis jetzt nicht kapiert, wie mir Deine Lösung hilft. Wie bewegt sich denn der Springer in Deinem Beispiel?

Du musst den Springer mit setPos an die Stelle des Markers oder Heli-Pads stellen.

Code:

_pos = getPos _taskLocation; // oder: _pos = getMarkerPos _marker;
_springer = "UAZ" createVehicle _pos;

Wenn du ein vollbesetztes Fahrzeug brauchst, nutz einfach bis_fnc_spawnvehicle.


Zitat:

Zitat von Wolkenbeisser (Beitrag 399599)
Vielleicht verstehen wir uns falsch? Ich möchte nicht, dass die Spieler irgendwelche Aufgaben auswählen. Ich möchte, dass zu zehn verschiedenen Zeitpunkten in meiner Mission (per Auslöser) eines von zehn möglichen Ereignissen eintritt. Dies in zufälliger Reihenfolge und nie eines zwei Mal.

Ich denke, dass habe ich verstanden. Die Zufallsauswahl in deinem Skript war zwar prinzipiell in Ordnung, du musst jedoch das gezogene Ereignis auch aus dem Array löschen, damit es nicht noch mal gezogen werden kann. Deswegen habe ich vorgeschlagen, die Marker in einem globalen Array 'marker' zu verwalten und den zufällig gewählten Marker aus dem Array zu löschen.

Wegen der Server Problematik weiss ich leider auch nicht weiter, ich habe noch keine MP Mission erstellt.

Vienna 27.12.2011 11:12

Vielleicht ist es so leichter verständlich, wenn es aus deinem Beispiel abgeleitet wird:
Code:

//Initialisierung des Array Markers
  if (isNil "Markers") then {Markers = ["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10"]};
//ein Element des Arrays zufällig auswählen
  _m = Markers select (floor(random(count Markers)));
//gewähltes Element aus dem Array entfernen
  Markers = Markers - [_m];
//Springer auf die Position des gewählten Elementes setzen
  Springer setpos getMarkerPos _m;


TeTeT 27.12.2011 12:03

Das Problem ist, dass die marker Initialisierung und die Zufallsauswahl an getrennten Stellen erfolgen muss. Ansonsten wird beim Aufruf marker doch wieder neu initiliasiert. Daher mein Vorschlag in der Init.sqf das globale Array marker zu setzen und dann in einer eigenen Funktion Zufallsauswahl zu ändern.

Vienna 27.12.2011 13:48

In meinem Beispiel geht das aber auch im selben Skript. Finde das ist auch besser so, als die Initialisierung in einem anderen Skript. Wegen der globalen Variablen muss man nur auf einen einmaligen Variablen-Namen achten.

if (isNil "Markers") then {Markers = [...]};

Diese Abfrage ist ja nur beim ersten Skript-Aufruf positiv.

Wolkenbeisser 27.12.2011 14:59

Hallo Vienna und TeTeT

Wenn ich es richtig verstanden habe machen eure Lösungen in etwa dasselbe. Viennas Script ist natürlich insofern elegant, als dass es nur 1 File ist.

Noch zwei Fragen an Vienna:

1. Muss ich bei diesem Code hier...

Code:

//Initialisierung des Array Markers
  if (isNil "Markers") then {Markers = ["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10"]};
//ein Element des Arrays zufällig auswählen
  _m = Markers select (floor(random(count Markers)));
//gewähltes Element aus dem Array entfernen
  Markers = Markers - [_m];
//Springer auf die Position des gewählten Elementes setzen
  Springer setpos getMarkerPos _m;

...das "if (isServer) then {....} verwenden? Oder geht das gleich so wie von Dir gepostet?

2. Wenn der zufällig gewählte Marker aus dem Array entfernt wird, ist der Marker selbst im Spiel immer noch vorhanden, steht aber nicht mehr zur Auswahl. Habe ich das richtig begriffen? Dann könnte ich mir das Löschen der Marker nämlich sparen (sie sind eh für den Spieler unsichtbar), richtig?

Vienna 27.12.2011 16:58

Die Auswahl soll nur auf einem PC erfolgen, da der setPos Befehl publik ist. Das kann der Server oder ein anderer PC sein. Wie du das aufrufst ist dir überlassen, muss aber immer beim selben sein. Sollen es mehrere Aufrufen können, dann ist die Variable Markers mit dem Befehl publicVariable zu synchronisieren. Soll es nur der Server sein, dann am Beginn des Skripts einfügen: if(!isServer)exitWith{};

Den Marker selbst brauchst du nicht löschen. Wenn er unsichtbar ist, dann reicht es den Namen aus dem Markers Array zu entfernen.

Anstelle von leeren Markern kannst du auch Logic-Objekte nehmen. Die sind im Editor immer sichtbar, Marker nur wenn du sie anwählst. Soll an der Position ein Heli landen, dann ist auch das unsichtbare Lande-H möglich.

TeTeT 27.12.2011 17:19

Zitat:

Zitat von Vienna (Beitrag 399622)
...

if (isNil "Markers") then {Markers = [...]};

Diese Abfrage ist ja nur beim ersten Skript-Aufruf positiv.

Ah, interessant. Hatte nicht bedacht, dass ein leeres Array natürlich nicht gleich Nil ist - wäre ja fatal einfach eine leere Datenstruktur ganz zu löschen, ohne spezielle Anweisung.

Vienna 27.12.2011 17:56

Damit bei einer Variablen isNil wieder true ergibt, musst man sie mit nil "entleeren".

z.B.: Markers = nil;

"Reserviert" man eine lokale Variable mit Private, dann ergibt isNil noch immer true, solange die Variable noch keinen "Wert" erhalten hat.

Wolkenbeisser 30.12.2011 10:51

Kurzer Zwischenbericht. Mein Code sieht im Moment so aus:

Code:

If (isServer) then
{
  if (isNil "Markers") then {Markers = ["M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10"]};
  _m = Markers select (floor(random(count Markers)));
  Markers = Markers - [_m];
  Springer setpos getMarkerPos _m;
}

Das funktioniert im Editor schon mal sehr zuverlässig. Ich konnte es aber noch nicht in einem echten MP-Spiel testen.

Sollte das wider erwarten im MP nicht gehen, würde ich mich hier wahrscheinlich nochmals melden... :D.

Grüsse aus der Schweiz
Wolkenbeisser

Wolkenbeisser 13.01.2012 14:16

Wollte nur noch kurz rapportieren:

Obiger Code funzt auch im MP tadellos :daumen:

Grüsse aus der Schweiz
Wolkenbeisser


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:36 Uhr.

Angetrieben durch vBulletin, Entwicklung von Philipp Dörner & Tobias


SEO by vBSEO 3.2.0 ©2008, Crawlability, Inc.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119