Модули pygame.image и pygame.transform

Загрузка и сохранение изображений в Pygame

Функция load() модуля pygame.image загружает изображение и создает экземпляр Surface, на котором отображено это изображение. В load() передается имя файла. "Родным" форматом является BMP, однако если функция pygame.image.get_extended() возвращает истину, то можно загружать ряд других форматов: PNG, GIF, JPG и др.

import pygame
pygame.init()
 
sc = pygame.display.set_mode((400, 300))
sc.fill((100, 150, 200))
 
dog_surf = pygame.image.load('dog.bmp')
dog_rect = dog_surf.get_rect(bottomright=(400, 300))
sc.blit(dog_surf, dog_rect)
 
pygame.display.update()
 
while 1:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            exit()
 
    pygame.time.delay(20)

dog1.png

Если у изображения нет прозрачного слоя, но он необходим, то следует воспользоваться методом set_colorkey() класса Surface:

...
 
dog_surf = pygame.image.load('dog.bmp')
dog_surf.set_colorkey((255, 255, 255))
 
...

Все пиксели, цвет которых совпадает с переданным в set_colorkey() значением, станут прозрачными.

dog2.png

У формата PNG с альфа-каналом (когда для точек можно настраивать степень прозрачности; обычно устанавливается полностью прозрачный фон) таких проблем нет:

...
sun_surf = pygame.image.load('sun.png')
sun_rect = sun_surf.get_rect()
sc.blit(sun_surf, sun_rect)
 
...

dog_sun.png

Ко всем экземплярам Surface рекомендуется применять метод convert(), который, если не передавать аргументы, переводит формат кодирования пикселей поверхности в формат кодирования пикселей главной поверхности. При выполнении игры это ускоряет отрисовку поверхностей.

Если поверхность была создана на базе изображения с альфа-каналом, то вместо convert() надо использовать метод convert_alpha(), так как первый удаляет прозрачные пиксели (вместо них будет черный цвет). Таким образом, код загрузки и обработки изображений разных форматов должен выглядеть примерно так:

...
dog_surf = pygame.image.load('dog.bmp').convert()
dog_surf.set_colorkey((255, 255, 255))
...
sun_surf = pygame.image.load('sun.png').convert_alpha()
...

Что по смыслу равносильно:

...
dog_surf = pygame.image.load('dog.bmp')
dog_surf = dog_surf.convert()
 
...

Метод convert() возвращает новую, конвертированную, поверхность. Он не изменяет ту, к которой применяется.

В модуле pygame.image есть функция save(), которая позволяет сохранять переданную ей поверхность (не обязательно главную) в формат BMP, TGA, PNG, JPEG. Пример:

...
 
while 1:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            exit()
        elif i.type == pygame.KEYUP and i.key == pygame.K_s:
            pygame.image.save(sc, 'day.png')
 
...

Изменение поверхностей

Модуль pygame.transform содержит функции для изменения поверхностей. Некоторые трансформации (например, изменение размера) приводят к ухудшению изображения из-за потери части пикселей. В таких случаях надо сохранять исходную поверхность и выполнять трансформации от нее.

Функции модуля transform, которые изменяют поверхности, возвращают новые. Первым аргументом им передается исходный Surface. Ниже приведены примеры использования наиболее востребованных функций.

Функция flip() переворачивает Surface по горизонтали и вертикали, к потери качества не приводит. Указывается поверхность и булевыми значениями оси переворота.

import pygame
pygame.init()
 
sc = pygame.display.set_mode((400, 300))
sc.fill((100, 150, 200))
 
dog_surf = pygame.image.load('dog.bmp').convert()
dog_surf.set_colorkey((255, 255, 255))
dog_rect = dog_surf.get_rect(center=(200, 150))
sc.blit(dog_surf, dog_rect)
 
pygame.display.update()
 
while 1:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            exit()
        elif i.type == pygame.KEYUP and i.key == pygame.K_f:
            # собака перевернется слева направо
            flip = pygame.transform.flip(dog_surf, 1, 0)
            sc.fill((100, 150, 200))
            sc.blit(flip, dog_rect)
            pygame.display.update(dog_rect)
 
    pygame.time.delay(20)

Поворот и изменение размера:

...
dog_surf = pygame.image.load('dog.bmp').convert()
dog_surf.set_colorkey((255, 255, 255))
dog_rect = dog_surf.get_rect(center=(200, 150))
sc.blit(dog_surf, dog_rect)
pygame.display.update()
 
# ждем 1 секунду перед изменением
pygame.time.wait(1000)
 
sc.fill((100, 150, 200))
# уменьшаем в два раза
scale = pygame.transform.scale(dog_surf, (dog_surf.get_width()//2, 
                                          dog_surf.get_height()//2))
 
scale_rect = scale.get_rect(center=(200, 150))
 
sc.blit(scale, scale_rect)
 
pygame.display.update(dog_rect)
pygame.time.wait(1000)
 
sc.fill((100, 150, 200))
# поворачиваем на 45 градусов
rot = pygame.transform.rotate(dog_surf, 45)
rot_rect = rot.get_rect(center=(200, 150))
sc.blit(rot, rot_rect)
pygame.display.update()
 
...

Практическая работа

Допустим, у вас есть такое изображение вида сверху машины:

car.png

Напишите программу управления ее движением с помощью стрелок клавиатуры (вверх, вниз, влево, вправо) так, чтобы объект всегда двигался головой вперед.

Курс с примерами решений практических работ: android-приложение, pdf-версия.

Комментарии

import pygame
pygame.init()
 
 
def turning(car_surf):  # Function turning car(need for using original car_surf every time)
    if keys[pygame.K_UP] or keys[pygame.K_DOWN] \
            or keys[pygame.K_RIGHT] or keys[pygame.K_LEFT]:
        car_surf = pygame.transform.rotate(car_surf, turn)
        sc.fill(BLACK)
        sc.blit(car_surf, car_rect)
        pygame.display.update()
 
 
# Constants
FPS = 60
SCREEN_SIZE = WIN_WIDTH, WIN_HEIGHT = 800, 800
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
UP = 0
DOWN = 180
RIGHT = -90
LEFT = 90
speed = 3
 
sc = pygame.display.set_mode(SCREEN_SIZE)
sc.fill(BLACK)
clock = pygame.time.Clock()
 
car_surf = pygame.image.load('C:/Users/Dmitry/Desktop/car.png')
car_rect = car_surf.get_rect(center=(WIN_WIDTH // 2, WIN_HEIGHT // 2))  # Set car in center of screen
sc.blit(car_surf, car_rect)
 
pygame.display.update()
while 1:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            exit()
 
    # Change direct car moving with keys
    keys = pygame.key.get_pressed()
    if keys[pygame.K_UP]:
        turn = UP
        car_rect.y -= speed
    elif keys[pygame.K_DOWN]:
        turn = DOWN
        car_rect.y += speed
    elif keys[pygame.K_RIGHT]:
        turn = RIGHT
        car_rect.x += speed
    elif keys[pygame.K_LEFT]:
        turn = LEFT
        car_rect.x -= speed
 
    turning(car_surf)
 
    clock.tick(FPS)

Ответ на от Дмитрий

import pygame
 
pygame.init()
 
FPS = 60
SCREEN = (600, 400)
GREEN = (0, 255, 0)
 
sc = pygame.display.set_mode(SCREEN)
sc.fill(GREEN)
car_surf_main = pygame.image.load('car.png').convert_alpha()
car_surf = car_surf_main
car_rect = car_surf_main.get_rect(center=(300, 200))
sc.blit(car_surf_main, car_rect)
pygame.display.update()
 
 
play = True
 
while play:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            play = False
 
        if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            car_surf = pygame.transform.rotate(car_surf_main, -90)
 
        if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
            car_surf = pygame.transform.rotate(car_surf_main, 90)
 
        if event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
            car_surf = car_surf_main
 
        if event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
            car_surf = pygame.transform.rotate(car_surf_main, 180)
 
    keys = pygame.key.get_pressed()
    if keys[pygame.K_RIGHT] and car_rect.x + car_rect.height < SCREEN[0]:
        car_rect.x += 3
 
    if keys[pygame.K_LEFT] and car_rect.x > 0:
        car_rect.x -= 3
 
    if keys[pygame.K_UP] and car_rect.y > 0:
        car_rect.y -= 3
 
    if keys[pygame.K_DOWN] and car_rect.y + car_rect.height < SCREEN[1]:
        car_rect.y += 3
 
    sc.fill(GREEN)
    sc.blit(car_surf, car_rect)
    pygame.display.update()
 
    pygame.time.Clock().tick(FPS)

import pygame
import os
 
white = (225, 225, 225)
weight = 700
height= 700
 
pygame.init()
sc = pygame.display.set_mode((weight, height))
clock = pygame.time.Clock()
 
current_path = os.path.dirname(__file__)
resourse_path = os.path.join(current_path)
image_path = os.path.join(resourse_path)
 
 
x = 350
y = 350
sc.fill(white)
 
 
while 1:
	car = pygame.image.load(os.path.join(image_path, 'car.png')).convert()
	car_rect = car.get_rect(center = (x, y))
 
	pygame.display.update()
 
	sc.blit(car, car_rect)
 
 
	for i in pygame.event.get():
		if i.type == pygame.QUIT:
			exit()
	keys = pygame.key.get_pressed()
	if keys[pygame.K_UP]:
		y -= 3
		rot = pygame.transform.rotate(car, 0)
		rot_rect = rot.get_rect(center = (x, y))
		sc.blit(rot, rot_rect)
		pygame.display.update()
 
 
	elif keys[pygame.K_DOWN]:
		y += 3
		rot = pygame.transform.rotate(car, 180)
		rot_rect = rot.get_rect(center = (x, y))
		sc.blit(rot, rot_rect)
		pygame.display.update()
 
 
	elif keys[pygame.K_LEFT]:
		x -= 3
		rot = pygame.transform.rotate(car, 90)
		rot_rect = rot.get_rect(center = (x, y))
		sc.blit(rot, rot_rect)
		pygame.display.update()
 
 
	elif keys[pygame.K_RIGHT]:
		x += 3
		rot = pygame.transform.rotate(car, -90)
		rot_rect = rot.get_rect(center = (x, y))
		sc.blit(rot, rot_rect)
		pygame.display.update()
 
 
	clock.tick(60)

Довольно простое задание, учитывая что мы уже делали аналог с шариком и возвратом его на начальные коорды
Просто замена шарика машинкой + развороты поверхности :)
Уверен, можно обойтись без инициализации двух поверхностей, но мне было лень
import pygame
pygame.init()
 
FPS = 30
W, H = 600, 300
WHITE = (255, 255, 255)
 
sc = pygame.display.set_mode((W,H))
clock = pygame.time.Clock()
 
motion = 'STOP'
 
car_surface_main = pygame.image.load('car.png').convert()
car_surface = pygame.image.load('car.png').convert()
x = W // 2
y = H // 2
 
while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            pygame.quit()
            break
        elif i.type == pygame.KEYDOWN:
            if i.key == pygame.K_LEFT:
                motion = 'LEFT'
            elif i.key == pygame.K_RIGHT:
                motion = 'RIGHT'
            elif i.key == pygame.K_UP:
                motion = 'UP'
            elif i.key == pygame.K_DOWN:
                motion = 'DOWN'
            else:
                motion = 'STOP'
 
    if motion == 'LEFT':
        x -= 3
        car_surface = pygame.transform.rotate(car_surface_main, 90)
    elif motion == 'RIGHT':
        x += 3
        car_surface = pygame.transform.rotate(car_surface_main, 270)
    elif motion == 'UP':
        y -= 3
        car_surface = car_surface_main
    elif motion == 'DOWN':
        y += 3
        car_surface = pygame.transform.rotate(car_surface_main, 180)
 
    sc.fill(WHITE)
    sc.blit(car_surface, (x, y))
 
    pygame.display.update()
    clock.tick(FPS)

import pygame
pygame.init()
""" загрузка изображений и движение   """
 
sc = pygame.display.set_mode((400, 300))#создаем окно
sc.fill((100, 150, 200))
 
car_surf = pygame.image.load('car.bmp').convert()#загруаем изобр-е и создаем экземпляр Surface
car_surf.set_colorkey((255,255,255))#задаем прозрачный слой #Все пиксели, цвет которых совпадает с 
#переданным в set_colorkey() значением, станут прозрачными.
car_rect = car_surf.get_rect(center=(200, 150))#
sc.blit(car_surf, car_rect)#отрисовать поверх-ть (экземпляр Surface)
 
pygame.display.update()#
 
rot = pygame.transform.rotate(car_surf, 0)#
rot_rect=rot.get_rect(center=(200,150))#
while 1:
    a=pygame.event.get()
    for i in a:
        if i.type == pygame.QUIT:#выход
            pygame.quit()
    if i.type == pygame.KEYDOWN and i.key == pygame.K_RIGHT:#при нажатии вправо
        rot = pygame.transform.rotate(car_surf, -90)#повернется на -90 градусов 
    elif i.type == pygame.KEYDOWN and i.key == pygame.K_UP:#при нажатии вверх
        rot = pygame.transform.rotate(car_surf, 0)#повернется на 0 градусов
    elif i.type == pygame.KEYDOWN and i.key == pygame.K_LEFT:#при нажатии влево
        rot = pygame.transform.rotate(car_surf, 90)#повернется на 90 градусов
    elif i.type == pygame.KEYDOWN and i.key == pygame.K_DOWN:#при нажатии вниз
        rot = pygame.transform.rotate(car_surf, 180)#повернется на 180 градусов
    sc.fill((100, 150, 200))
    sc.blit(rot,rot_rect)
    pygame.display.update()
#прописываем движение
    keys = pygame.key.get_pressed()
    if keys[pygame.K_RIGHT]:#вправо
        rot_rect.x+=1
    elif keys[pygame.K_UP]:#вверх
        rot_rect.y-=1
    elif keys[pygame.K_LEFT]:#влево
        rot_rect.x-=1
    elif keys[pygame.K_DOWN]:#вниз
        rot_rect.y+=1
 
 
    pygame.time.delay(20)#