在 Pygame 中为无尽的跑酷游戏制作障碍系统
Making an Obstacle System for an Endless Runner Game in Pygame
我正在尝试在 Python pygame
中复制 google chrome dinosaur game。我对 pygame
没有太多经验。我设法创建了所有的恐龙精灵动画(行走、跳跃和弯曲),现在我正在尝试添加障碍物。所以我想做的是当用户的分数超过 35 时,障碍物将开始随机生成。问题是,当分数超过 35 时,障碍物层层叠叠,有的不断出现又消失,看起来很糟糕,非常滞后。我怎样才能更顺利地渲染障碍物?代码的相关部分:
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()
我也做了一个video,这样你可以更好地理解问题是什么。
完整代码:
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()
感谢@qouify,问题已解决。你可以看看他的回答,看看是什么解决了问题。完整更新代码:
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()
我怀疑您的代码存在一个问题,即 pygame.display.update()
可以同时被调用:
- 通过
draw
函数的主程序;
- 以及当得分大于 35 时通过
draw_obstacles
函数启动的线程。
这可以解释为什么有些障碍物出现和消失得很快。也许,只需删除函数 draw_obstacles
中的 pygame.display.update()
就可以解决这个问题。
另一个可以解释滞后的问题与您启动线程的条件有关。在我看来,一旦分数超过 35,您将在主循环的每次迭代中启动另一个线程,这意味着 lot 个线程。因此,除非您的代码中有某些条件可以防止这种情况发生,否则您应该添加一个。
[编辑]看完你的完整代码后我注意到了一些问题。
首先,如前所述,您应该 pygame.display.update()
在你的主循环中只有 一次。 WINDOW.fill
也一样
put 在你的代码中有几个地方。这就是造成效果的原因
物体出现和消失的速度非常快。
您的程序(以及每个 pygame 程序)应该具有以下内容
结构。
while run:
process_events_and_change_objects_status()
WINDOW.fill("#FFFFFF")
redraw_everything()
pygame.display.update()
wait()
并且不应该有任何其他调用 WINDOW.fill
或
pygame.display.update()
其他任何地方。
二、看fall
方法:
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()
在这里你试图同时做两件事:更新
对象状态并使用 self.walk
重绘所有内容。那很糟
因为,例如,如果当前屏幕上有障碍物,
他们不会被绘制,因为 self.walk
不关心障碍物。此外,这意味着在恐龙坠落时无法处理事件。
所以你必须将它更改为只更新对象状态
类似的东西。
def fall(self):
if self.is_falling:
self.y += 20
if self.y != 323:
self.is_falling = False
self.is_jumping = False
然后重绘将由主循环中的self.walk
管理。相同的
对于 bend
和 jump
.
所以我认为你需要修改你的程序结构才能
在您的代码中将绘图部分与处理明确分开
部分(处理事件和更新恐龙状态)。除此以外
如果你把两者混在一起,你将面临你现在面临的那种问题
并且您的代码将无法维护和发展。
我正在尝试在 Python pygame
中复制 google chrome dinosaur game。我对 pygame
没有太多经验。我设法创建了所有的恐龙精灵动画(行走、跳跃和弯曲),现在我正在尝试添加障碍物。所以我想做的是当用户的分数超过 35 时,障碍物将开始随机生成。问题是,当分数超过 35 时,障碍物层层叠叠,有的不断出现又消失,看起来很糟糕,非常滞后。我怎样才能更顺利地渲染障碍物?代码的相关部分:
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()
我也做了一个video,这样你可以更好地理解问题是什么。
完整代码:
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()
感谢@qouify,问题已解决。你可以看看他的回答,看看是什么解决了问题。完整更新代码:
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()
我怀疑您的代码存在一个问题,即 pygame.display.update()
可以同时被调用:
- 通过
draw
函数的主程序; - 以及当得分大于 35 时通过
draw_obstacles
函数启动的线程。
这可以解释为什么有些障碍物出现和消失得很快。也许,只需删除函数 draw_obstacles
中的 pygame.display.update()
就可以解决这个问题。
另一个可以解释滞后的问题与您启动线程的条件有关。在我看来,一旦分数超过 35,您将在主循环的每次迭代中启动另一个线程,这意味着 lot 个线程。因此,除非您的代码中有某些条件可以防止这种情况发生,否则您应该添加一个。
[编辑]看完你的完整代码后我注意到了一些问题。
首先,如前所述,您应该 pygame.display.update()
在你的主循环中只有 一次。 WINDOW.fill
也一样
put 在你的代码中有几个地方。这就是造成效果的原因
物体出现和消失的速度非常快。
您的程序(以及每个 pygame 程序)应该具有以下内容 结构。
while run:
process_events_and_change_objects_status()
WINDOW.fill("#FFFFFF")
redraw_everything()
pygame.display.update()
wait()
并且不应该有任何其他调用 WINDOW.fill
或
pygame.display.update()
其他任何地方。
二、看fall
方法:
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()
在这里你试图同时做两件事:更新
对象状态并使用 self.walk
重绘所有内容。那很糟
因为,例如,如果当前屏幕上有障碍物,
他们不会被绘制,因为 self.walk
不关心障碍物。此外,这意味着在恐龙坠落时无法处理事件。
所以你必须将它更改为只更新对象状态
类似的东西。
def fall(self):
if self.is_falling:
self.y += 20
if self.y != 323:
self.is_falling = False
self.is_jumping = False
然后重绘将由主循环中的self.walk
管理。相同的
对于 bend
和 jump
.
所以我认为你需要修改你的程序结构才能 在您的代码中将绘图部分与处理明确分开 部分(处理事件和更新恐龙状态)。除此以外 如果你把两者混在一起,你将面临你现在面临的那种问题 并且您的代码将无法维护和发展。