Seltsamer Fehler (Pygame)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

hm wie soll ich die tasten für die steuerung die im optionsmenü eingestellt werden, also die variablen, ins eigentliche spiel übergeben ? 2 funktionen sind nämlich nicht direkt mit einander verbunden !
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

so ich habs tatsächlich geschafft : alle globals sind weg

ABER

der fehler ist immernoch da :evil: :x :evil:
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

ARRGGHH

UPDATE :

alle globals weg ... ABER .... "unsubscriptable object" ... fehler ohne sinn wie beim ersten post... also was is nur los ? an den globals kanns ja net mehr liegen ....
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

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 ()


 
screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
TypeError: unsubscriptable object
Zuletzt geändert von rady am Dienstag 10. Mai 2005, 18:44, insgesamt 1-mal geändert.
joe

rady hat geschrieben:screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
TypeError: unsubscriptable object
Debugge doch einfach mal.
Ersetze ...

Code: Alles auswählen

        screen.blit(asteroiden_liste[z][0],[asteroiden_liste[z][1],asteroiden_liste[z][2]])
... durch zb ...

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 "---------------------"
... und erzähl uns, was da kommt.
joe
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

es kommt :
0
print asteroiden_liste[z][0]
TypeError: unsubscriptable object



:cry:

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
joe

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 ist gleich (<Surface(40x43x8 SW)>, 369, -2204, 7, 40)
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]
joe
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

JA !!!! DANKE !!

hab aus asteroiden_liste=....
asteroiden_liste[k]=...
gemacht
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

print schuesse_liste :
(398, 378)

-------------

schuesse_liste[0]=x+42
TypeError: object does not support item assignment


wo is das problem an schuesse_liste[0]=398+42 ?
mawe
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 ;)

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
Gruß, mawe
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

danke dir !
BlackJack

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.

Code: Alles auswählen

from random import randint
dice = randint(1, 6)
# oder
import random
dice = random.randint(1, 6)
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:

Code: Alles auswählen

if x > 0 and x < 100: pass
# ==
if 0 < x < 100: pass
Die beiden Funktionen `vorwaertsrechner()` und `rueckwaertsrechner()` lassen sich zusammenfassen und ohne die vielen ``if``s schreiben:

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)
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:

Code: Alles auswählen

for (dummy, asteroid_x, asteroid_y, speed, zahl) in liste:
    # ...
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.
rady
User
Beiträge: 20
Registriert: Dienstag 3. Mai 2005, 17:08

weil Du die Funktion später zweimal aufrufst um doppelte Geschwindigkeit zu erreichen
hö ? was wo ? weiss ich nichts von :shock:

Objektorientierung ? hatten wir nicht in der schule 8)

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 :)
BlackJack

rady hat geschrieben:
weil Du die Funktion später zweimal aufrufst um doppelte Geschwindigkeit zu erreichen
hö ? was wo ? weiss ich nichts von :shock:
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.
was mich aber noch interessiert :was genau meinst du mit
das Anzeigen der Tabelle würde ich in einer Schleife machen
Ungetestet:

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])
`scores_text` sollte besser `scores_font` heissen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

BlackJack 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)
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()") kommen ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten