verdammt, ich kapier es einfach nicht

Fragen zu Tkinter.
derkai
User
Beiträge: 169
Registriert: Montag 12. Mai 2008, 11:43

Montag 7. Juli 2008, 22:19

eigentlich sollte das mal battletech werden, aber so langsam schwindet mir der Mut ....

Ich verstehe einfach nicht, was ihr mit dieser Trennung meint ?
Logik, Gui, intern, usw...

Könnt Ihr das nicht mal ein wenig plastischer Ausdrücken ?
Vor allem an Hand eines Beispiels ?

Kai
imac
20 Zoll
2,4 ghz
derkai
User
Beiträge: 169
Registriert: Montag 12. Mai 2008, 11:43

Montag 7. Juli 2008, 22:47

in der deutschen Anleitung zu Frog steht, dass man folgendes
Format zur Übergabe des pools an eine GUI verwenden soll

teich = Pool(root=frame)

Dazu muss ich ja erst ein GUI Fenster erstellen und ein Widget FRAME.

Das hatte ich folgendermaßen versucht :

Code: Alles auswählen

from Tkinter import *

fenster = Tk()
fenster.config(width=900,height=900)

test = Frame(fenster,relief=GROOVE,bd=2,padx=100,pady=100)
test.pack()

fenster.mainloop(
Leider ohne Erfolg
imac
20 Zoll
2,4 ghz
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dienstag 8. Juli 2008, 04:59

derkai hat geschrieben:Leider ohne Erfolg
Der Erfolg sollte sich einstellen, wenn du in der letzten Zeile die Klammer schließt ... :D

Oder was meinst du mit "kein Erfolg"?
BlackJack

Dienstag 8. Juli 2008, 08:14

@derkai: Mit der Trennung von GUI und Logik ist gemeint, dass die Logik ohne GUI implementiert werden sollte. Das heisst, Du musst auch ohne GUI eine Datenstruktur haben, welche die Karte und die ganzen Einheiten usw. enthält und die man nach den Regeln des Spiels manipulieren kann. Die GUI setzt man dann da drauf. Die Eingaben vom Spieler über eine GUI rufen die Methoden auf der Logik auf und bei Veränderungen fragt die GUI neue Werte ab, die dann dargestellt werden. Oft kann man dem Logikteil auch "Callback"-Funktionen geben, die bei bestimmten Ereignissen dann aufgerufen werden.

Für Dein Spiel bedeutet dass, Du bräuchtest so etwas wie eine `Map`-Klasse, die weiss wie gross sie ist, und bei der man jedes Feld durch irgendwie geartete Koordinaten eindeutig ansprechen kann, erfragen kann welches die sechs Nachbarfelder für eine gegebene Koordinate sind und so weiter. Da sind hexagonale Felder zum Beispiel etwas aufwändiger als quadratische Felder.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dienstag 8. Juli 2008, 09:15

@derkai (ergänzend zum Post von BlackJack):
Deine Vorgehensweise findet man leider häufig bei Programmieranfängern:
Man will (meistens) ein Spiel programmieren und fängt damit an, die Spieloberfläche (irgendwie) zusammenzubasteln und hält das für das Schwierigste an der Sache. Sobald die Oberfläche steht, tritt dann die große Ernüchterung ein und man stellt fest, dass es (im günstigsten Fall) zwar schick aussieht, aber es sich nicht spielen lässt.

Bei solchen (einfachen) Spielen ist das anspruchsvollste in der Regel nicht die graphische Umsetzung, sondern die Spiellogik dahinter. Dazu gehören - das hat BlackJack mit der Klasse schon angesprochen - vor allem (ggf. lange) Überlegungen zur Datenstruktur.

Empfehlung: Eine Hand voll Blätter und einen Bleistift nehmen und eine Datenstruktur entwerfen: Welche Informationen werden von welchen Elementen/Objekten/Spielfiguren etc. gebraucht und in welcher Art von Datenstruktur kann man diese speichern.
Benutzeravatar
wuf
User
Beiträge: 1497
Registriert: Sonntag 8. Juni 2003, 09:50

Dienstag 8. Juli 2008, 11:09

Hallo derkai

Das frog-Modul würde ich in den Sumpf zurückgeben. Versuche dein Projekt wie schon erwähnt wurde mit reinen Tkinter-Widget zusammen zu bauen. Da muss man sich sukzessive einarbeiten. Es gibt es sicher genügend Mitglieder in diesem Forum die dich dabei irgendwie in einer Form unterstützen werden.

Aller Anfang ist die Zeugung eines Haupfensters. Da gibt es sicher hunderte Ansichten wie dies gemacht werden sollte (muss)..

Hier ist mein Weg um dieses Hauptfenster zu erstellen:

Code: Alles auswählen

import Tkinter as tk

#~~ Konstanten die Hauptfenster-Geometrie
MAIN_WIN_XPOS   = 0     # X-Position
MAIN_WIN_YPOS   = 0     # Y-Position
MAIN_WIN_WIDTH  = 900   # Hauptfenster-Breite
MAIN_WIN_HEIGHT = 900   # Hauptfenster-Höhe

#--- Erstelle ein Tk-Hauptfenster ----
fenster = tk.Tk()

#~~ Geometrie für das Hauptfentser
fenster.geometry("%dx%d+%d+%d" % (
    MAIN_WIN_WIDTH,
    MAIN_WIN_HEIGHT,
    MAIN_WIN_XPOS,
    MAIN_WIN_YPOS)
    )

fenster.title('Mein Hauptfenster')

fenster.mainloop()
Experimentiere mit den Konstanten für die Fenster-Abmessung

Gruss wuf :wink:
Take it easy Mates!
derkai
User
Beiträge: 169
Registriert: Montag 12. Mai 2008, 11:43

Dienstag 8. Juli 2008, 22:47

ok, jetzt habe ich neuen Mut.

Ich habe nun auch einmal versucht, das Hefeld (noch nicht die gesamte Spielfläche) in Tkinter umzusetzen. Hier schon einmal mein Ergebnis :

Code: Alles auswählen

from Tkinter import *
from math import *
from random import *

master = Tk()
spiel = Canvas(master, width=1024, height=768)
spiel.pack()

laenge = 20

x1 = 20
y1 = 10
x2 = 40
y2 = 10
x3 = x2 + (laenge/2.0)
y3 = y2 + ((laenge * sqrt(3)/2))
x4 = x2
y4 = (sqrt(3) * laenge) + y2
x5 = x1
y5 = y4
x6 = x1 - (laenge / 2.0)
y6 = y3

farbe = ("black","green")

spiel.create_polygon(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6,outline="black",fill=choice(farbe))
master.mainloop()

print x1,y1
print x2,y2
print x3,y3
print x4,y4
print x5,y5
print x6,y6
Mehr, bzw mehr Zeit um dies schön zu programmieren hatte ich leider noch nicht :

ich brauche ne Mütze Schlaf

Kai
imac
20 Zoll
2,4 ghz
Benutzeravatar
wuf
User
Beiträge: 1497
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 9. Juli 2008, 07:12

Hallo derkai

Das ist doch schon ein schönes Sechseck was du da auf die Canvas-Fläche zauberst. Was ich als nächstes versuchen würde ist, dass sich das Sechseck beim ändern der variable 'länge' von deinem jetztigen Wert 20 auf einen neuen Wert z.B. 50, proportional richtig vergrössert.

Für mich ist 'choice' etwas neues. Du siehst jeder Fetzen Code in diesem Forum hinterlässt neues Wissen. :lol:

Über die Darstellung des Codes gibt es so etwas wie PEP8, da würde ich Tag für Tag einen Abschnitt durchlesen und übernehmen was für die gute Lesbarkeit des Codes zu gebrauchen ist.

OK. Gruss wuf :wink:
Zuletzt geändert von wuf am Mittwoch 9. Juli 2008, 10:02, insgesamt 1-mal geändert.
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Mittwoch 9. Juli 2008, 08:07

@derkai:

Ja, das ist gegenüber dem ersten Code ein echter Fortschritt!
Jetzt ist schonmal die erforderliche Mathematik enthalten und die Eckpunkte werden berechnet.
Zeile 13/14 sollten dann auch entsprechend geändert werden.

Nochmal zum Frosch, falls du ihn noch nicht ganz beerdigt hast:
Du kannst den Frosch auch mit Tkinter kombinieren, da die Klasse Pool nichts weiter als ein erweitertes Canvas-Widget ist, d.h. du kannst aus spiel eine Instanz von Pool statt von Canvas machen.

Unterschied ist dann allerdings ein geändertes Koordinatensystem:
Der Nullpunkt ist dann nicht linksoben, sondern stets in der Mitte (d.h. er wandert bei Größenänderungen durch den Anwender auch mit) und der y-Achsenvektor ist nach oben hin ausgerichtet, also wie das aus der Mathematik bekannte (cartesische) Koordinatensystem.

Möglicherweise ist gerade der wandernde Mittelpunkt etwas, was dir entgegenkommt, weil du ja so eine Art "wanderndes Spielfeld" brauchst, wenn ich das richtig verstanden habe.
Benutzeravatar
wuf
User
Beiträge: 1497
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 9. Juli 2008, 10:17

Hallo numerix

Deine Idee mit dem Frosch ist sicher einen Versuch wert in einem späteren Stadium, sobald ein grösserer Array von Sechsecken auf der Canvasfläche verfügbar ist. Dann werden wir den Frosch noch einmal aus dem Sumpf locken. :lol:

Eventuell kann dies auch mit einer Kombination Canvas und Ziehleisten oder der move-Methode automatisiert werden ohne den Frosch als weiteres Modul reinzuziehen. Vielleicht ist es ja auch möglich in dieser Hinsicht im Froschmodul etwas brauchbares herauszulesen.

Gruss wuf :wink:
Take it easy Mates!
derkai
User
Beiträge: 169
Registriert: Montag 12. Mai 2008, 11:43

Mittwoch 9. Juli 2008, 22:29

ich habe es dann jetzt doch endlich hinbekommen, dass ich über tkinter eine Spielfläche generieren kann.

Mit dem Ergebnis / Programmierstil bin ich aber selber total unzufrieden.
Ich möchte es halt unbedingt hinbekommen, dass die Spielfläche zeilenweise erstellt wird. Mein Code erstellt quasi zuerst Zeile 1..3..5 usw, bevor dieser dann anschließend Zeilen 2..4..6 aufbaut.

Das ist einfach ein totales durcheinander ...

Aber guckt einmal selber und vielleicht habt Ihr ja ne Idee :

Code: Alles auswählen

from Tkinter import *
from math import *
from random import *

master = Tk()
spiel = Canvas(master, width=1024, height=768)
spiel.pack()

laenge = 20

x1 = 25
y1 = 15
x2 = x1 + laenge
y2 = y1
x3 = x2 + (laenge/2.0)
y3 = y2 + ((laenge * sqrt(3)/2))
x4 = x2
y4 = (sqrt(3) * laenge) + y2
x5 = x1
y5 = y4
x6 = x1 - (laenge / 2.0)
y6 = y3


for feld in range(1,42,2):
    
    for feld in range(17):
        
        spiel.create_polygon(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6,outline="black",fill="green")
        x1 = (x3 - x2) + x3 + laenge
        x2 = x1 + laenge
        x3 = x2 + (laenge/2.0)
        x4 = x2
        x5 = x1
        x6 = x1 - (laenge / 2.0)
        
    x1 = 25
    y1 = y1 + (y4 - y2)
    x2 = x1 + laenge
    y2 = y1
    x3 = x2 + (laenge/2.0)
    y3 = y2 + ((laenge * sqrt(3)/2))
    x4 = x2
    y4 = (sqrt(3) * laenge) + y2
    x5 = x1
    y5 = y4
    x6 = x1 - (laenge / 2.0)
    y6 = y3       


x1 = 55
y1 = 27.3205080757 + 5
x2 = x1 + laenge
y2 = y1
x3 = x2 + (laenge/2.0)
y3 = y2 + ((laenge * sqrt(3)/2))
x4 = x2
y4 = (sqrt(3) * laenge) + y2
x5 = x1
y5 = y4
x6 = x1 - (laenge / 2.0)
y6 = y3

for feld in range(2,43,2):
    
    for feld in range(16):
        
        spiel.create_polygon(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6,outline="black",fill="green")
        x1 = (x3 - x2) + x3 + laenge
        x2 = x1 + laenge
        x3 = x2 + (laenge/2.0)
        x4 = x2
        x5 = x1
        x6 = x1 - (laenge / 2.0)
        
    x1 = 55
    y1 = y1 + (y4 - y2)
    x2 = x1 + laenge
    y2 = y1
    x3 = x2 + (laenge/2.0)
    y3 = y2 + ((laenge * sqrt(3)/2))
    x4 = x2
    y4 = (sqrt(3) * laenge) + y2
    x5 = x1
    y5 = y4
    x6 = x1 - (laenge / 2.0)
    y6 = y3       



Gute Nacht#

Kai








master.mainloop()

print x1,y1
print x2,y2
print x3,y3
print x4,y4
print x5,y5
print x6,y6
imac
20 Zoll
2,4 ghz
BlackJack

Donnerstag 10. Juli 2008, 06:22

Meine Ideen wären: Erstmal ein wenig sauberer Programmieren. Sternchen-Importe endlich sein lassen. Magische Konstanten entfernen. Das ganze in Funktionen kapseln und damit auch die wirklich grossen Wiederholungen im Quelltext entfernen. Auf Modulebene sollte kein Code mehr sein, ausser ``def``, ``class`` und dem Aufruf einer Hauptfunktion.
Benutzeravatar
wuf
User
Beiträge: 1497
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 10. Juli 2008, 17:04

Hallo derkai

Hoffe, dass du dich gut ausruhen konntest. BlackJack hat hier wichtige Punkte angesprochen. Um dir zu zeigen was er damit meinte habe ich einmal versucht deine Codedarstellung zu ergänzen und zu formattieren. Der Code kann evt. noch erheblich optimiert werden. Da werden die hier beteiligten Mitglieder sicher noch weitere Anregungen einfliessen lassen können. Es wird vielleicht auch langsam an der Zeit von den Funktionen auf Klassen umzustellen, da für die momentanen Versuche nur Funktionen verwendet werden. Mit Klassen meine ich die schon öffters erwähnte Trennung von GUI und Logik. Eventuell liefern hierfür auch die anderen gezielte Ansätze.

OK. Versuche einmal den folgend Code zu verstehen und damit herum zu spielen. Für aufkommende Fragen stehen dir in diesem Forum viele kompetente Mitglieder zur Seite:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Skriptname derkai_05_02 (10.07.2008)

# from Tkinter import * -> (ersetzen durch folgende Zeile)
import Tkinter as tk
# from math import *    -> (ersetzen durch folgende Zeile)
from math import sqrt
# from random import *  -> (ersetzen durch folgende Zeile)
from random import choice

def calculate_polygon_points(laenge,xorg,yorg):
    """Berechne die Eckpunkte für ein Sechseck"""

    x1 = xorg
    y1 = yorg
    x2 = x1 + laenge
    y2 = y1
    x3 = x2 + (laenge/2.0)
    y3 = y2 + ((laenge * sqrt(3)/2))
    x4 = x2
    y4 = (sqrt(3) * laenge) + y2
    x5 = x1
    y5 = y4
    x6 = x1 - (laenge / 2.0)
    y6 = y3

    #~~ Gebe die berechneten Eckpunkte in einer Liste zurück
    return [x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6]

def create_hex_polygon(spiel_feld,xpos,ypos,points,farbe):
    """Erzeugt das grafische Sechseck-Objekt"""

    x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6 = points

    x1 += xpos
    y1 += ypos
    x2 += xpos
    y2 += ypos
    x3 += xpos
    y3 += ypos
    x4 += xpos
    y4 += ypos
    x5 += xpos
    y5 += ypos
    x6 += xpos
    y6 += ypos

    return spiel_feld.create_polygon(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6,
                outline="black",fill=choice(farbe))

def calculate_xyoffset(points):
    """Berechnet die X- und Y-Versatzabstände"""

    x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6 = points

    laenge = x2 - x1
    xoffset = laenge + (x3-x2)
    yoffset = y5 - y1

    return (xoffset,yoffset)

def main():
    #~~ Erzeugt das Hauptfenster
    # master = Tk() -> (ersetzen durch folgende Zeile)
    master = tk.Tk()
    # spiel = Canvas(master, width=1024, height=768) (ersetzen durch folgende Zeile)
    spiel = tk.Canvas(master, width=1024, height=768)
    spiel.pack()

    hex_laenge = 20 # Bestimmt die Sechseckgrösse
    hex_xorg = 25
    hex_yorg = 15

    #~~ Eckpunkte für das Sechseck berechnen
    hex_point_list = calculate_polygon_points(hex_laenge,hex_xorg,hex_yorg)

    #~~ Horizontaler- & Vertikaler-Versatz die Sechseck-Platzierung berechnen
    xoffset, yoffset = calculate_xyoffset(hex_point_list)

    xpos = xorg = 10           # X Start-Koordinate
    ypos = yorg = 10           # Y Start-Koordinate
    columns = 30               # Anzahl vertikale Reihen
    rows = 10                  # Anzahl horizontale Reihen
    farbe = ("yellow","green") # Zufalls-Farben

    toggle = 0

    #~~ Platziere den zweidimensionalen Sechseck-Array
    for x in xrange(columns):
        for y in xrange(rows):
            create_hex_polygon(spiel,xpos,ypos,hex_point_list,farbe)
            ypos += yoffset

        xpos += xoffset

        if not toggle:
            toggle = 1
            ypos = yorg + yoffset/2.0
        else:
            toggle = 0
            ypos = yorg

    master.mainloop()

main()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Donnerstag 10. Juli 2008, 17:42

wuf hat geschrieben:Der Code kann evt. noch erheblich optimiert werden.
Ganz sicher :wink:

Ein Beispiel (Ersatz für die Zeilen 33-52):

Code: Alles auswählen

def create_hex_polygon(spiel_feld,xpos,ypos,points,farbe):
    """Erzeugt das grafische Sechseck-Objekt"""
    return spiel_feld.create_polygon([points[n]+n%2*ypos+(n+1)%2*xpos for n in range(len(points))],outline="black",fill=choice(farbe))
Edit: Noch besser so:

Code: Alles auswählen

def create_hex_polygon(spiel_feld,xpos,ypos,points,farbe):
    """Erzeugt das grafische Sechseck-Objekt"""
    return spiel_feld.create_polygon([value+n%2*ypos+(n+1)%2*xpos for n,value in enumerate(points)],outline="black",fill=choice(farbe))
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Donnerstag 10. Juli 2008, 18:09

Ein Sechseck per Hand zu erzeugen ist auch nicht besonders elegant.

Code: Alles auswählen

[(sin(2*pi/N*x)*length+xoffset, cos(2*pi/N*x)*length+yoffset) for x in range(N)]
Und das Verschieben ist dann auch geschenkt:

Code: Alles auswählen

map(lambda (x,y): (x+xoffset, y+yoffset), poly)
Antworten