Урок 10. Работа с поверхностными объектами (часть 2)
В предыдущем уроке мы познакомились с созданием поверхности, объектами на поверхности, их редактированием и конвертированием. Настало время узнать о подповерностях (подслой), его заполнение, настройки пикселей на поверхности и их получение, копирование информации изображения с поверхности на поверхность.
Подслой
Подслой это поверхность внутри другой поверхности. Когда вы рисуете на подслое, вы также рисуете на родительской поверхности. Один из способ использования подслоев, это рисование шрифтов. Модуль pygame.font воспроизводит шрифт одного цвета, но некоторые игры требует более сложного отображения шрифта. Как вариант, можно сохранить каждую букву в формате изображения, но будет проще создать одно изображение со всеми буквами текста и затем создать 26 подслоев при загрузки изображения в код.
Чтобы создать подслой, нужно вызвать функцию subsurface объекта Surface, которая вызывет прямоугольную область, определяющую часть экрана которую необходимо заполнить. В результате будет возвращен новый объект Surface имеющий тот же цветовой формат что и родительская поверхность. Например, мы можем загрузить изображение с шрифтами и разделить в соответствие с размерами:
my_font_image = pygame.load(”font.png”)
letters = []
letters["a"] = my_font_image.subsurface ((0, 0), (80, 80))
letters["b"] = my_font_image.subsurface ((80, 0), (80, 80))
Код создаст два подслоя из my_font_image и сохранит их в словарь, чтобы мы могли с легкостью посмотреть подслои с соответствующими буквами. Безусловно, нам потребуется намного больше букв нежели “а” и “b”, поэтому вполне вероятно, что подслой будет закольцован на повторение 26 раз.
Когда вы работаете с подслоями важно помнить, что они имеют свою координатную систему. Другими словами, (0, 0) на подслое всегда является верхним левым углом вне зависимости от расположения его родительской поверхности.
Заполнение поверхности
Когда вы создаете изображение на экране, вы должны заполнить весь экран, иначе останутся видны части предыдущего экрана. Если вы не отрисовываете каждый пиксель, вы получите неприятный эффект стробирования при попытки анимировать что-либо. Самый простой способ избежать этого – очистить экран вызвав функцию fill. Выглядит это следующим образом:
screen.fill ((0, 0))
Функция fill также может быть использована для заполнения определенной части поверхностного объекта.
Установка пикселей на поверхности
Одна из базовых вещей которую мы можем выполнять, это заполнить экран маленькими разноцветными точками. Для этого мы будем использовать функцию set_at, которая берет координаты пикселей и цвет пикселей. Чтобы понять как это работает, напишем скрипт, который автоматически хаотично рисует пиксели:
import pygame
from pygame.locals import*
from sys import exit
from random import randint
pygame.init ()
screen = pygame.display.set_mode ((640, 480), 0, 32)
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit ()
rand_col = (randint (0, 255), randint (0, 255), randint (0, 255))
for _ in xrange (100):
rand_pos = (randint (0, 639), randint (0, 479))
screen.set_at (rand_pos, rand_col)
pygame.display.update ()
В результате:

Получение пикселей на поверхности
Дополнением set_at является get_at, который возвращает цвет пикселя на заданной координате. Получение пикселей необходимо для определения столкновений, то есть чтобы программа могла определить, что игровой персонаж располагается в точности в нужном месте. Если все платформы и другие объекты определенного цвета, то такой вариант будет работать на ура. set_at берет один параметр, который должен быть кортежом координат необходимого пикселя. В следующем примере, мы получаем пиксель с координатами (100, 100) на поверхности под названием screen:
my_color = screen.get_at ((100, 100))
Внимание! Функция get_at может работать медленно при чтение с “аппаратной” поверхности. Экран может быть аппаратной поверхностью, особенно если приложение запущено на весь экран – поэтому, по возможности вы должны избегать получение пикселей на экране.
Фиксация поверхности
Всякий раз когда Pygame отрисовывает объекты на поверхности, в первую очередь они должны быть заблокированы. Когда поверхность заблокирована, Pygame получает полный контроль над поверхностью и никакой другой процесс не может использовать поверхность, пока она заблокирована. Блокировка и разблокировка происходит автоматически когда вы отрисовываете что-либо на поверхности, но она может стать неэффективной при многократном блокирование и разблокирование. В следующем примере написан цикл который вызывает set_at 100 раз, заставляя Pygame блокировать и разблокировать поверхность screen 100 раз. Мы можем снизить количество блокировок и разблокировок и увеличить скорость цикла с помощью ручного блокирования. Следующий пример идентичен предыдущему, но выполняется быстрее благодаря вызову lock перед отрисовкой и вызову unlock после отрисовки всех пикселей:
import pygame
from pygame.locals import*
from sys import exit
from random import randint
pygame.init()
screen = pygame.display.set_mode ((640, 480), 0, 32)
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
rand_col = (randint (0, 255), randint (0, 255), randint (0, 255))
screen.lock ()
for _ in xrange (100):
rand_pos = (randint (0, 639), randint (0, 479))
screen.set_at (rand_pos, rand_col)
screen.unlock()
pygame.display.update()
Внимание! Количественное значение блокировок должно соответствовать количественному значению разблокировок. Если вы забудете разблокировать поверхность, Pygame перестанет отвечать на вызовы, то есть просто напросто повиснет.
Не все поверхности нуждаются в блокировке. Аппаратная поверхность нуждается (экран обычно является аппаратной поверхностью), но для простых программных средств это не нужно. Pygame предоставляет функцию mustlock для поверхностных объектов, которые в ходе цикла возвращают логическое значение True если поверхность нуждается в блокировке. Мы можем проверить возвращаемое значение mustlock перед блокировкой или разблокировкой. Если вы заблокируете поверхность которая не нуждается в этом, ничего страшного.
Блиттер (Blitting)
Название происходит от акронима BLIT (Block Image Transfer). Основное применение блиттер находит в работе с 2D-графикой и связанных с нею преобразованиях. Блиттер копирует параметры изображения с одной поверхности на другую. Вы будете использовать блиттер для отрисовки фона, шрифтов, персонажей и т.д.
Чтобы скопировать поверхность нужно вызвать blit из конечного поверхностного объекта (часто это дисплей) и указать исходную поверхность (спрайт, фон и т.д.) следом за координатами куда мы хотим скопировать. Также мы можем копировать только часть поверхности. Есть два способа использовать функцию blit:
screen.blit (background, (0, 0)) – данный способ копирует поверхность, которая называется background в левый верхний угол экрана. Если background и screen имеют одинаковые размеры, то нам не требует заполнять экран с помощью функции fill. Второй способ:
screen.blit (ogre, (300, 200), (100*frame_no, 0, 100, 100))
Если у нас есть изображение содержащее несколько фреймов идущего великана-людоеда (ogre), то мы можем использовать вышеприведенный код, для того чтобы скопировать его на экран. Изменяя значение frame_no, мы можем копировать другой участок из исходной поверхности.
xione от ноября 26 2009 в изучение pygame
Трэкбек URI | RSS комментариев