Problem mit coords

Fragen zu Tkinter.
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

Hi,

da ich noch relativ neu in diesem gebiet bin verbessert mich bzw fragt weiter


Das ganze soll irgendwann einmal ein jump&run spiel werden.

In der Methode try_everything soll getestet werden ob sich der Spieler(roter Kreis) noch nach rechts bzw nach links bewegen darf, oder ob er fällt weil er keinen boden mehr unter den "füßen" hat.

Das funktioniert beim vorwärts bewegen und beim "fallen" recht gut, self.FALL und self.FORWARD haben immer den zu erwartenden wert, jedoch funktionier dies bei self.BACK nicht.

Wenn sich das Objekt dem Kreis annähert und dann irgendwann die rechte obere seite des Kreises (world.coords(self.item)[0]) den gleichen x wert hat wie die obere linke seite eines anderen objekts (world.coords(environment_list.item)[0]) und ein paar andere bedingungen erfüllt sind bedeutet das, dass der kreis sich nichtmehr in diese richtung bewegen darf.

aber alleine diese erste bedingung in z 79 (if world.coords(self.item)[0] == world.coords(environment_list[2].item)[2]: ) wird erfüllt obwohl sie den gleichen wert annehmen, wenn man mehrfach nach links drückt.


Ich nehms keinem übel wenn er das nicht versteht was ich da schreib, aber ich weiß einfach nicht wie ichs erklären soll

:cry:


Code:

Code: Alles auswählen

from Tkinter import *
from time import *


            
            
class Foreground:
    def __init__(self,x1,y1,x2,y2):
        self.x1=x1
        self.y1=y1
        self.x2=x2
        self.y2=y2

        self.BACK=True
        self.FORWARD=True
        self.FALL=False

        self.color="black"
        self.fall_counter=0
        
        self.draw_me()

    def draw_me(self):
                
        self.item = world.create_rectangle(self.x1,self.y1,self.x2,self.y2,fill="black")
        world.itemconfig(self.item, fill=self.color)
        
    def set_fill(self,color):
        self.color=color
        
        world.itemconfig(self.item, fill=self.color)


class Player(Foreground):
        
    
    def draw_me(self):
        
        
        self.item = world.create_oval(self.x1,self.y1,self.x2,self.y2,fill="black")
        world.itemconfig(self.item, fill=self.color)
    def go_forward(self,environment_list):
        self.environment_list=environment_list

        for i in range(len(self.environment_list)):
                       world.move(self.environment_list[i].item,-5,0)
                       world.update()
        self.try_everything()
        
    def go_back(self,environment_list):
        self.environment_list=environment_list

        for i in range(len(self.environment_list)):
                       world.move(self.environment_list[i].item,+5,0)
                       world.update()
        self.try_everything()
    def try_everything(self):
        x=0     
        for i in range(len(environment_list)):
            if world.coords(self.item)[3]==world.coords(environment_list[i].item)[1]:
                if world.coords(self.item)[2]>world.coords(environment_list[i].item)[0]:
                    if world.coords(self.item)[0]<world.coords(environment_list[i].item)[2]:
                        self.FALL=False
                        x=1
        if x==0:
            self.FALL=True
        x=0
        for i in range(len(environment_list)):
            if world.coords(self.item)[2]==world.coords(environment_list[i].item)[0]:
                if world.coords(self.item)[3]>=world.coords(environment_list[i].item)[1]:
                    if world.coords(self.item)[1]<=world.coords(environment_list[i].item)[3]:
                        self.FORWARD=False
                        x=1
        if x==0:
            self.FORWARD=True
        print world.coords(self.item)[0],world.coords(environment_list[2].item)[2]
        x=0
        for i in range(len(environment_list)):
            if world.coords(self.item)[0] == world.coords(environment_list[2].item)[2]:
                if world.coords(self.item)[3]>=world.coords(environment_list[i].item)[1]:
                    if world.coords(self.item)[1]<=world.coords(environment_list[i].item)[3]:
                        self.BACK=False
                        x=1
        if x==0:
            self.BACK=True
        print self.FALL,self.FORWARD,self.BACK
        
        
    def fall(self):
        pass
        
    
                
                
class Environment(Foreground):
    pass
        
def vorwaerts(event):
    Mario.go_forward(environment_list)
    
def rueckwaerts(event):
    Mario.go_back(environment_list)



    
    
window = Tk()
world = Canvas(window,bg = "white",width=1100,height=600)
world.pack()

environment_list=[]


Mario= Player(500,400,600,500)
environment_list.append(Environment(0,500,10000,600))
environment_list.append(Environment(800,300,900,400))
environment_list.append(Environment(200,400,300,500))

Mario.set_fill("red")


world.bind_all("<Right>",vorwaerts)
world.bind_all("<Left>",rueckwaerts)




window.resizable(width=0,height=0)
window.mainloop()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Vielleicht wird es für dich und andere leichter nachvollziehbar, wenn du den Code erstmal ein wenig zum Positiven hin überarbeitest. Das gilt z.B. für deine Schleifen, wo du direkt über die Elemente aus der environment_list iterieren kannst. Guckst du hier:

Code: Alles auswählen

>>> tiere = ["Hund","Katze","Affe","Ratte","Pferd"]
>>> for k in range(len(tiere)):
...     print tiere[k]
...
Hund
Katze
Affe
Ratte
Pferd
>>> for tier in tiere:
...     print tier
...
Hund
Katze
Affe
Ratte
Pferd
Du benutzt die erste Variante, die zweite ist die "richtige".

Bei der Farbgebung hast du ein überflüssiges itemconfig. Setz doch gleich die richtige Farbe, statt erst "black" und dann die Wunschfarbe (die ist zwar auch noch "black", aber das willst du vermutlich später noch ändern).

Vielleicht hat sich das Problem dann schon von selbst gelöst.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Hab' auch noch ein paar Dinge:

Die Klase "Foreground" sollte noch von "object" erben.

Die Koordinaten "x1,x2,y1,y2" würde ich als Tupel erstellen:

Code: Alles auswählen

self.coord1 = (x1, y1)
self.coord2 = (x2, y2)
Bei der Gelegenheit solltest du dier dafür auch einen richtigen Nameneinfallen lassen, zweistellige Bezeichner sind oft sehr nichtssagend.

Dann kannst du neben der bereits erwähnten Vereinfachung der for-Schleifen diese noch weiter vereinfachen:

Dies

Code: Alles auswählen

        x=0     
        for i in range(len(environment_list)):
            if world.coords(self.item)[3]==world.coords(environment_list[i].item)[1]:
                if world.coords(self.item)[2]>world.coords(environment_list[i].item)[0]:
                    if world.coords(self.item)[0]<world.coords(environment_list[i].item)[2]:
                        self.FALL=False
                        x=1
        if x==0:
            self.FALL=True
wird zu:

Code: Alles auswählen

        wc = world.coords(self.item)
        ec = world.coords(env.item)
        for env in range(environment_list):
            if wc[3]==ec[1] and wc[2]>ec[0] and wc[0]<ec[2]:
                self.FALL=False
                break
        else:
            self.FALL=True
Alternativ kannst du den else-Teil auch weglassen und vor der schleife "self.FALL" auf "True" setzen.

Dann hast du im unteren Teil noch sehr viel Code auf modulebene, packe das mal in eine main-Funktion.

Auch die Environment-Liste kannst du ganz ohne append erstellen:

Code: Alles auswählen

environment_list = [
    Environment(0,500,10000,600),
    Environment(800,300,900,400),
    Environment(200,400,300,500)
]
Schau dir doch bitte noch mal PEP8 an.

Lass die *-Importe.

Dann könntest du noch ein paar Konstanten einführen, damit im Quellcode nicht überall Zahlen durch die Gegend fliegen.

Und nicht zu vernachlässigen: es fehlen Kommentare!
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

danke schonmal für euer feedback, ich werde eure ratschläge mal in meinen code einbauen :wink:
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

So, ich habe mal den code überarbeitet aber meinen fehler nicht gefunden :(

muss irgendwo in meiner try_everything() methode liegen


Code: Alles auswählen

from Tkinter import *
from time import *


            
            
class Foreground(object):
    def __init__(self, x1, y1, x2, y2):
        self.coord1 = (x1, y1)
        self.coord2 = (x2, y2)


        self.BACK=True    #wird False, wenn die linke Seite des roten Kreises
                          #an die rechte Seite eines schwarzen Objekts stößt
                          #  FUNKTIONIERT NICHT!                             
                   
        self.FORWARD=True #wird False, wenn die rechte Seite des roten Kreises
                          #an die linke Seite eines schwarzen Objekts stößt
        
        self.FALL=False   #wird False, wenn die untere Seite des roten Kreises 
                          #auf der oberen Seite eines schwarzen Objekts liegt

        self.color="black"
        self.fall_counter=0
        
        self.draw_me()

    def draw_me(self):
        self.item = world.create_rectangle(self.coord1[0],self.coord1[1],
                                           self.coord2[0],self.coord2[1],
                                           fill="black")
        
        
    def set_fill(self, color):
        self.color=color
        world.itemconfig(self.item, fill=self.color)


class Player(Foreground):
        
    
    def draw_me(self):
        self.item = world.create_oval(self.coord1[0],self.coord1[1],
                                      self.coord2[0],self.coord2[1],
                                      fill="black")
       
        
    def go_forward(self,environment_list):
        self.environment_list = environment_list

        for i in self.environment_list:
                       world.move(i.item,-5,0)
                       world.update()
        self.try_everything()
        
    def go_back(self, environment_list):
        self.environment_list = environment_list

        for i in self.environment_list:
                       world.move(i.item,+5,0)
                       world.update()
        self.try_everything()
        
    def try_everything(self):
        pc = world.coords(self.item)
        for i in self.environment_list: 
            if pc[3] == world.coords(i.item)[1] and \
               pc[2] > world.coords(i.item)[0] and \
               pc[0] < world.coords(i.item)[2]:
                self.FALL = False
                break
        else:
            self.FALL=True
            
        for i in self.environment_list:
            if pc[2] == world.coords(i.item)[0] and \
               pc[3] > world.coords(i.item)[1] and \
               pc[1] < world.coords(i.item)[3]:
                 self.FORWARD=False
                 break
        else:
            self.FORWARD=True
            
        for i in self.environment_list:
            if pc[0] == world.coords(i.item)[2] and \
               pc[3] > world.coords(i.item)[1]and \
               pc[1] < world.coords(i.item)[3]: 
                self.BACK=False
                break
        else:
            self.BACK=True
            
        print self.FALL,self.FORWARD,self.BACK
        
        
    def fall(self):
        pass
        
    
                
                
class Environment(Foreground):
    pass
        
def vorwaerts(event):
    Mario.go_forward(environment_list)
    
def rueckwaerts(event):
    Mario.go_back(environment_list)


def main():
    global window, world, Mario, environment_list
    
    window = Tk()
    world = Canvas(window, bg = "white", width=1100, height=600)
    world.pack()

    environment_list = [
        Environment(0,500,10000,600),
        Environment(800,300,900,400),
        Environment(200,400,300,500),
        Environment(700,300,800,500)
    ]


    Mario= Player(500, 400, 600, 500)
    Mario.set_fill("red")


    world.bind_all("<Right>", vorwaerts)
    world.bind_all("<Left>", rueckwaerts)
    
    window.resizable(width=0, height=0)
    window.mainloop()

    
main()



Beim ausprobieren stellt man fest das self.BACK sich nie ändert
Zuletzt geändert von Kalkas am Dienstag 15. April 2008, 19:02, insgesamt 1-mal geändert.
BlackJack

Das wird grundsätzlich in Zeile 89 an `True` gebunden.
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

ups, ich hab break dort, vergessen

mit break funktionierts leider auch nicht :(

(ich editier ma den code oben)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Du bist einem besonderen "Feature" von Python erlegen:

Deine else-Anweisungen sollen sich auf die vorherige if-Anweisung beziehen - tun sie aber nicht. Stattdessen beziehen sie sich auf die for-Schleifen, das gibt es in Python nämlich auch (wobei man das m.E. wirklich selten sinnvoll nutzen kann). Also: Einrückungstiefe ändern und dann nochmal schauen ...
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Die Einrückung ist schon genau richtig, du musst dir nur mal den ersten Post von Kalkas anschauen.
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

Also die Schleifen habe ich auch EyDU's anweisung geändert und es passt auch, sie funktionieren wie geplant, die funktionalität ist die selbe wie davor.

die ersten beide schleifen machen genau was ich will nur die letzte nicht und ich weiß nicht warum :(

ich muss irgend einen denkfehler bei den if anweisungen gemacht haben, aber ich komme einfach nicht dahinter
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

So, ich habe jetzt mal ein wenig mit dem Code rumgespielt, jetzt läuft das Programm so, wie ich es erwarten würde:

Code: Alles auswählen

    def go_forward(self,environment_list):
        self.environment_list = environment_list 
        self.try_everything()

        if self.FORWARD:
            for i in self.environment_list: 
                           world.move(i.item,-5,0) 
                           world.update()  
        
    def go_back(self, environment_list):
        self.environment_list = environment_list
        self.try_everything()
        
        if self.BACK:
            for i in self.environment_list: 
                           world.move(i.item,+5,0) 
                           world.update()
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

und genau das funktioniert bei mir nich :/


bei der bewegung nach vorne stoppt er wie erwartet aber beim der bewegung zurück gehts bei mir nich...

meine 2 bewegungsmethoden wollte ich erst weiterschreiben wenn das mit der überprüfung überall geklappt hätte und da es bei mir beim rückwärtslaufen nicht funktioniert stoppt er auch nicht

hast du sonst noch was verändert? wie gesagt bei mir wird self.BACK niemals "False"
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hier mal mein kompletter Code:

http://paste.pocoo.org/show/40826/
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

Eben deinen code kopiert und ausgeführt und er geht nicht.

Wenn in links drücke geht der rote kreis einfach durch den schwarzen block durch, ist das bei dir anders? :>
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das funktioniert bei mir ziehmlich gut. Eben bin ich einmal durch eine Wand gehüpft als ich RIGHT dauerhaft gedrückt habe, aber normalerweise bleibe ich daran stehen. Sowohl links als auch rechts.

Hast du das Problem auch, wenn du mit einzelnen Tastenanschlägen dich der Wand näherst? Denn sonst würde ich das Problem am "==" vermuten.
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

<RIGHT> klappt bei mir wunderbar, aber <LEFT> funktioniert garnicht, egal ob kurz drücken oder gedrückt halten.

Woran kann denn sowas liegen wenns beim einen klappt und beim anderen nicht? am betriebsystem? an der python version?

edit:

gerade wo gelesen das IDLE und Tkinter sich nicht so mögen, ich werds mal anders probieren das programm zu starten (erstmal rausfinden wie :>)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Bei mir geht es sowohl über IDLE als auch die python.exe. Probier doch mal das folgende:

Code: Alles auswählen

def vorwaerts(event): 
    Mario.go_forward(environment_list) 
    
def rueckwaerts(event): 
    Mario.go_forward(environment_list) 
Dann kann man schon mal feststellen, ob es an deinem Code liegt.
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

wie erwartet geht er jetzt sowohl bei <RIGHT> als auch bei <LEFT> vorwärts, und da funktioniert ja auch das anhalten

und was sagt uns das jetzt?^^
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das es auf jeden Fall dein Fehler ist und es keine Probleme mit irgend welchen Events von der Tastatur gibt :D
Kalkas
User
Beiträge: 14
Registriert: Montag 14. April 2008, 16:01

ich habe eben deinen code kopiert und bei mir getestet also müsste es doch theoretissch bei mir auch funktionieren, das tut es aber nicht :>
Antworten