Как с помощью библиотеки pygame сделать так, чтобы скорость игры не зависела от частоты обновления кадров?
Я пишу свою первую игру с помощью библиотеки pygame, ниже представлен её код
import os
import sys
import pygame
# Инициализация Pygame
pygame.init()
# Определение размеров экрана пользователя
screen_info = pygame.display.Info()
window_width = screen_info.current_w
window_height = screen_info.current_h
# Создание окна с полноэкранным режимом и адаптацией под размеры экрана
window = pygame.display.set_mode((window_width, window_height), pygame.FULLSCREEN)
pygame.display.set_caption("game")
# Загрузка изображений
obstacle_image = pygame.image.load("obstacle.png")
background1_image = pygame.image.load("map2.png")
background1_image = pygame.transform.scale(background1_image, (window_width, window_height))
background2_image = background1_image
# Загрузка изображений для анимации бега
run_images = []
for i in range(9):
image_path = os.path.join("man3", f"man{i}.png")
image = pygame.image.load(image_path)
run_images.append(image)
# Текущий индекс кадра анимации
current_frame = 0
# Скорость смены кадров анимации бега
animation_speed = 3
# Создание маски таракана
obstacle_mask = pygame.mask.from_surface(obstacle_image)
# Создание массива с масками каждого кадра анимации бега
player_masks = []
for player_image in run_images:
mask = pygame.mask.from_surface(player_image)
player_masks.append(mask)
# Получение размеров изображений
obstacle_width = obstacle_image.get_width()
obstacle_height = obstacle_image.get_height()
background1_width = background1_image.get_width()
background1_height = background1_image.get_height()
# Счёт очков
counter = 0
score1 = 0
score2 = 1
# Путь к файлу с рекордом
record_file_path = "record.txt"
# Загрузка текущего рекорда
if os.path.exists(record_file_path):
with open(record_file_path, "r") as file:
record = int(file.read())
else:
record = 0
# Определение начальных координат игрока
player_x = window_width * 0.1
player_y = window_height * 0.45
# Определение начальных координат таракана
obstacle_x = window_width
obstacle_y = window_height * 0.67
# Определение начальных координат фона
background1_x = 0
background1_y = 0
background2_x = background1_width
background2_y = 0
# Определение начальных координат номера двери
number1_x = background1_width * 0.888
number1_y = background1_height * 0.435
number2_x = background1_width * 0.888 + background1_width
number2_y = background1_height * 0.435
# Определение скорости таракана и фона
obstacle_speed = 9
background_speed = 7
# Определение состояния прыжка игрока
is_jumping = False
jump_count = 30
clock = pygame.time.Clock()
# Скорость игры
fps = 60
time = 1000 // fps
# Изначальное состояние игры
game_state = "menu"
# Функция запускающая главное меню
def main_menu():
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
return
elif event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
elif event.type == pygame.QUIT:
pygame.quit()
sys.exit()
window.fill((0, 0, 0)) # Заливка окна черным цветом
# Отображение текста и элементов главного меню
font = pygame.font.Font(None, 36)
text = font.render("Нажмите Enter чтобы начать", True, (255, 255, 255))
text_rect = text.get_rect(center=(window_width // 2, window_height // 2))
window.blit(text, text_rect)
pygame.display.flip()
clock.tick(fps)
# Основной игровой цикл
running = True
while running:
if game_state == "menu":
main_menu()
game_state = "playing" # После выхода из главного меню начинается игра
elif game_state == "playing":
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit() # Завершение Pygame перед выходом
sys.exit() # Завершение программы
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if not is_jumping:
is_jumping = True
# Формула высоты и скорости прыжка
if is_jumping:
current_frame = 2
if jump_count >= -30:
player_y -= (jump_count * abs(jump_count)) * 0.02
jump_count -= 1
else:
jump_count = 30
is_jumping = False
# Перемещение таракана
if counter > 0:
obstacle_x -= obstacle_speed
if obstacle_x < -obstacle_width:
obstacle_x = window_width
# Перемещение первого кадра фона и номера двери
background1_x -= background_speed
number1_x -= background_speed
if background1_x < -background1_width:
background1_x = background1_width - background_speed
number1_x = ((background1_width * 0.888) + background1_width) - background_speed
counter += 1
score1 += 2
# Перемещение второго кадра фона и номера двери
background2_x -= background_speed
number2_x -= background_speed
if background2_x < -background1_width:
background2_x = background1_width - background_speed
number2_x = ((background1_width * 0.888) + background1_width) - background_speed
counter += 1
score2 += 2
# Проверка на столкновение таракана с игроком
if player_masks[current_frame // animation_speed].overlap(obstacle_mask, (int(obstacle_x - player_x), int(obstacle_y - player_y))):
game_state = "game_over" # Если столкновение произошло, переход в режим "game_over"
# Обновление рекорда
if counter > record:
record = counter
# Отрисовка фона
window.blit(background1_image, (background1_x, background1_y))
window.blit(background2_image, (background2_x, background2_y))
# Отрисовка счёта
font = pygame.font.Font(None, 30)
text = font.render("Счёт: "+str(counter), True, (255, 255, 255))
text_rect = text.get_rect(center=(window_width * 0.05, window_height*0.15))
window.blit(text, text_rect)
# Отрисовка рекорда
text_record = font.render("Рекорд: " + str(record), True, (255, 255, 255))
text_record_rect = text.get_rect(center=(window_width * 0.05, window_height*0.1))
window.blit(text_record, text_record_rect)
# Отрисовка чётного номера двери
font_number = pygame.font.Font(None, 20)
number1 = font_number.render(str(score1), True, (242, 224, 20))
number1_rect = number1.get_rect(center=(number1_x, number1_y))
window.blit(number1, number1_rect)
# Отрисовка нечётного номера двери
number2 = font_number.render(str(score2), True, (242, 224, 20))
number2_rect = number2.get_rect(center=(number2_x, number2_y))
window.blit(number2, number2_rect)
# Отрисовка анимации бега игрока
window.blit(run_images[current_frame // animation_speed], (player_x, player_y))
current_frame += 1
if (current_frame // animation_speed >= len(run_images)) and (is_jumping == False):
current_frame = 0
# Отрисовка таракана
if counter > 0:
window.blit(obstacle_image, (obstacle_x, obstacle_y))
# Обновление окна
pygame.display.update()
clock.tick(fps)
elif game_state == "game_over":
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
game_state = "menu" # При нажатии "Esc" возвращаемся в главное
if event.type == pygame.QUIT:
running = False
break
window.fill((0, 0, 0)) # Заливка окна черным цветом
# Отображение текста меню Game Over
font = pygame.font.Font(None, 36)
text = font.render("Игра окончена", True, (255, 255, 255))
text_rect = text.get_rect(center=(window_width // 2, window_height // 2))
window.blit(text, text_rect)
restart_text = font.render("Нажмите Esc чтобы вернуться в главное меню", True, (255, 255, 255))
restart_rect = restart_text.get_rect(center=(window_width // 2, window_height // 2 + 50))
window.blit(restart_text, restart_rect)
# Возвращение значений к начальным
counter = 0
fps = 60
player_x = window_width * 0.1
player_y = window_height * 0.45
obstacle_x = window_width
obstacle_y = window_height * 0.67
background1_x = 0
background1_y = window_height - background1_height
background2_x = background1_width
background2_y = window_height - background1_height
background3_x = background1_width * 2
background3_y = window_height - background1_height
number1_x = background1_width * 0.888
number1_y = background1_height * 0.435
number2_x = background1_width * 0.888 + background1_width
number2_y = background1_height * 0.435
obstacle_speed = 9
background_speed = 7
score1 = 0
score2 = 1
current_frame = 0
is_jumping = False
jump_count = 30
pygame.display.flip()
clock.tick(fps)
frame_time = clock.get_time()
if frame_time < time:
pygame.time.delay(time - frame_time)
# Сохранение рекорда в файл
with open(record_file_path, "w") as file:
file.write(str(record))
# Закрытие окна Pygame
pygame.quit()
Скорость игры зависит от значения переменной fps. Как я понимаю из за этого скорость зависит ещё и от производительности компьютера, потому что когда я начинал писать игру и она была ещё совсем примитивной, скорость была больше. Теперь когда я ставлю любое значение fps больше 60, скорость не меняется, а если ставлю меньше, она замедляется соответственно значению этой переменной. Но если я ставлю маленькую скорость, у меня просто медленно сменяются кадры картинка перестаёт быть плавной. Как сделать так, чтобы скорость игры не зависела от частоты обновления кадров?
Источник: Stack Overflow на русском