简体   繁体   中英

TypeError: unhashable type: 'list' In pyglet

So after getting inspired by code bullet to try out pyglet. Recently I have been creating many small games and simulations with it. The current one being a game is a flappy bird(Pretty sure you've all played that). So my mission is to code flappybird with pyglet today. But as usual, I fell into a problem, and even though there were many questions and answers for this problem as I was using pyglet all of the other answers weren't working. The code I have written for the flappy bird is pretty straightforward. I have 2 classes the bird and the pipe and I render all of them using batches and groups. here:

import math, sys
import pyglet, random
from pyglet.window import key, mouse

window = pyglet.window.Window(width=335, height=540, caption="FLAPPY BIRD!")

batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
pipes = pyglet.graphics.OrderedGroup(1)
foreground = pyglet.graphics.OrderedGroup(2)
player = pyglet.graphics.OrderedGroup(3)

bg = pyglet.image.load("background.png")
background_1 = pyglet.sprite.Sprite(bg, 0, 0, batch=batch, group=background)
background_2 = pyglet.sprite.Sprite(bg, bg.width, 0, batch=batch, group=background)

base = pyglet.image.load("base.png")
base_1 = pyglet.sprite.Sprite(base, 0, 0, batch=batch, group=foreground)
base_2 = pyglet.sprite.Sprite(base, base.width, 0, batch=batch, group=foreground)

bird_image = pyglet.image.load("yellowbird-midflap.png")
bird_image.anchor_x = bird_image.width // 2
bird_image.anchor_y = bird_image.height // 2

class Bird:
    def __init__(self):
        self.charector = \
            pyglet.sprite.Sprite(bird_image, window.width * 0.2, window.height/2, batch=batch, group=player)
        self.y_speed = 0
        self.rotation_vel = 0
        self.alive = True
    
    def update(self):
        self.y_speed -= 0.6
        self.rotation_vel += 1
        self.charector.y += self.y_speed
        self.charector.rotation = min(self.rotation_vel, 90)
    
    def jump(self):
        self.y_speed = 7 * 1.5
        self.rotation_vel = -35

bird_image = pyglet.image.load("yellowbird-midflap.png")

class Pipe:
    tp = pyglet.image.load("down-pipe.png")
    bp = pyglet.image.load("pipe.png")
    
    def __init__(self):
        self.top_pipe = pyglet.sprite.Sprite(self.tp, x = window.width + 100, y = random.randint(325, 484), batch=batch, group=pipes)
        self.bottom_pipe = pyglet.sprite.Sprite(self.bp, x = window.width + 100, y = self.top_pipe.y - 125 - self.bp.height, batch=batch, group=pipes)
    
    def update(self):
        self.top_pipe.x -= 3
        self.bottom_pipe.x -= 3

bird = Bird()
pipes = [Pipe()]
time_created_pipe = 50

def update_char(dt):
    global time_created_pipe,  pipes

    if bird.alive:
        bird.update()
        for pipe in pipes:
            pipe.update()
            if pipe.top_pipe.x <= -100:
                pipes.remove(pipe)
            
        if time_created_pipe <= 0:
            time_created_pipe = 50
            pipes.append(Pipe())
        time_created_pipe -= 1


def update_bg(dt):
    if bird.alive:
        background_1.x -= 0.5
        background_2.x -= 0.5
        if background_1.x <= -bg.width:
            background_1.x = bg.width
        if background_2.x <= -bg.width:
            background_2.x = bg.width
        
        base_1.x -= 1.5
        base_2.x -= 1.5
        if base_1.x <= -base.width:
            base_1.x = base.width
        if base_2.x <= -base.width:
            base_2.x = base.width

@window.event
def on_mouse_press(x, y, button, modifiers):
    if button == mouse.LEFT:
        bird.jump()

@window.event
def on_draw():
    window.clear()
    batch.draw()

pyglet.clock.schedule_interval(update_char, 1/60)
pyglet.clock.schedule_interval(update_bg, 1/60)
pyglet.app.run()

But the second I run the code this happens:

back (most recent call last):
File "c:\Users\Tejas&Shiva\OneDrive\Desktop\HTCODEATHON PYTHON PRACTICE\Day4\flappy bird.py", line 105, in <module>
    pyglet.app.run()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\app\__init__.py", line 107, in run
    event_loop.run()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\app\base.py", line 169, in run
    timeout = self.idle()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\app\base.py", line 239, in idle
    redraw_all = self.clock.call_scheduled_functions(dt)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\clock.py", line 292, in call_scheduled_functions
    item.func(now - item.last_ts, *item.args, **item.kwargs)
File "c:\Users\Tejas&Shiva\OneDrive\Desktop\HTCODEATHON PYTHON PRACTICE\Day4\flappy bird.py", line 73, in update_char
    pipes.append(Pipe())
File "c:\Users\Tejas&Shiva\OneDrive\Desktop\HTCODEATHON PYTHON PRACTICE\Day4\flappy bird.py", line 50, in __init__
    self.top_pipe = pyglet.sprite.Sprite(self.tp, x = window.width + 100, y = random.randint(325, 484), batch=batch, group=pipes)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\sprite.py", line 246, in __init__
    self._create_vertex_list()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\sprite.py", line 391, in _create_vertex_list
    self._vertex_list = self._batch.add(
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\graphics\__init__.py", line 366, in add
    domain = self._get_domain(False, mode, group, formats)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\graphics\__init__.py", line 443, in _get_domain
    self._add_group(group)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\graphics\__init__.py", line 468, in _add_group
    if group.parent not in self.group_map:
TypeError: unhashable type: 'list'

My guess is there is a problem with the pipes list but I'm not sure why. Is there any solution to this?

The problem is that the name pipes is used twice. First is used for the OrderedGroup of pipes. In this group, the initial pipe batches are added:

 pipes = pyglet.graphics.OrderedGroup(1)

However, it is then used for a list of pipes . The original group pipes is shadowed by the list of pipes and creating a new Pipe object fails:

 pipes = [Pipe()]

Use different names for the group and the list. Rename list:

pipes_list = [Pipe()]
time_created_pipe = 50

def update_char(dt):
    global time_created_pipe, pipes_list

    if bird.alive:
        bird.update()
        for pipe in pipes_list:
            pipe.update()
            if pipe.top_pipe.x <= -100:
                pipes_list.remove(pipe)
            
        if time_created_pipe <= 0:
            time_created_pipe = 50
            pipes_list.append(Pipe())
        time_created_pipe -= 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM