I'm trying to make a clone of google chrome dinosaur game in Python pygame. I don't have much experience with pygame. I managed to create all of the dinosaur sprite animations (walking, jumping and bending) and now I'm trying to add the obstacles. So what I want to do is when the user's score surpasses 35, obstacles will start being randomly generated. The problem is that when the score surpasses 35, obstacles appear on top of each other, some appear and disappear constantly and it just looks bad and very laggy. How can I render the obstacles more smoothly? The relevant parts of the code: import pygame import random import os from threading import Thread pygame.init() w, h = pygame.display.get_surface().get_size() imgX = w def generate_obstacles(): global imgX obstacles_tuple = (obstacle1, obstacle2, obstacle3, obstacle4, obstacle5) chosen_obstacle = random.choice(obstacles_tuple) try: if WINDOW.get_width() >= imgX > 0: WINDOW.blit(chosen_obstacle, (imgX, 323)) else: imgX = w except pygame.error: quit() pygame.display.update() def draw(): WINDOW.fill("#FFFFFF") pygame.display.update() r1, r2 = 5000, 7000 def timer(score): global r1, r2 timer_running = True while timer_running: rand_time = random.randint(r1, r2) pygame.time.delay(rand_time) generate_obstacles() if r1 >= 500 and r2 >= 500: if score % 100 == 0: r1 -= 20 r2 -= 20 keys = pygame.key.get_pressed() if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: break game_intro(True) run = True my_sprite = Dino() speed = 5 while run: pygame.time.delay(100) bgX -= speed bgX2 -= speed imgX -= speed if bgX < floor.get_width() * -1: bgX = floor.get_width() if bgX2 < floor.get_width() * -1: bgX2 = floor.get_width() for event in pygame.event.get(): keys = pygame.key.get_pressed() if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: with open("highscore.txt", "w") as f: f.write(str(my_sprite.high_score)) run = False pygame.quit() quit() if event.type == pygame.USEREVENT+1: my_sprite.fall() if (keys[pygame.K_UP] or keys[pygame.K_SPACE]) and not my_sprite.is_jumping: my_sprite.jump() if keys[pygame.K_DOWN]: my_sprite.bend() draw() my_sprite.walk() if my_sprite.score >= 35: Thread(target=lambda: timer(my_sprite.score)).start() I also made a video so you can get a better understanding of what the problem is. Full code: import pygame import random import os from threading import Thread pygame.init() WINDOW = pygame.display.set_mode((500, 500)) pygame.display.set_caption("Dinosaur Game") walk1_image = pygame.image.load("images/walk1.png") walk1 = pygame.transform.scale(walk1_image, (64, 64)) bend1_image = pygame.image.load("images/bend1.png") bend1 = pygame.transform.scale(bend1_image, (64, 64)) bend2_image = pygame.image.load("images/bend2.png") bend2 = pygame.transform.scale(bend2_image, (64, 64)) walk2_image = pygame.image.load("images/walk2.png") walk2 = pygame.transform.scale(walk2_image, (64, 64)) die_image = pygame.image.load("images/die.png") die = pygame.transform.scale(die_image, (64, 64)) jump_image = pygame.image.load("images/jump.png") jump = pygame.transform.scale(jump_image, (64, 64)) images_list = [walk1, walk2, die, jump, bend1] floor_image = pygame.image.load("obstacles/floor-0.png").convert() floor = pygame.transform.scale(floor_image, (500, 100)) bgX = 0 bgX2 = floor.get_width() in_main = False obstacle1_image = pygame.image.load("obstacles/obstacle1.png") obstacle1 = pygame.transform.scale(obstacle1_image, (78, 78)) obstacle2_image = pygame.image.load("obstacles/obstacle2.png") obstacle2 = pygame.transform.scale(obstacle2_image, (156, 78)) obstacle3_image = pygame.image.load("obstacles/obstacle3.png") obstacle3 = pygame.transform.scale(obstacle3_image, (64, 64)) obstacle4_image = pygame.image.load("obstacles/obstacle4.png") obstacle4 = pygame.transform.scale(obstacle4_image, (128, 64)) obstacle5_image = pygame.image.load("obstacles/obstacle5.png") obstacle5 = pygame.transform.scale(obstacle5_image, (192, 64)) def game_intro(intro): while intro: WINDOW.fill("#FFFFFF") my_font = pygame.font.SysFont("comicsans", 40) label = my_font.render("Press space to play", True, (105, 105, 105)) WINDOW.blit(jump, (125, 200)) WINDOW.blit(label, (125, 300)) my_font = pygame.font.SysFont("comicsans", 20) label2 = my_font.render("Made by: Roni", True, (0, 0, 0)) WINDOW.blit(label2, (10, 480)) pygame.display.update() for event2 in pygame.event.get(): keys2 = pygame.key.get_pressed() if event2.type == pygame.QUIT or keys2[pygame.K_ESCAPE]: intro = False pygame.quit() quit() if keys2[pygame.K_SPACE]: if not os.path.isfile("highscore.txt"): f = open("highscore.txt", "w") f.write("0") f.close() intro = False return class Dino(pygame.sprite.Sprite): def __init__(self): super(Dino, self).__init__() self.images = [walk1, walk2] self.index = 0 self.image = self.images[self.index] self.x = 200 self.y = 323 self.is_falling = False self.is_jumping = False self.is_bend = False self.is_down = False self.score = 0 self.high_score = 0 def walk(self): self.update_score() WINDOW.blit(floor, (bgX, 300)) WINDOW.blit(floor, (bgX2, 300)) self.score += 1 if self.is_jumping: WINDOW.blit(jump, (self.x, self.y)) elif self.is_bend: bend_images = [bend1, bend2] keys3 = pygame.key.get_pressed() self.index += 1 if self.index >= len(self.images): self.index = 0 bend = bend_images[self.index] if keys3[pygame.K_DOWN]: WINDOW.blit(bend, (self.x, self.y)) else: self.is_bend = False self.walk() else: self.index += 1 if self.index >= len(self.images): self.index = 0 self.image = self.images[self.index] WINDOW.blit(self.image, (self.x, self.y)) pygame.display.update() def jump(self): self.is_jumping = True for i in range(3): self.y -= 20 self.walk() pygame.time.delay(10) WINDOW.fill("#FFFFFF") self.is_falling = True pygame.time.set_timer(pygame.USEREVENT+1, 1000) def fall(self): if self.is_falling: while self.y != 323: self.y += 20 self.walk() WINDOW.fill("#FFFFFF") self.is_falling = False self.is_jumping = False pygame.display.update() def bend(self): self.is_bend = True self.walk() def update_score(self): my_font = pygame.font.SysFont("comicsans", 40) zeros = 5 - len(str(self.score)) str_score = "0" * zeros + str(self.score) label = my_font.render(str_score, True, (0, 0, 0)) WINDOW.blit(label, (410, 0)) with open("highscore.txt", "r") as f: self.high_score = int(f.read()) if self.high_score <= self.score: self.high_score = self.score zeros2 = 5 - len(str(self.high_score)) str_score2 = "0" * zeros2 + str(self.high_score) label2 = my_font.render("HI: " + str_score2, True, (0, 0, 0)) WINDOW.blit(label2, (250, 0)) pygame.display.update() w, h = pygame.display.get_surface().get_size() imgX = w def generate_obstacles(): global imgX obstacles_tuple = (obstacle1, obstacle2, obstacle3, obstacle4, obstacle5) chosen_obstacle = random.choice(obstacles_tuple) try: if WINDOW.get_width() >= imgX > 0: WINDOW.blit(chosen_obstacle, (imgX, 323)) else: imgX = w except pygame.error: quit() pygame.display.update() def draw(): WINDOW.fill("#FFFFFF") pygame.display.update() r1, r2 = 5000, 7000 def timer(score): global r1, r2 timer_running = True while timer_running: rand_time = random.randint(r1, r2) pygame.time.delay(rand_time) generate_obstacles() if r1 >= 500 and r2 >= 500: if score % 100 == 0: r1 -= 20 r2 -= 20 keys = pygame.key.get_pressed() if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: break game_intro(True) run = True my_sprite = Dino() speed = 5 while run: pygame.time.delay(100) bgX -= speed bgX2 -= speed imgX -= speed if bgX < floor.get_width() * -1: bgX = floor.get_width() if bgX2 < floor.get_width() * -1: bgX2 = floor.get_width() for event in pygame.event.get(): keys = pygame.key.get_pressed() if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: with open("highscore.txt", "w") as f: f.write(str(my_sprite.high_score)) run = False pygame.quit() quit() if event.type == pygame.USEREVENT+1: my_sprite.fall() if (keys[pygame.K_UP] or keys[pygame.K_SPACE]) and not my_sprite.is_jumping: my_sprite.jump() if keys[pygame.K_DOWN]: my_sprite.bend() draw() my_sprite.walk() if my_sprite.score >= 35: Thread(target=lambda: timer(my_sprite.score)).start() The problem was solved thanks to @qouify. You can look at his answer to see what solved the problem. Full updated code: import pygame import random import os from threading import Thread pygame.init() WINDOW = pygame.display.set_mode((500, 500)) pygame.display.set_caption("Dinosaur Game") walk1_image = pygame.image.load("Dino/walk1.png") walk1 = pygame.transform.scale(walk1_image, (64, 64)) bend1_image = pygame.image.load("Dino/bend1.png") bend1 = pygame.transform.scale(bend1_image, (64, 64)) bend2_image = pygame.image.load("Dino/bend2.png") bend2 = pygame.transform.scale(bend2_image, (64, 64)) walk2_image = pygame.image.load("Dino/walk2.png") walk2 = pygame.transform.scale(walk2_image, (64, 64)) die_image = pygame.image.load("Dino/die.png") die = pygame.transform.scale(die_image, (64, 64)) jump_image = pygame.image.load("Dino/jump.png") jump = pygame.transform.scale(jump_image, (64, 64)) images_list = [walk1, walk2, die, jump, bend1] floor_image = pygame.image.load("Others/floor-0.png").convert() floor = pygame.transform.scale(floor_image, (500, 100)) bgX = 0 bgX2 = floor.get_width() in_main = False obstacle1_image = pygame.image.load("Obstacles/obstacle1.png") obstacle1 = pygame.transform.scale(obstacle1_image, (78, 78)) obstacle2_image = pygame.image.load("Obstacles/obstacle2.png") obstacle2 = pygame.transform.scale(obstacle2_image, (156, 78)) obstacle3_image = pygame.image.load("Obstacles/obstacle3.png") obstacle3 = pygame.transform.scale(obstacle3_image, (64, 64)) obstacle4_image = pygame.image.load("Obstacles/obstacle4.png") obstacle4 = pygame.transform.scale(obstacle4_image, (128, 64)) obstacle5_image = pygame.image.load("Obstacles/obstacle5.png") obstacle5 = pygame.transform.scale(obstacle5_image, (192, 64)) def game_intro(intro): while intro: WINDOW.fill("#FFFFFF") my_font = pygame.font.SysFont("comicsans", 40) label = my_font.render("Press space to play", True, (105, 105, 105)) WINDOW.blit(jump, (125, 200)) WINDOW.blit(label, (125, 300)) my_font = pygame.font.SysFont("comicsans", 20) label2 = my_font.render("Made by: Roni Meirom", True, (0, 0, 0)) WINDOW.blit(label2, (10, 480)) pygame.display.update() for event2 in pygame.event.get(): keys2 = pygame.key.get_pressed() if event2.type == pygame.QUIT or keys2[pygame.K_ESCAPE]: intro = False pygame.quit() quit() if keys2[pygame.K_SPACE]: if not os.path.isfile("highscore.txt"): f = open("highscore.txt", "w") f.write("0") f.close() intro = False return class Dino(pygame.sprite.Sprite): def __init__(self): super(Dino, self).__init__() self.images = [walk1, walk2] self.index = 0 self.image = self.images[self.index] self.x = 200 self.y = 323 self.is_falling = False self.is_jumping = False self.is_bend = False self.is_down = False self.score = 0 self.high_score = 0 def walk(self): self.update_score() WINDOW.blit(floor, (bgX, 300)) WINDOW.blit(floor, (bgX2, 300)) self.score += 1 if self.is_jumping: WINDOW.blit(jump, (self.x, self.y)) elif self.is_bend: bend_images = [bend1, bend2] keys3 = pygame.key.get_pressed() self.index += 1 if self.index >= len(self.images): self.index = 0 bend = bend_images[self.index] if keys3[pygame.K_DOWN]: WINDOW.blit(bend, (self.x, self.y)) else: self.is_bend = False self.walk() else: self.index += 1 if self.index >= len(self.images): self.index = 0 self.image = self.images[self.index] WINDOW.blit(self.image, (self.x, self.y)) def jump(self): self.is_jumping = True for i in range(3): self.y -= 20 self.walk() pygame.time.delay(10) WINDOW.fill("#FFFFFF") self.is_falling = True pygame.time.set_timer(pygame.USEREVENT+1, 1000) def fall(self): if self.is_falling: self.y += 20 if self.y != 323: self.y = 323 self.is_falling = False self.is_jumping = False def bend(self): self.is_bend = True self.walk() def update_score(self): my_font = pygame.font.SysFont("comicsans", 40) zeros = 5 - len(str(self.score)) str_score = "0" * zeros + str(self.score) label = my_font.render(str_score, True, (0, 0, 0)) WINDOW.blit(label, (410, 0)) with open("highscore.txt", "r") as f: self.high_score = int(f.read()) if self.high_score <= self.score: self.high_score = self.score zeros2 = 5 - len(str(self.high_score)) str_score2 = "0" * zeros2 + str(self.high_score) label2 = my_font.render("HI: " + str_score2, True, (0, 0, 0)) WINDOW.blit(label2, (250, 0)) w, h = pygame.display.get_surface().get_size() imgX = w def generate_obstacles(): global imgX obstacles_tuple = (obstacle1, obstacle2, obstacle3, obstacle4, obstacle5) chosen_obstacle = random.choice(obstacles_tuple) try: if WINDOW.get_width() >= imgX > 0: WINDOW.blit(chosen_obstacle, (imgX, 323)) else: imgX = w except pygame.error: quit() r1, r2 = 5000, 7000 def timer(score): global r1, r2 timer_running = True while timer_running: rand_time = random.randint(r1, r2) pygame.time.delay(rand_time) generate_obstacles() if r1 >= 500 and r2 >= 500: if score % 100 == 0: r1 -= 20 r2 -= 20 keys = pygame.key.get_pressed() if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: break game_intro(True) run = True my_sprite = Dino() speed = 5 while run: bgX -= speed bgX2 -= speed imgX -= speed if bgX < floor.get_width() * -1: bgX = floor.get_width() if bgX2 < floor.get_width() * -1: bgX2 = floor.get_width() for event in pygame.event.get(): keys = pygame.key.get_pressed() if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: with open("highscore.txt", "w") as f: f.write(str(my_sprite.high_score)) run = False pygame.quit() quit() if event.type == pygame.USEREVENT+1: my_sprite.fall() if (keys[pygame.K_UP] or keys[pygame.K_SPACE]) and not my_sprite.is_jumping: my_sprite.jump() if keys[pygame.K_DOWN]: my_sprite.bend() WINDOW.fill("#FFFFFF") my_sprite.walk() if my_sprite.score >= 35: Thread(target=lambda: timer(my_sprite.score)).start() pygame.time.delay(100) pygame.display.update() Continue reading...