Reputation: 164
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?
Upvotes: 1
Views: 93
Reputation: 211277
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
Upvotes: 1