Na, ich meinte ja nicht, daß man in jedem Fall gleich alles wegwerfen und neu schreiben soll - das kann machen wer zuviel Zeit hat! Sondern eher "ausmisten" von Code, sich aber am bestehenden Code anlehnen.
Was unittests angeht - das ist in Python nicht so sehr das Problem ... allerdings bei GUIs ist das so eine Sache für sich, das gebe ich gerne zu.
Gruß
Christian
Seltsamer Fehler (Pygame)
Sehr gut. Dann zeige uns doch mal Deinen Code. Vielleicht kann man jetzt ja den Fehler eingrenzen. Achte darauf nicht wieder nur genau die Zeilen zu posten, wo der Fehler auftritt, sondern alle Zeilen, die irgendwie relevant sein können - zur Not den ganzen Code. Und sei so gut und hänge das Traceback gleich mit unten dran.
Gruß,
Christian
Gruß,
Christian
Code: Alles auswählen
def refresh(asteroiden_liste,x,y,ausrichtung,level,schaden,schuesse,strg,schuesse_liste):
schuess=keyboard_action(ausrichtung,x,y, strg,schuesse,schuesse_liste)
screen.fill(black)
screen.blit(hintergrundbild,[100,0])
screen.blit((raumschiffbilder[ausrichtung]),[x,y])
for z in range(level+1):
screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
if schuesse==1:
schuesse_liste[1]=schuesse_liste[1]-10
screen.blit(schuss,[schuesse_liste[0],schuesse_liste[1]])
if schuesse_liste[1]<0:
schuesse=0
refreshinterface(level, schaden)
pygame.display.flip()
return schuesse
#unterkategorie von refresh, aktualisiert das interface(level,schaden)
def refreshinterface(level,schaden):
interfacetext=pygame.font.Font('font.ttf',20)
leveltext=interfacetext.render('Level '+str(level),1, white)
screen.blit(leveltext,[680,565])
schadentext=interfacetext.render(str(schaden)+'% Schaden',1,white)
screen.blit(schadentext,[40,565])
#ueberprueft ob mauszeiger beim klick ueber dem button war und leitet ggf. weiter
def click(erstelltx,erstellty,breite,hoehe,umleitung,strg_angepasst,strg,musik):
mausx=pygame.mouse.get_pos()[0]
mausy=pygame.mouse.get_pos()[1]
if mausx>erstelltx and mausx<(erstelltx+breite) and mausy>erstellty and mausy<(erstellty+hoehe):
if umleitung==1:
if strg_angepasst==1:
menu_starten(strg,musik)
else:
menutext=pygame.font.Font('font.ttf',20)
fehler=menutext.render('Steuerung wurde noch nicht festgelegt.',1, red,black)
screen.blit(fehler,[100,280])
pygame.display.flip()
if umleitung==2:
menu_highscore(strg_angepasst,strg,musik)
if umleitung==3:
menu_optionen(strg_angepasst,strg,musik)
if umleitung==4:
menu_beenden()
if umleitung==5:
menu(strg_angepasst,strg,musik)
def vorwaertsrechner(ausrichtung,x,y):
if ausrichtung==0:
y=y+8
if ausrichtung==1:
y=y+6
x=x-2
if ausrichtung==2:
y=y+4
x=x-4
if ausrichtung==3:
y=y+2
x=x-6
if ausrichtung==4:
x=x-8
if ausrichtung==5:
y=y-2
x=x-6
if ausrichtung==6:
y=y-4
x=x-4
if ausrichtung==7:
y=y-6
x=x-2
if ausrichtung==8:
y=y-8
if ausrichtung==9:
y=y-6
x=x+2
if ausrichtung==10:
y=y-4
x=x+4
if ausrichtung==11:
y=y-2
x=x+6
if ausrichtung==12:
x=x+8
if ausrichtung==13:
y=y+2
x=x+6
if ausrichtung==14:
y=y+4
x=x+4
if ausrichtung==15:
y=y+6
x=x+2
return x,y
def rueckwaertsrechner(ausrichtung,x,y):
if ausrichtung==0:
y=y-8
if ausrichtung==1:
y=y-6
x=x+2
if ausrichtung==2:
y=y-4
x=x+4
if ausrichtung==3:
y=y-2
x=x+6
if ausrichtung==4:
x=x+8
if ausrichtung==5:
y=y+2
x=x+6
if ausrichtung==6:
y=y+4
x=x+4
if ausrichtung==7:
y=y+6
x=x+2
if ausrichtung==8:
y=y+8
if ausrichtung==9:
y=y+6
x=x-2
if ausrichtung==10:
y=y+4
x=x-4
if ausrichtung==11:
y=y+2
x=x-6
if ausrichtung==12:
x=x-8
if ausrichtung==13:
y=y-2
x=x-6
if ausrichtung==14:
y=y-4
x=x-4
if ausrichtung==15:
y=y-6
x=x-2
return x,y
#ueberprueft ob das raumschiff im bild ist. wenn nicht -> game over
def verschollen(x,y):
if x<-64 or x>864 or y<-64 or y>664:
gameover(True)
def keyboard_action(ausrichtung,x,y,strg,schuesse,schuesse_liste):
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key==strg[0]:
x,y=vorwaertsrechner(ausrichtung,x,y)
if event.key==strg[1]:
x,y=rueckwaertsrechner(ausrichtung,x,y)
if event.key==strg[2]:
pygame.key.set_repeat(2,2)
if ausrichtung==0:
ausrichtung=15
else:
ausrichtung=ausrichtung-1
pygame.key.set_repeat(1,1)
if event.key==strg[3]:
pygame.key.set_repeat(2,2)
if ausrichtung==15:
ausrichtung=0
else:
ausrichtung=ausrichtung+1
if event.key==strg[4]:
if schuesse==0:
schuesse=1
schuesse_liste=[x+30,y-10]
return x,y,ausrichtung,schuesse,schuesse_liste
def collision(ausrichtung,asteroiden_liste,x,y,level,asteroids_out,schuesse,schuesse_liste):
for k in range(level+1):
if asteroiden_liste[k][2]>0:
if asteroiden_liste[k][1]+asteroiden_liste[k][4]>x+24 and asteroiden_liste[k][1]<x+40:
if asteroiden_liste[k][2]+asteroiden_liste[k][4]>y+24 and asteroiden_liste[k][2]<y+40:
gameover()
if schuesse==1:
if asteroiden_liste[k][2]>0:
if schuesse_liste[0]+5>asteroiden_liste[k][1] and schuesse_liste[0]<asteroiden_liste[k][1]+asteroiden_liste[k][4]:
if schuesse_liste[1]+5>asteroiden_liste[k][2] and schuesse_liste[1]<asteroiden_liste[k][2]+asteroiden_liste[k][4]:
asteroiden_liste=asteroiden_liste[k][0],asteroiden_liste[k][1],asteroiden_liste[k][2]-2500,asteroiden_liste[k][3],asteroiden_liste[k][4]
asteroids_out=asteroids_out+1
return asteroids_out,asteroiden_liste
def gameover(verschollen_status = False):
if verschollen_status==1:
hinweis_verschollen=gameovertext.render('Im Weltall verschollen..',1, red)
screen.blit(hinweis_verschollen,[100,100])
else:
gameovertext=pygame.font.Font('font.ttf',30)
hinweis=gameovertext.render('Game Over',1, red)
screen.blit(hinweis,[100,100])
pygame.display.flip()
pygame.time.delay(1000)
menu()
def level_ablauf(ausrichtung,x,y,level,schaden,schuesse,strg,schuesse_liste):
asteroids_out=0
level=level+1
asteroiden_liste=[]
for b in range(level+1):
zahl1=randint(3,9)
zahl=zahl1*10
speed=randint(4,7)
asteroid_spawn_x=randint(0,800-zahl)
asteroid_spawn_y=0-zahl
out=0
asteroid_bild,asteroid_x,asteroid_y=pygame.image.load('bilder/asteroid'+str(zahl)+'.gif'),asteroid_spawn_x,asteroid_spawn_y
asteroid_daten=asteroid_bild,asteroid_x,asteroid_y,speed,zahl
asteroiden_liste.append(asteroid_daten)
screen.blit(asteroid_bild,[asteroid_spawn_x,asteroid_spawn_y])
while 1:
for c in range(level+1):
a=asteroiden_liste[c][3]
b=asteroiden_liste[c][2]
asteroiden_liste[c]=asteroiden_liste[c][0],asteroiden_liste[c][1],a+b,asteroiden_liste[c][3],asteroiden_liste[c][4]
if asteroiden_liste[c][2]>600:
asteroiden_liste[c]=asteroiden_liste[c][0],asteroiden_liste[c][1],asteroiden_liste[c][2]-2500,asteroiden_liste[c][3],asteroiden_liste[c][4]
asteroids_out=asteroids_out+1
if asteroids_out==level+1:
level_ablauf(ausrichtung,x,y,level,schaden,schuesse,strg,schuesse_liste)
x, y,ausrichtung,schuesse,schuesse_liste =keyboard_action(ausrichtung,x,y,strg,schuesse,schuesse_liste)
asteroids_out,asteroiden_liste=collision(ausrichtung,asteroiden_liste,x,y,level,asteroids_out,schuesse,schuesse_liste)
verschollen(x,y)
schuesse=refresh(asteroiden_liste,x,y,ausrichtung,level,schaden,schuesse,strg,schuesse_liste)
#das hauptmenue
def menu(strg_angepasst=0,strg=[],musik=0):
pygame.mouse.set_visible(1)
screen.fill(black)
screen.blit(menuhintergrund,[0,0])
screen.blit(icon_starten,[550,150])
screen.blit(icon_highscore,[550,200])
screen.blit(icon_optionen,[550,250])
screen.blit(icon_beenden,[550,300])
pygame.display.flip()
while 1:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
click(550,150,238,41,1,strg_angepasst,strg,musik)
click(550,200,239,45,2,strg_angepasst,strg,musik)
click(550,250,240,43,3,strg_angepasst,strg,musik)
click(550,300,240,45,4,strg_angepasst,strg,musik)
pygame.display.flip()
#startet das eigentliche spiel
def menu_starten(strg,musik):
if musik!=0:
track=pygame.mixer.Sound(musik)
track.play()
schiffx=368
schiffy=536
level=0
schaden=0
ausrichtung=8
pygame.key.set_repeat(1,1)
schuesse=0
schuesse_liste=[]
verschollen_status=0
level_ablauf(ausrichtung,schiffx,schiffy,level,schaden,schuesse,strg,schuesse_liste)
menu ()
TypeError: unsubscriptable object
Zuletzt geändert von rady am Dienstag 10. Mai 2005, 18:44, insgesamt 1-mal geändert.
Debugge doch einfach mal.rady hat geschrieben:screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
TypeError: unsubscriptable object
Ersetze ...
Code: Alles auswählen
screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
Code: Alles auswählen
try:
screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
except TypeError:
print "---------------------"
print z
print asteroiden_liste[z][0]
print asteroiden_liste[z][1]
print asteroiden_liste[z][2]
print "---------------------"
joe
es kommt :
0
print asteroiden_liste[z][0]
TypeError: unsubscriptable object

hab dann noch
print asteroiden_liste hinzugefügt :
0
(<Surface(40x43x8 SW)>, 369, -2204, 7, 40)
print asteroiden_liste[z][0]
TypeError: unsubscriptable object
dann dachte ich mir: eventuell kann er dieses surface ding net printen. also hab ich das print asteroiden_liste[z][0] weggelassen.
dann kam das hier
in collision
if asteroiden_liste[k][2]>0:
TypeError: unsubscriptable object
0
print asteroiden_liste[z][0]
TypeError: unsubscriptable object

hab dann noch
print asteroiden_liste hinzugefügt :
0
(<Surface(40x43x8 SW)>, 369, -2204, 7, 40)
print asteroiden_liste[z][0]
TypeError: unsubscriptable object
dann dachte ich mir: eventuell kann er dieses surface ding net printen. also hab ich das print asteroiden_liste[z][0] weggelassen.
dann kam das hier
in collision
if asteroiden_liste[k][2]>0:
TypeError: unsubscriptable object
asteroiden_liste ist gleich (<Surface(40x43x8 SW)>, 369, -2204, 7, 40)rady hat geschrieben: print asteroiden_liste hinzugefügt :
0
(<Surface(40x43x8 SW)>, 369, -2204, 7, 40)
print asteroiden_liste[z][0]
TypeError: unsubscriptable object
asteroiden_liste[0] ist damit gleich <Surface(40x43x8 SW)>
und asteroiden_liste[0][0] scheitert, da <Surface(40x43x8 SW)> nicht per index angesprochen werden kann, ist also z.b. keine liste oder kein dict.
Die folgende zeile kommt mir dabei komisch vor. Da wird aus einem 2-dimensionalen feld ein eindimensionales feld.
Code: Alles auswählen
asteroiden_liste=asteroiden_liste[k][0],asteroiden_liste[k][1],asteroiden_liste[k][2]-2500,asteroiden_liste[k][3],asteroiden_liste[k][4]
-
- Python-Forum Veteran
- Beiträge: 1209
- Registriert: Montag 29. September 2003, 17:18
- Wohnort: Purkersdorf (bei Wien [Austria])
Hi!
Naja, anscheinend ist schuesse_liste keine Liste, sondern ein Tupel, und damit immutable
Gruß, mawe
Naja, anscheinend ist schuesse_liste keine Liste, sondern ein Tupel, und damit immutable

Code: Alles auswählen
>>> l = [1,2,3]
>>> l[0] = 3 # alles ok
>>> t = (1,2,3)
>>> t[0] = 3
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object does not support item assignment
Ein paar Kritikpunkte vom ewigen Nörgler 
Man sollte die `import` Form mit dem ``*`` nicht verwenden, weil man sich damit viele Namen in das Modul holt die man gar nicht benutzt, die aber unter Umständen Probleme machen können. Also zum Beispiel anstatt alles aus dem `random` Modul zu importieren, lieber nur die Namen importieren, die man auch wirklich verwendet, oder sie über das Modul dereferenzieren.
Anstelle von `1` und `0` für Wahrheitswerte sind `True` und `False` wesentlich verständlicher.
Die Funktion `menue_optionen` ist, äh, subobtimal. Du willst nacheinander Tasten abfragen und verschachtelst für jede Taste immer tiefere Schleifen. Das sollte in *eine* Schleife gepackt werden, die nacheinander die Tastenbelegung erfragt.
Den Quelltext sollte man sowieso nicht dermassen tief einrücken. Eine Zeile sollte nach 80 Zeichen zuende sein. Und bei Python wird traditionell pro Ebene um vier Leerzeichen eingerückt. Wo wir gerade bei Leerzeichen sind: es sind zu wenig Leerzeichen, z.B. zwischen Operatoren und nach Kommata sollten welche stehen. Wenn man sich Quelltext mal ohne Syntaxhighlighting anschaut, dann wird es schnell sehr unübersichtlich wenn Namen, Gleichheitszeichen und Operatoren alle aneinander kleben.
Einige Abfragen von Wertebereichen kann man kürzer schreiben, weil man in Python auch mehr als einen Vergleich auf einmal machen kann:
Die beiden Funktionen `vorwaertsrechner()` und `rueckwaertsrechner()` lassen sich zusammenfassen und ohne die vielen ``if``s schreiben:
Ich habe noch einen `faktor` eingeführt weil Du die Funktion später zweimal aufrufst um doppelte Geschwindigkeit zu erreichen.
In `verschollen()` ist der `verschollen_status` überflüssig.
Die Funktion `collision` ist furchtbar unübersichtlich. Als erstes würde ich da über die Liste `liste` iterieren und nicht den Index `k` benutzen. Und vielleicht den Elementen der Listenelemente Namen geben, damit es nicht so undurchsichtig bleibt:
Dann brauchst Du auch das `level` nicht mehr an die Funktion übergeben. Eine Liste "weiss" ja selbst wie lang sie ist.
Ähnliches gilt für die ``for c in range(level+1)`` Schleife in `level_ablauf()`. In der Funktion ist übrigens eine Rekursion von der ich nicht glaube, dass Du die da wirklich drin haben möchtest.
In `menu_highscore` wird die Datei nicht wieder geschlossen. Und das Anzeigen der Tabelle würde ich in einer Schleife machen.
Insgesamt würde dem ganzen Spiel ein wenig Objektorientierung gut tun.

Man sollte die `import` Form mit dem ``*`` nicht verwenden, weil man sich damit viele Namen in das Modul holt die man gar nicht benutzt, die aber unter Umständen Probleme machen können. Also zum Beispiel anstatt alles aus dem `random` Modul zu importieren, lieber nur die Namen importieren, die man auch wirklich verwendet, oder sie über das Modul dereferenzieren.
Code: Alles auswählen
from random import randint
dice = randint(1, 6)
# oder
import random
dice = random.randint(1, 6)
Die Funktion `menue_optionen` ist, äh, subobtimal. Du willst nacheinander Tasten abfragen und verschachtelst für jede Taste immer tiefere Schleifen. Das sollte in *eine* Schleife gepackt werden, die nacheinander die Tastenbelegung erfragt.
Den Quelltext sollte man sowieso nicht dermassen tief einrücken. Eine Zeile sollte nach 80 Zeichen zuende sein. Und bei Python wird traditionell pro Ebene um vier Leerzeichen eingerückt. Wo wir gerade bei Leerzeichen sind: es sind zu wenig Leerzeichen, z.B. zwischen Operatoren und nach Kommata sollten welche stehen. Wenn man sich Quelltext mal ohne Syntaxhighlighting anschaut, dann wird es schnell sehr unübersichtlich wenn Namen, Gleichheitszeichen und Operatoren alle aneinander kleben.
Einige Abfragen von Wertebereichen kann man kürzer schreiben, weil man in Python auch mehr als einen Vergleich auf einmal machen kann:
Code: Alles auswählen
if x > 0 and x < 100: pass
# ==
if 0 < x < 100: pass
Code: Alles auswählen
def rechner(ausrichtung, x, y, vorwaerts=True, faktor=1):
deltas = ((0, 8), (-2, 6), (-4, 4), (-6, 2),
(-8, 0), (-6, -2), (-4, -4), (-2, -6),
(0, -8), (2, -6), (4, -4), (6, -2),
(8, 0), (6, 2), (4, 4), (2, 6))
delta_x, delta_y = deltas[ausrichtung]
delta_x *= faktor
delta_y *= faktor
if vorwaerts:
return (x + delta_x, y + delta_y)
else:
return (x - delta_x, y - delta_y)
In `verschollen()` ist der `verschollen_status` überflüssig.
Die Funktion `collision` ist furchtbar unübersichtlich. Als erstes würde ich da über die Liste `liste` iterieren und nicht den Index `k` benutzen. Und vielleicht den Elementen der Listenelemente Namen geben, damit es nicht so undurchsichtig bleibt:
Code: Alles auswählen
for (dummy, asteroid_x, asteroid_y, speed, zahl) in liste:
# ...
Ähnliches gilt für die ``for c in range(level+1)`` Schleife in `level_ablauf()`. In der Funktion ist übrigens eine Rekursion von der ich nicht glaube, dass Du die da wirklich drin haben möchtest.
In `menu_highscore` wird die Datei nicht wieder geschlossen. Und das Anzeigen der Tabelle würde ich in einer Schleife machen.
Insgesamt würde dem ganzen Spiel ein wenig Objektorientierung gut tun.
hö ? was wo ? weiss ich nichts vonweil Du die Funktion später zweimal aufrufst um doppelte Geschwindigkeit zu erreichen

Objektorientierung ? hatten wir nicht in der schule

aber danke für die tips. ein paar sachen werd ich später sicher noch einbaun.
was mich aber noch interessiert :was genau meinst du mit
das Anzeigen der Tabelle würde ich in einer Schleife machen
thx

Ups, da habe ich mich geirrt. In `keyboard_action()` rufst Du `vorwaertsrechner()` und `rueckwaertsrechner()` jeweils zweimal auf. Der jeweils erste Aufruf hat keinen Effekt, den kannst Du rausnehmen.rady hat geschrieben:hö ? was wo ? weiss ich nichts vonweil Du die Funktion später zweimal aufrufst um doppelte Geschwindigkeit zu erreichen
Ungetestet:was mich aber noch interessiert :was genau meinst du mitdas Anzeigen der Tabelle würde ich in einer Schleife machen
Code: Alles auswählen
it = iter(scores_content)
for (i, (name, score)) in enumerate(zip(it, it)):
y_pos = 210 + 40 * i
screen.blit(scores_text.render(name, 1, white), [200, y_pos])
screen.blit(scores_text.render(score, 1, white), [500, y_pos])
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ich tendiere immer ehr dazu die zweite Variante zu nehmen... Auch wenn man mehr Tippen muß, man weiß einfach besser woher die Dinge (in dem Beispiel "randint()") kommenBlackJack hat geschrieben:Man sollte die `import` Form mit dem ``*`` nicht verwenden, weil ...Code: Alles auswählen
from random import randint dice = randint(1, 6) # oder import random dice = random.randint(1, 6)
