Ankündigung

Einklappen
Keine Ankündigung bisher.

Problem mit Script in mehreren Objekten

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge
  • gerrit92
    Empty
    • 05.11.2017
    • 31

    GE-Python Problem mit Script in mehreren Objekten

    Hey Leute,
    kleine Frage: für ein Tower Defense Game versuche ich einen Gegner mehrmals zu spawnen. Der Gegner hat dabei ein Script und ein paar Aktuatoren, nix großartiges.

    Wenn nur einer der Gegner in der Szene ist funktioniert alles ohne Probleme. Sobald ich einen zweiten spawne bekomme ich folgende Fehlermeldung:
    Python script error - object 'enemy.001', controller 'Python':
    Traceback (most recent call last):
    File "C:\Users\x\Desktop\tower defense.blend\enemy.py", line 53, in main
    File "C:\Users\x\Desktop\tower defense.blend\enemy.py", line 25, in state_normal
    ValueError: Steering not in this python controllers actuator list
    Wieso findet das Skript denn plötzlich die Aktuatoren nichtmehr? Es ändert sich ja an sich nichts am Objekt.

    Ich hab die betreffende .blend angehängt, dann könnt ihr euch selbst ein Bild davon machen. Mit der SPACE-Taste spawnt ein Gegner.

    Danke schonmal! tower defense.blend
  • tobi_blenderhilfe
    Edge
    • 04.06.2018
    • 180

    #2
    Hi, ich habs jetzt nicht gefunden auf die schnelle - aber ich arbeite auch nie mit Klassen...
    Wieso nutzt du nicht die State-Machine der BGE ?
    Schreib dir evtl. debug-Ausgaben (print) damit du den Fehler besser verfolgen kannst.
    lg, Tobi
    freie Tutorials -- Trainings-DVDs & Downloads -- 1zu1 Coaching -- Auftragsarbeiten -- blenderhilfe.de

    Kommentar

    • gerrit92
      Empty
      • 05.11.2017
      • 31

      #3
      Hey Tobi.
      ich arbeite mit Klassen, da ich denke dass ist das flexibelste und übersichtlichste wenn man mit mehreren States arbeitet. Die State machine der BGE wird irgendwann unübersichtlich.
      Debug Ausgaben hab ich schon probiert, hat leider nicht geholfen. Hab auch schon gegoogelt und alle Tipps probiert auf die ich gestoßen bin, das Problem bleibt aber dasselbe.
      meine Vermutung ist, dass das geschrieben Script nicht einfach instanzuert wird beim Spawnen sondern einzeln stehen bleibt und für alle Objekte zählt und dann versucht das „falsche“ Objekt anzusprechen.
      Wie könnte ich das umgehen?

      Kommentar

      • tobi_blenderhilfe
        Edge
        • 04.06.2018
        • 180

        #4
        keine Ahnung - vielleicht liegts an den Klassen - aber da kenn ich mich eben nicht aus - es müsste eigentlich schon funktionieren... soweit ich das lesen kann.
        er findet ja den Actuator gar nicht... keine Ahnung auf was das referenziert - aber scheinbar nicht auf deine Objekte...
        freie Tutorials -- Trainings-DVDs & Downloads -- 1zu1 Coaching -- Auftragsarbeiten -- blenderhilfe.de

        Kommentar

        • Doc Holiday
          Edge
          • 31.08.2017
          • 157

          #5
          Wann soll das auftreten? Wo muss ich da klicken?
          Ich finde Fehler am besten wenn ich versuche das Problem möglichst einfach zu reproduzieren.
          Meine Kanäle auf Vimeo und YouTube.

          Kommentar

          • tobi_blenderhilfe
            Edge
            • 04.06.2018
            • 180

            #6
            Ah hey Doc, was läuft?
            endlich einer der sich etwas besser auskennt
            wenn du SPACE drückst passiert der Fehler ab dem spawnen des 2ten Gegners.
            freie Tutorials -- Trainings-DVDs & Downloads -- 1zu1 Coaching -- Auftragsarbeiten -- blenderhilfe.de

            Kommentar

            • Doc Holiday
              Edge
              • 31.08.2017
              • 157

              #7
              Hi Tobi. Bau bloß keinen Erwartungshaltung auf. Wie kommst Du denn darauf? Ich hab doch mit Klassen auch nix am Hut. Und bislang komme ich auch noch gut ohne zurecht. Aber ich möcht natürlich trotzdem helfen.

              Ich habe, wie immer, zuerst versucht das Problem zu reproduzieren. Mit herkömmlichem Python gelang es mir nicht.

              Ich habe das Gefühl es wird irgendwas vererbt, was nicht vererbt werden soll. Bzw. Das Script biegt irgendwo falsch ab. Aber dazu kenn ich mich zu wenig mit Klassen aus. Im GameLogic Module Template findet man diesen Text:
              Code:
              # variables defined here will only be set once when the
              # module is first imported. Set object specific vars
              # inside the function if you intend to use the module
              # with multiple objects.
              Könnte das etwas damit zu tun haben?
              Meine Kanäle auf Vimeo und YouTube.

              Kommentar

              • Momel
                Empty
                • 31.08.2017
                • 280

                #8
                Zitat von Doc Holiday Beitrag anzeigen
                Könnte das etwas damit zu tun haben?
                Ja. Das Modul wird einmal am Anfang importiert und ausgeführt und die Werte bleiben dann so lange im Speicher, wie die Game Engine ausgeführt wird. Du kannst das testen, indem du einmal print("Test") in die erste Zeile schreibst und guckst, wann das ausgeführt wird. Variablen auf Modul-Ebene sind also global, das kann in der BGE ganz nützlich sein.
                Das gilt im Übrigen nicht nur für die BGE, sondern für Python ganz generell. Die BGE nutzt ja nur Python, d.h. alle Eigenschaften sind komplett identisch. Wenn man ein Python-Skript einfach nur im Interpreter ausführt, wird es bei jedem Mal neu durchlaufen, wenn man in diesem Skript jedoch ein Modul importiert (Skript=ausgeführt, Modul=importiert, ) bleiben dessen Inhalte während der Laufzeit des Skripts gleich. Deshalb sieht man oft in Skripten (vorallem außerhalb der BGE) die folgenden Zeilen:

                PHP-Code:
                if __name__ == "__main__":
                    
                # Code 

                __name__ beinhaltet den Namen des Moduls und wenn es als Skript ausgeführt wird, ist dieser Name eben automatisch __main__. Damit wird verhindert, dass Code beim Importieren ausgeführt wird. Um es nochmal anders zu formulieren: Ein Skript ist quasi immer der "Startpunkt" eines Pythonprogramms, und alle importierten Skripte sind Module. Vielleicht sprachlich nicht ganz korrekt formuliert, aber so kann man es sich merken Blender importiert deine Datei also in diesem Fall und führt dann die angegebene Methode darin aus.

                Jetzt aber zu deinem Fehler:

                Wenn jetzt hier der Variable cont ein Wert zugewiesen wird, ist dieser überall gleich. Die einzelnen Objekte rufen hier jeweils nur die main()-Methode auf. Bei Modulen ist es außerdem gefährlich, Funktionen wie getCurrentController() oder getCurrentScene() zu nutzen, meistens funktioniert das aber (zumindest nach meinen Erfahrungen, hier klappt das auch).

                Bei Skripten ist das mit den globalen Variablen etwas anderes. Die werden jeden Frame neu ausgeführt. Daher sind Module manchmal auch etwas schneller, aber sie funktionieren halt nach einem anderen Prinzip.

                Also schmeiß den ganzen Code über der Klasse raus und schreib ihn in der Klasse neu. Wie gesagt, getCurrentController() funktioniert hier auch, du kannst aber z.B. auch den Controller als Parameter in __init__() weitergeben, schließlich kennt den main() ja schon. Dort kannst du übrigens auch die Zeile cont = logic.getCurrentController() entfernen, main() hat ja cont schon als Parameter übergeben bekommen, wie du in der Zeile drüber sehen kannst.

                Wenn du dann also statt path überall self.path reinschreibst und in der __init__()-Methode diesem Attribut den Actuator zuweist (für die anderen Actuatoren natürlich auch) klappt alles

                Hier der etwas überarbeitete Code:
                PHP-Code:
                from bge import logiceventstypes


                class Enemy(types.KX_GameObject):
                    
                def __init__(selfowncont):
                        
                self.holder None

                        self
                .cont cont
                        self
                .path cont.actuators["Steering"]
                        
                self.assign cont.actuators["assign"]
                        
                self.end cont.actuators["end"]

                        
                self.main self.state_normal

                    
                #states
                    
                def state_normal(self):
                        
                self.cont.activate(self.path)

                    
                def state_gehalten(self):
                        
                self.cont.deactivate(self.path)
                        
                self.cont.activate(self.assign)

                    
                def state_kill(self):
                        
                self.cont.activate(self.end)

                    
                def kill(self):
                        
                self.main self.state_kill

                    def halten
                (selfholder):
                        
                self.holder holder
                        self
                .main self.state_gehalten

                    def get_holder
                (self):
                        return 
                self.holder


                def main
                (cont):
                    
                own cont.owner
                    
                if not "init" in own#hier alles rein was nur einmal ausgeführt werden soll
                        
                own["init"] = True
                        own 
                Enemy(owncont)

                    
                own.main() 

                Ein kleiner Tipp noch: Sei vorsichtig mit Variablen/Methoden (Methoden sind in Python auch Objekte) gleichen Namens, das kann schnell zu Fehlern führen, wenn du z.B. bei self.main() das self vergisst.

                So, das war länger als gedacht, aber hoffe es ist einigermaßen verständlich erklärt und es hilft dir
                Zuletzt geändert von Momel; 10.03.2019, 15:56.
                Aktuelles Spieleprojekt "The Myth of Excalibur"

                Kommentar

                • Doc Holiday
                  Edge
                  • 31.08.2017
                  • 157

                  #9
                  Sooo sieht eine Antwort aus von jemand der sich auskennt.
                  Danke für die ausführliche Erklärung. Ich seh zwar jetzt das es geht, aber einen richtigen Fluss verfolgen ... klappt immernoch nicht. Ich würde das aber schon gerne können. Ich muß mir da echt mal Zeit nehmen.
                  Meine Kanäle auf Vimeo und YouTube.

                  Kommentar

                  Lädt...
                  X