When the game starts, a pipe should generate every few seconds and then delete itself while it is off the screen. Except... the pipes does not appear on the screen at all. I tried checking how many pipes there were present and the number fluctuated between 2 and 3 meaning that pipes were being generated and destroyed???? I would also appreciate any advice on how to make my code more efficient/readable.
This is my current code which doesn't work.
from tkinter import \*
from PIL import Image, ImageTk
import tkinter as tk
import random
class Bird:
BIRD_WIDTH = 75
BIRD_HEIGHT = 50
BIRD_GRAVITY = 0.2
def __init__(self, canvas, x, y):
self.canvas = canvas
self.image = Image.open("bird.png")
self.image = self.image.resize((self.BIRD_WIDTH, self.BIRD_HEIGHT),
Image.ANTIALIAS)
self.photo = ImageTk.PhotoImage(self.image)
self.bird_id = self.canvas.create_image(x,
y,
image=self.photo,
anchor="nw")
self.velocity = 0
def move(self):
bird_x, bird_y = self.canvas.coords(self.bird_id)
self.velocity += self.BIRD_GRAVITY # add gravity to velocity
bird_y += self.velocity # add velocity to y-coordinate
self.canvas.coords(self.bird_id, bird_x, bird_y)
class Pipe:
PIPE_WIDTH = 600
PIPE_HEIGHT = 1000
PIPE_SPEED = 5
def __init__(self, canvas, x, y, photo):
self.canvas = canvas
self.pipe_id = self.canvas.create_image(x,
y,
image=photo,
anchor="nw")
def move(self):
self.canvas.move(self.pipe_id, -self.PIPE_SPEED, 0)
@classmethod
def create_pipe(cls, canvas):
image = Image.open("pipes.png")
image = image.resize((cls.PIPE_WIDTH, cls.PIPE_HEIGHT), Image.ANTIALIAS)
photo = ImageTk.PhotoImage(image)
return cls(canvas, 1200, random.randint(-300, -100), photo)
class Gui:
CANVAS_WIDTH = 1200
CANVAS_HEIGHT = 5000
WINDOW_WIDTH = 1440
WINDOW_HEIGHT = 500
JUMP_HEIGHT = 5.5
PIPE_INTERVAL = 100
PIPE_COUNTER = 0
SCORE = 0
def __init__(self, start):
self.start = start
# Set up the main window
self.root = tk.Tk()
self.root.title("Flappy Bird")
self.root.geometry(f"{self.WINDOW_WIDTH}x{self.WINDOW_HEIGHT}")
# Set up the game canvas
self.canvas = tk.Canvas(self.root,
width=self.CANVAS_WIDTH,
height=self.CANVAS_HEIGHT)
self.canvas.pack()
# Create the bird and pipes
self.bird = Bird(self.canvas, 100, 200)
self.pipes = []
self.pipes.append(Pipe.create_pipe(self.canvas))
self.bind_keys()
# Schedule the game loop
self.game_loop()
self.start_game()
def bind_keys(self):
self.root.bind("<space>", self.flap_up)
def flap_up(self, event):
self.bird.velocity = -self.JUMP_HEIGHT
def check_collision(self):
pass
def game_over(self):
pass
def start_game(self):
self.root.mainloop()
def game_loop(self):
# Update the position of the bird
self.bird.move()
# Move the pipe to the left
for pipe in self.pipes:
pipe.move()
# Delete pipes that are off the screen
for pipe in self.pipes:
pipe_x = self.canvas.coords(pipe.pipe_id)[0]
if pipe_x < -pipe.PIPE_WIDTH:
self.canvas.delete(pipe.pipe_id)
self.pipes.remove(pipe)
self.SCORE += 1
self.PIPE_COUNTER += 1
if self.PIPE_COUNTER >= self.PIPE_INTERVAL:
self.PIPE_COUNTER = 0
new_pipe = Pipe.create_pipe(self.canvas)
self.pipes.append(new_pipe)
print(len(self.pipes))
# Check for collision
if self.check_collision():
self.game_over()
else:
# Schedule the next iteration of the game loop
self.canvas.after(10, self.game_loop)
gui = Gui(None)
gui.start_game()
Here is a previous iteration of my code that succeeds in generating the pipes. (but of course I need the pipes to generate every few seconds) I haven't found any notable difference that makes this code work but the latest version to not work. I also asked chatgpt but it also couldn't detect any notable difference.
from tkinter import \*
from PIL import Image, ImageTk
import tkinter as tk
import random
class Bird:
BIRD_WIDTH = 75
BIRD_HEIGHT = 50
BIRD_GRAVITY = 0.1
def __init__(self, canvas, x, y):
self.canvas = canvas
self.image = Image.open("bird.png")
self.image = self.image.resize((self.BIRD_WIDTH, self.BIRD_HEIGHT),
Image.ANTIALIAS)
self.photo = ImageTk.PhotoImage(self.image)
self.bird_id = self.canvas.create_image(x,
y,
image=self.photo,
anchor="nw")
self.velocity = 0
def move(self):
bird_x, bird_y = self.canvas.coords(self.bird_id)
self.velocity += self.BIRD_GRAVITY # add gravity to velocity
bird_y += self.velocity # add velocity to y-coordinate
self.canvas.coords(self.bird_id, bird_x, bird_y)
class Pipe:
PIPE_WIDTH = 600
PIPE_HEIGHT = 1000
def __init__(self, canvas, x, y):
self.canvas = canvas
self.image = Image.open("pipes.png")
self.image = self.image.resize((self.PIPE_WIDTH, self.PIPE_HEIGHT),
Image.ANTIALIAS)
self.photo = ImageTk.PhotoImage(self.image)
self.pipe_id = self.canvas.create_image(x,
y,
image=self.photo,
anchor="nw")
def move(self, dx, dy):
self.canvas.move(self.pipe_id, dx, dy)
class Gui:
CANVAS_WIDTH = 1200
CANVAS_HEIGHT = 5000
WINDOW_WIDTH = 1440
WINDOW_HEIGHT = 500
PIPE_SPEED = 4
JUMP_HEIGHT = 4
PIPE_INTERVAL = 300000
def __init__(self, start):
self.start = start
# Set up the main window
self.root = tk.Tk()
self.root.title("Flappy Bird")
self.root.geometry(f"{self.WINDOW_WIDTH}x{self.WINDOW_HEIGHT}")
# Set up the game canvas
self.canvas = tk.Canvas(self.root,
width=self.CANVAS_WIDTH,
height=self.CANVAS_HEIGHT)
self.canvas.pack()
# Create the bird and pipes
self.bird = Bird(self.canvas, 100, 200)
self.pipe = Pipe(self.canvas, 1200, random.randint(-300, -100))
self.bind_keys()
# Schedule the game loop
self.canvas.after(10, self.game_loop)
def bind_keys(self):
self.root.bind("<space>", self.flap_up)
def flap_up(self, event):
self.bird.velocity = -self.JUMP_HEIGHT
def generate_pipe(self):
self.pipe = Pipe(self.canvas, 1200, random.randint(-300, -100))
def game_loop(self):
# Update the position of the bird
self.bird.move()
# Move the pipe to the left
self.pipe.move(-self.PIPE_SPEED, 0)
# Delete pipe that is off the screen
pipe_x = self.canvas.coords(self.pipe.pipe_id)[0]
if pipe_x < -self.pipe.PIPE_WIDTH:
self.canvas.delete(self.pipe.pipe_id)
# Check for collision
if self.check_collision():
self.game_over()
else:
# Schedule the next iteration of the game loop
self.canvas.after(5, self.game_loop)
def check_collision(self):
pass
def start_game(self):
self.root.mainloop()
gui = Gui(None)
gui.start_game()