Seite 1 von 4 1234 LetzteLetzte
Ergebnis 1 bis 10 von 33

Thema: Betreten eines Bereichs als Auslöser

  1. #1
    Avatar von Eddman
    Registriert seit
    07.04.2013
    Ort
    Bayern

    Terminal Betreten eines Bereichs als Auslöser

    Hallo GMOD-Community, ich habe eine Idee, weiss aber nicht wie ich diese in die Praxis umsetzen kann. Der Titel des Threads erklärt eigentlich schon was ich vorhabe. Ich möchte das eine bestimmte Aktion ausgeführt wird, wenn eine bestimmte Person einen bestimmten Bereich betritt. Ich möchte mir erstmal nur ein einfaches Beispiel machen.

    Nehmen wir mal an ich möchte das sich eine Variable "counter" jedesmal um eins erhöht wenn der Spieler einen bestimmten Bereich betritt z.B. ein Feld das vor einem Eingang liegt. Kann mir jemand hierbei behilflich sein? Ich habe momentan leider kaum eine Idee wie ich das umsetzen kann :/

    Vielleicht kann ich das Feld mit Vektoren erstellen?

    Also so in etwa, den roten Text weiss ich nicht wie ich umsetzen soll:
    Code:
    local counter = 0
    function GM:Think()
        if ply:IsPlayer() and (ply:GetPos() == Innerhalb_des_Feldes) then
             counter += 1
         end
    end
    Danke für jede Hilfe!!
    Gruß -Eddman
    Geändert von Eddman (10.04.2013 um 20:11 Uhr)

  2. #2

    Standard AW: Betreten eines Bereichs als Auslöser

    Lua Code:
    1. local counter = 0
    2. for k, v in pairs( player.GetAll() ) do
    3. 	if v == player.GetByID(<id des Players>) and v:GetPos() >= Vector( low_x, low_y, low_z ) and v:GetPos() <= Vector( high_x, high_y, high_z ) then counter = counter +1 print(counter) end
    4. end

    Hab's nicht getestet, sollte aber klappen.

  3. Folgender Benutzer sagt Danke zu RP-01 für den nützlichen Beitrag:


  4. #3
    Huge Sponsor Avatar von isch
    Registriert seit
    08.12.2009
    Ort
    Graz

    Standard AW: Betreten eines Bereichs als Auslöser

    Noch eine Kleinigkeit - du musst in einer Variable speichern wie der Status des Spielers (beim vorherigen durchgang der Funktion) war, also ob er innerhalb dieses Bereiches war oder nicht. Bei der if-Abfrage musst du dann überprüfen ob der aktuelle Status ungleich dem vorherigen ist. Da der Code bei jedem Frame ausgeführt wird würde der Wert nicht nur beim betreten sondern so lange er in dem bereich steht sehr schnell erhöht werden.

    Des weiteren ist der Code Performance-Technisch nicht gerade optimal. Du solltest einen zweiten Bereich definieren der etwas größer ist. Diese Überprüfung wird aber nur jede Sekunde ausgeführt. Die Überprüfung mittels Think() wird erst dann ausgeführt wenn sich der Spieler innerhalb dieses Bereiches befindet. Somit müssen nicht ständig sämtliche Positionen aller Spieler überprüft werden, sondern nur die, die sch zumindest in der nähe des zu überprüfenden Bereiches befinden.
    Zitat Zitat von Bier_Baron Beitrag anzeigen
    Und wer ist Garry?

  5. Folgender Benutzer sagt Danke zu isch für den nützlichen Beitrag:


  6. #4
    Avatar von Eddman
    Registriert seit
    07.04.2013
    Ort
    Bayern

    Standard AW: Betreten eines Bereichs als Auslöser

    Hi, Danke erstmal für eure Antworten. Thx für den Code, werde ich nach der Schule mal so testen.

    Noch eine Kleinigkeit - du musst in einer Variable ...
    Stimmt, danke für die Info!
    Des weiteren ist der Code Performance-Technisch nicht gerade optimal.
    I know, Ich hatte den Code sehr simpel gehalten, da es mir erstmal nur darum geht zu verstehen wie ich überhaupt vorgehen muss und ich ein schnelles Beispiel bräuchte. Danach kümmere ich mich um die Performance ;)
    Du solltest einen zweiten Bereich definieren der etwas größer ist.
    Könntest du mir bitte erklären wie du das meinst bzw. wie du es machen würdest?

    Ich denke ich würde einen Timer verwenden der jede Sekunde ausgeführt wird, aber was soll der Auslöser vom Timer sein? GM:PlayerSpawn() vielleicht?

  7. #5
    Huge Sponsor Avatar von isch
    Registriert seit
    08.12.2009
    Ort
    Graz

    Standard AW: Betreten eines Bereichs als Auslöser

    Zitat Zitat von Eddman Beitrag anzeigen
    I know, Ich hatte den Code sehr simpel gehalten, da es mir erstmal nur darum geht zu verstehen wie ich überhaupt vorgehen muss und ich ein schnelles Beispiel bräuchte. Danach kümmere ich mich um die Performance
    Quellcode gleich ordentlich zu schreiben ist meist einfacher als diesen später umstrukturieren/umschreiben zu müssen. Vor allem weil man dann wieder Sachen übersieht/vergisst.

    Zitat Zitat von Eddman Beitrag anzeigen
    Ich denke ich würde einen Timer verwenden der jede Sekunde ausgeführt wird, aber was soll der Auslöser vom Timer sein? GM:PlayerSpawn() vielleicht?
    Ich erklär es dir am besten mit einem beispiel:
    PHP-Code:
    local checkPlayers = {} // Tabelle in der Spieler eingetragen werden bei denen die Position genau überprüft werden soll

    // grobe positionsbestimmung
    timer.Create('checkPlayerPos1'10000, function() // timer der alle 1000 ms (also jede sekunde) ausgeführt wird
        
    for indexply in pairs(player.GetAll()) do // alle spieler die am server sind durchgehen
            
    local plyPos ply:GetPos() // auslesen der position des spielers
            
    if plyPos Vector(100100100) and plyPos Vector(200200200then // befindet sich er spieler in der nähe des gewünschten punktes?
                
    checkPlayers[ply:SteamID64()] = ply // spieler in die tabelle eintragen
            
    elseif checkPlayers[ply:SteamID64()] ~= nil // spieler ist in der tabelle eingetragen, befindet sicher aber nicht mehr in der nähe des gewünschten punktes
                
    table.remove(checkPlayersindex// spieler aus tabelle löschen
            
    end
        end
    end
    )

    local counter 0
    local playersInPos 
    = {}

    // genaue positionsbestimmung
    timer.Create('checkPlayerPos2'1000, function() // genauere positionsbestimmung, timer der öfter läuft, 100 ms sollten für diesen zweck ausreichen, think ist eigentlich sowieso nicht nötig da die position sicher nicht so genau bestimmt werden muss
        
    for indexply in pairs(checkPlayers) do // tabelle checkPlayers durchlaufen
            
    local plyPos ply:GetPos() // auslesen der position des spielers
            
    if plyPos Vector(125125125) and plyPos Vector(175175175) and playersInPos[ply:SteamID64()] ~= true then // befindet sich der spieler im vorgesehenen bereich?
                
    counter counter // variable um 1 inkrementieren
                
    playersInPos[ply:SteamID64()] = true // zwischenspeichern das variable bei nächstem schleifendurchlauf nicht wieder inkrementiert wird
            
    else
                
    playersInPos[ply:SteamID64()] = false // spieler befindet sich nicht (mehr) im gewünschten bereich, zwischenspeicher löschen das variable erhöht wird wenn spieler den bereich wieder betritt
            
    end
        end
    end

    Enthaltet vermutlich ein paar Fehler der Code da ich ihn nicht getestet habe.
    Geändert von isch (11.04.2013 um 16:18 Uhr)
    Zitat Zitat von Bier_Baron Beitrag anzeigen
    Und wer ist Garry?

  8. Folgender Benutzer sagt Danke zu isch für den nützlichen Beitrag:


  9. #6
    Avatar von Eddman
    Registriert seit
    07.04.2013
    Ort
    Bayern

    Standard AW: Betreten eines Bereichs als Auslöser

    Zitat Zitat von isch Beitrag anzeigen
    Quellcode gleich ordentlich zu schreiben ist meist einfacher als diesen später umstrukturieren/umschreiben zu müssen. Vor allem weil man dann wieder Sachen übersieht/vergisst.
    Das stimmt schon, aber ich will einfach nur verstehen wie das funktioniert.

    Danke für dein Beispiel , sieht von der Logik her einwandfrei aus und müsste funktionieren. Auch sehr gut und verständlich auskommentiert, vielen Dank!
    Geändert von Eddman (11.04.2013 um 20:15 Uhr)

  10. #7

    Standard AW: Betreten eines Bereichs als Auslöser

    @isch: Die Variante ist aber ziemlich schlecht, wenn man sich schnell(er) bewegt. Wenn man nun etwa schnell durch das Feld durch-noclipt, durchgespusht oder in einem Auto oder Seat durchfliegt, während man sich gerade nicht an dem Zeitpunkt befindet, in dem gechecked wird, wird der Trigger niemals ausgelöst. Gerade um die Ecken und Kanten des Feldes herum, wird das problematisch.

    Die Variante die mMn am performantesten und geeignetsten ist, wäre ein Touch-Trigger (basierend auf collision-detection).

    Dazu baust du dir zuerst ein Entity zusammen, bei welchem du per Variablen, Funktionen oder KeyValues Werte wie etwa den min- und max-Vector des Feldes setzen kannst.
    Die Daten könntest du nun dazu verwenden, ein eigenes Kollisionsmodel für das Entity zu kreieren, per Ent.PhysicsFromMesh. Dazu musst du eigentlich nur die acht benötigten Punkte für ein Quader errechnen und in die Mesh-Table einfügen. Damit man nun nicht mit dem Ding kollidiert, die Trigger aber dennoch ausgelöst werden, musst du die Funktion Ent.SetCollisionGroup auf das Entity anwenden, und zwar am besten mit der Collision-Enumeration "COLLISION_GROUP_DEBRIS".

    Um dann zu überprüfen wer oder was innerhalb des definierten Feldes steht/fliegt/whatevert, beziehungsweise was dann zu tun ist -etwa eine bestimmte Funktion für das jeweilige Entity ausführen, 'nen Counter inkrementieren oder sonst was-, musst du lediglich die Funktion(en) Ent.Touch und/oder Ent.StartTouch & Ent.EndTouch in dem Entity entsprechend ausprogrammieren.

    Gerade mit Hilfe von Ent.Start/EndTouch lässt sich der Rechenaufwand auf ein Minimum reduzieren, während kein potenzieller "Triggerer" (=Auslöser) ignoriert wird.

    Die Methode funktioniert zu 100%. Kann ich bezeugen, da ich diese in einem Gamemode selbst schonmal angewand habe.

  11. Folgender Benutzer sagt Danke zu RP-01 für den nützlichen Beitrag:


  12. #8
    Avatar von Eddman
    Registriert seit
    07.04.2013
    Ort
    Bayern

    Standard AW: Betreten eines Bereichs als Auslöser

    Hi RP-01, thx. Das werde ich mir auf jedenfall mal ansehen, aber leider hab ich noch keine Erfahrung mit Collision Detection, könntest du vielleicht mal ein einfaches Beispiel posten damit ich es verstehe? Wäre sehr nice, da ich es sehr gerne lernen würde! Vielleicht kannst du den Abschnitt aus deinem Gamemode einfach hier reinposten?

    PS: Ich habe deine Variante versucht, bekomme aber folgenden Fehler ausgegeben:
    [ERROR] gamemodes/test/gamemode/shared.lua:100: attempt to compare two userdata values
    1. unknown - gamemodes/test/gamemode/shared.lua:100


    Für <id des Players> habe ich 1 eingetragen, da dies ja der erste Spieler ist, der ja ich bin (da Einzelspieler).
    Für Vector(low_x, low_y, low_z) habe ich Vector(963, -53, -79) und für Vector(high_x, high_y, high_z) habe ich Vector(1008, 170, 9) eingetragen, das ist bei der Map gm_construct eine Fläche vor dem Eingang links gleich neben den zwei schmalen Fensteröffnungen am ersten Gebäude wo man spawnt. Ich habe deinen Code bei <shared.lua> geschrieben

    @isch deinen Code versuche ich jetzt auch gleich, mir ist aber ein Fehler bei deinem Timer aufgefallen, den delay muss man in Sekunden angeben nicht in Millisekunden Also 1 für 1 Sekunde und nicht 1000.

    EDIT: Konnte es mit meinem eigenen Code "lösen", aber leider kann ich den Timer ja nur auf 1 Sekunde minimalwert stellen, was viel zu viel ist... da der Auslöser zu spät erkannt wird. Wenn ich den Code mit GM:Think ausführe ist es kein Problem, ist aber eher die Notlösung denke ich. Ich lass mir was einfallen.

    Ich muss aber noch herausfinden wie ich in der Bedinung abfragen kann ob eine bestimmte Map geladen ist, kann mir dabei jemand noch behilflich sein? Gibt es eine Abfrage wie "IsPlayer()" aber eben "IsMap()" oder so etwas ähnliches ?

    Danke für eure Codes, teile davon werden mir noch sicherlich behilflich sein, z.B. den Teil des Codes von isch wo man anhand der SteamID prüfen kann welcher Spieler vom Auslöser betroffen werden soll.

    PS: @RP-01 Interesse an deine Lösung mit "Collision Detection" besteht natürlich weiterhin
    Geändert von Eddman (11.04.2013 um 20:22 Uhr)

  13. #9

    Standard AW: Betreten eines Bereichs als Auslöser

    Mein Code müsste wie folgt korrigiert werden:
    Lua Code:
    1. local counter = 0
    2. local v_low = Vector( low_x, low_y, low_z )
    3. local v_high = Vector( high_x, high_y, high_z )
    4.  
    5. for k, v in pairs( player.GetAll() ) do
    6. 	if v == player.GetByID(<id des Players>) and v:GetPos().x >=v_low. and v:GetPos().x >=v_low. and v:GetPos().y >=v_low.y and v:GetPos().z >=v_low.z and v:GetPos().x <= v_high.x and v:GetPos().y <= v_high.y and v:GetPos().y <= v_high.y then counter = counter +1 print(counter) end
    7. end

    Du kannst Vektoren in GMod zwar direkt vergleichen (==), nicht aber mit >, <, >= und <= vergleichen.

    Zitat Zitat von Eddman Beitrag anzeigen
    EDIT: Konnte es mit meinem eigenen Code lösen, aber leider kann ich den Timer ja nur auf 1 Sekunde minimalwert stellen, was viel zu viel ist... wenn ich den Code mit GM:Think ausführe ist es kein Problem, ist aber eher die Notlösung denke ich. Ich lass mir was einfallen. Danke für eure Codes, teile davon werden mir noch sicherlich behilflich sein, z.B. den Teil des Codes von isch wo man anhand der SteamID prüfen kann welcher Spieler vom Auslöser betroffen werden soll.
    Kommazahlen gehen selbstverständlich auch, wesshalb du als delay auch "0.001" eintragen könntest.
    Und das in GM:Think() auszuführen, ist auch kein Problem. So z.B.:
    Lua Code:
    1. local counter = 0
    2. local v_low = Vector( low_x, low_y, low_z )
    3. local v_high = Vector( high_x, high_y, high_z )
    4.  
    5. function plyInField()
    6. 	for k, v in pairs( player.GetAll() ) do
    7. 		if v == player.GetByID(<id des Players>) and v:GetPos().x >=v_low. and v:GetPos().x >=v_low. and v:GetPos().y >=v_low.y and v:GetPos().z >=v_low.z and v:GetPos().x <= v_high.x and v:GetPos().y <= v_high.y and v:GetPos().y <= v_high.y then
    8. 			counter = counter +1
    9. 		end
    10. 	end
    11. end
    12.  
    13. local oldtime = 0
    14. local delay = 0.2
    15.  
    16. function GM:Think()
    17. 	if CurTime() > oldtime +delay then
    18. 		plyInField()
    19. 		oldtime = CurTime()
    20. 	end
    21.  
    22. end


    Zitat Zitat von Eddman Beitrag anzeigen
    PS: @RP-01 Interesse an deine Lösung mit "Colision Detection" besteht natürlich weiterhin
    Das ist, wie gesagt, nicht mehr als das was ich beschrieben habe. Die StartTouch Hook-Funktion wird ausgelöst, sobald ein Objekt X theoretisch mit unserem beginnen würde zu kollidieren, während Touch so lange ausgelöst wird, wie ObjektX noch mit unserem Objekt kollidiert. EndTouch wird nur dann ausgelöst, wenn Objekt X aufgehört hat mit unserem Objekt zu kollidieren.
    Für das was du erreichen willst, brauchst du eigentlich nur StartTouch.

    Aber damit du siehst, wie das letztendlich richtig funktioniert, habe ich ein Beispiel mit normalem Helikopterbomben-Model angehangen.
    Einfach per Spawnmenü unter "Others" spawnen, selbst durchgehen oder andere Objekte reinstecken, und auf das achten, was in die Konsole geschrieben wird.
    Angehängte Dateien Angehängte Dateien

  14. Folgender Benutzer sagt Danke zu RP-01 für den nützlichen Beitrag:


  15. #10
    Avatar von Eddman
    Registriert seit
    07.04.2013
    Ort
    Bayern

    Standard AW: Betreten eines Bereichs als Auslöser

    Hi, thx. Werd mal den überarbeiteten Code probieren, ich poste nach der Schule auch mal meine Lösung die nur das nötigste zum verstehen enthält, da ja das mit der Spielerüberprüfung erstmal zum verstehen des Auslöser an sich irrelevant ist, danach aber auf jeden fall wichtig!

    Zitat Zitat von RP-01 Beitrag anzeigen
    Du kannst Vektoren in GMod zwar direkt vergleichen (==), nicht aber mit >, <, >= und <= vergleichen.
    Deswegen also..., schade das dies in keinem Wiki steht, oder hab ich was übersehn ? Über einen Umweg geht es doch, wie gesagt poste ich dann mal meine Lösung.

    Zitat Zitat von RP-01 Beitrag anzeigen
    Kommazahlen gehen selbstverständlich auch, wesshalb du als delay auch "0.001" eintragen könntest.
    Das hatte ich natürlich ausprobiert, aber ich glaube ich habe eine Fehlermeldung bekommen, ich werde es heute nochmal nach der Schule testen, thx

    Lua Code:
    1. local counter = 0
    2. local v_low = Vector( low_x, low_y, low_z )
    3. local v_high = Vector( high_x, high_y, high_z )
    4.  
    5. function plyInField()
    6. 	for k, v in pairs( player.GetAll() ) do
    7. 		if v == player.GetByID(<id des Players>) and v:GetPos().x >=v_low. and v:GetPos().x >=v_low. and v:GetPos().y >=v_low.y and v:GetPos().z >=v_low.z and v:GetPos().x <= v_high.x and v:GetPos().y <= v_high.y and v:GetPos().y <= v_high.y then
    8. 			counter = counter +1
    9. 		end
    10. 	end
    11. end
    12.  
    13. local oldtime = 0
    14. local delay = 0.2
    15.  
    16. function GM:Think()
    17. 	if CurTime() > oldtime +delay then
    18. 		plyInField()
    19. 		oldtime = CurTime()
    20. 	end
    21.  
    22. end
    So ähnlich sieht meine Lösung auch aus ^^ ich poste sie aber später trotzdem mal

    Dank you für deine Hilfe :)

Ähnliche Themen

  1. Die folgen eines nukers
    Von Master AP im Forum Bildbearbeitung
    Antworten: 3
    Letzter Beitrag: 16.08.2008, 18:24
  2. Regeln Akzeptieren beim Server betreten.
    Von computer22 im Forum Wünsche
    Antworten: 19
    Letzter Beitrag: 01.07.2008, 13:34
  3. Clanlogo auf Arm eines Combine
    Von Zulrak121 im Forum Hilfe & Support
    Antworten: 5
    Letzter Beitrag: 08.04.2008, 17:01
  4. Starten eines Listenservers
    Von Scarecrow im Forum Server
    Antworten: 30
    Letzter Beitrag: 01.07.2006, 20:46
  5. Ein Tag im Leben eines Facepunchmoderators.
    Von killuah im Forum Comics
    Antworten: 19
    Letzter Beitrag: 28.06.2006, 13:32

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •