Программирование аркадных игр
и обучение информатикеChapter 13: Введение в спрайты
Спрайт - это двухмерная картинка, являющаяся частью большей, графической сцены. Обычно спрайт отображает какой-либо интерактивный объект на сцене.
Вначале, поддержка спрайтов была организована на отдельном, аппаратном уровне, в игровых консолях. Эта особая поддержка больше не требуется, однако её лексикон до сих пор сохранился.
Библиотека Pygame поддерживает спрайты. Этот код поможет с управлением анимацией, обнаружением столкновений, управлением групп спрайтов.
13.1 Обычные спрайты и столкновения
Этот пример показывает процесс создания набора чёрных блоков с их последовательным
сбором при использовании красных блоков, управляемых мышью.
Программа сохраняет “очки”, записывая, как много блоков уже было собрано.
Код к этому примеру можно найти по ссылке:
http://cs.simpson.edu/index.php?chapter=example_code
# Sample Python/Pygame Programs # Simpson College Computer Science # http:
cs.simpson.edu import pygame import random # Задать цвета black = ( 0, 0, 0) white = ( 255, 255, 255) red = ( 255, 0, 0)
Библиотека pygame импортируется ради поддержки спрайтов. Библиотека random импортируется ради случайного размещения блоков. Установка цветов проходит по стандартной схеме. Пока в этом примере нет ничего нового.
# Этот класс представляет блок # Он наследуется от класса "Sprite" из Pygame class Block(pygame.sprite.Sprite):
Начинается определение класса Block. Заметьте, что на строке 15 этот класс является дочерним классом класса Sprite. pygame.sprite. обозначает библиотеку и пакет, которые будут обсуждены несколько позже. Вся стандартная функциональность класса Sprite отныне будет частью класса Block.
# Конструктор. Ему передаётся цвет блока, # а также его ширина и высота def __init__(self, color, width, height): # Вызвать конструктор родительского класса (Sprite) super().__init__()
Конструктор класса Block, подобно конструкторам других классов, также берёт параметр self. Он также берёт параметр, определяющий цвет, высоту и ширину объекта.
Важно вызывать конструктор родительского класса Sprite для того, чтобы помочь инициализации спрайта. Это делается на строке 21.
# Create an image of the block, and fill it with a color. # This could also be an image loaded from the disk. self.image = pygame.Surface([width, height]) self.image.fill(color)
Этот код создаёт картинку, которая в скором времени появится на экране. Строка 25 создаёт пустую картинку. Строка 26 заполняет её чёрным. Если программе нужно что-то кроме чёрного квадрата, нужно менять именно эти строки.
Например, посмотрите на нижеприведённый код:
self.image = pygame.Surface([width, height]) self.image.fill(white) self.image.set_colorkey(white) pygame.draw.ellipse(self.image,color,[0,0,width,height])
Если бы в создание блока был поставлен этот код, то все блоки были бы в форме эллипсов. Эллипс рисуется на 25й строке, а 26 строка делает белый цвет прозрачным.
self.image = pygame.image.load("player.png").convert() self.image.set_colorkey(white)
Если появляется надобность в растровой графике, то вставив вышеприведённые линии кода загрузит картинку и поставит белый цвет как прозрачный цвет фона. В этом случае, размеры спрайта автоматически будут поставлены как размеры спрайта, так что передавать их уже нужно не будет.
# Достать прямоугольный объект, обладающий размерами картинки # Обновить позицию этого объекта, задав значения rect.x и rect.y self.rect = self.image.get_rect()
Атрибут rect - переменная, являющаяся инстанцией класса Rect, предоставляемого Pygame. Прямоугольник представляет размеры спрайта. Этот класс прямоугольник содержит настраиваемые атрибуты для x и y. Pygame нарисует спрайт там, куда указывают атрибуты x и y. Так что для передвижения спрайта программисту потребуется менять mySpriteRef.rect.x и mySpriteRef.rect.y, где mySpriteRef - переменная, указывающая на спрайт.
# Инициализировать Pygame pygame.init() # Задать размер экрана screen_width=700 screen_height=400 screen=pygame.display.set_mode([screen_width,screen_height])
Этот код инициализирует pygame и создаёт окно для игры. В этом нет ничего отличного от других программ pygame.
# Это список спрайтов. Каждый блок добавляется в этот список. # Список управляется классом, называющимся 'Group.' block_list = pygame.sprite.Group() # Это список каждого спрайта. Все блоки, а также блок игрока. all_sprites_list = pygame.sprite.Group()
Большое преимущество работы со спрайтами - возможность работать с элементами внутри списка. Вместо того, чтобы проверять каждый объект отдельно и смотреть, было ли столкновение, программа просто может проверить элемент со всем списком объектов.
Подобным образом целые группы спрайтов могут менять свою позицию а также быть перерисованы. Нужно просто скомандовать списку обновиться или перерисовать. Это автоматически обновит или нарисует каждый элемент из списка.
Вышеприведённый код создаёт два списка. Переменная all_sprites_list будет содержать в себе все спрайты в игре. Этот список будет использован для рисования всех спрайтов. Переменная block_list содержит каждый объект, с которым игрок может столкнуться. В этом примере он будет содержать в себе каждый объект игры, исключая объект игрока. Очевидно, в этом примере мы не хотим проверять столкновение объекта игрока с объектом игрока, поэтому программе нужен список, который не содержит самого игрока.
for i in range(50): # Здесь создаётся блок block = Block(black, 20, 15) # Задать случайное местоположение блоку block.rect.x = random.randrange(screen_width) block.rect.y = random.randrange(screen_height) # Добавить блок в список объектов block_list.add(block) all_sprites_list.add(block)
Цикл, начинающийся на 46й строке, добавляет 50 чёрных спрайтов-блоков на экран. Строка 48 создаёт новый блок, задаёт ему цвет, ширину, высоту. Строки 51 и 52 задают кординаты, где появится объект. Строка 55 добавляет блок в список блоков, с которыми может столкнуться игрок. Строка 56 добавляет его в список всех блоков.
# Создать красный блок игрока player = Block(red, 20, 15) all_sprites_list.add(player)
Строка 59 создаёт красный блок, который будет представлять игрока. Этот блок добавляется в all_sprites_list, чтобы было возможным его нарисовать.
# Быть в цикле до момента, пока пользователь не решит закрыть программу done=False # Используется для определения скорости обновления экрана clock=pygame.time.Clock() score = 0 # -------- Основной цикл программы ----------- while done==False: for event in pygame.event.get(): # Пользователь что-то сделал if event.type == pygame.QUIT: # Если пользователь нажал "закрыть" done=True # Отметить, что всё готово, так чтобы программа вышла из цикла # Очистить экран screen.fill(white)
Это стандартный програмный цикл. Строка 68 ставит очки игрока на 0.
# Получить текущую позицию мыши в виде списка из двух чисел pos = pygame.mouse.get_pos() # Достать из списка x и y, # так же, как мы бы доставали буквы из строки. # Установить объект игрока на позицию курсора мыши. player.rect.x=pos[0] player.rect.y=pos[1]
Строка 81 достаёт координаты мыши, подобно тому, как это было сделано в разобнанных ранее Pygame программах. Важная часть содержится в строка 86-87, где прямоугольник, содержащий спрайт игрока, переносится в новое местоположение. Помните, что прямоугольник был создан на строке 32 и этот код не будет работать без той строки.
# Проверить, столкнулся ли с чем-нибудь блок игрока blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True)
Эта строка проверяет спрайт player на столкновение со всеми спрайтами из списка block_list. Код возвращает список пересекающихся спрайтов. Если ни один спрайт не пересекается со спрайтом игрока, возвращается пустой лист. Значение True уберёт все столкнувшиеся с игроком спрайты из списка. Если вместо него передать False, спрайты убраны не будут.
# Проверить список столкновений. if len(blocks_hit_list) > 0: score +=len(blocks_hit_list) print( score )
Это проверяет, есть ли какие-либо спрайты в списке столкновений. Если такие имеются, увеличиваем очки игрока на количество спрайтов, с которыми он столкнулся. Затем, выведем результаты на экран. Заметьте, что print на строке 95 не выведет значение в главное окно со спрайтами. Вместо этого, вывод будет показан в консольном окне.
# Нарисовать все спрайты all_sprites_list.draw(screen)
Это заставлит нарисовать все спрайты в all_sprites_list.
# Поставить лимит на 20 кадров в секунду clock.tick(20) # Обновить экран, вывести то, что мы нарисовали pygame.display.flip() pygame.quit()
Это обновляет экран, а также вызывает метод quit после завершения цикла.
13.2 Передвижение спрайтов
В данном примере двигается только спрайт игрока. Как может программа заставить двигаться все спрайты? Этого можно легко достигнуть, нужны только два шага.
Первым шагом будет добавить новый метод в класс Block. Этот метод будет называться update. Функция update будет вызываться автоматически, когда вызывается метод update для всего списка.
Разместите это в классе блока:
def update(self): # Подвинуть блок на один пиксель вниз self.rect.y += 1
Затем поставьте следующую строку в главный цикл программы:
# Вызвать метод update() для всех блоков в block_list block_list.update()
Код не идеален, потому что блоки рано или поздно передвинутся за границы экрана и не появятся снова. Этот код улучшит функцию update так, чтобы блоки появлялись сверху.
def update(self): # Передвинуть блок на один пиксель вниз self.rect.y += 1 if self.rect.y > screen_height: self.rect.y = random.randrange(-100,-10) self.rect.x = random.randrange(0,screen_width)
Если программе нужно обновить только что собранные блоки наверху экрана, спрайт можно поменять с помощью следующего кода:
def reset_pos(self): self.rect.y = random.randrange(-100,-10) self.rect.x = random.randrange(0,screen_width) def update(self): # Передвинуть блок на один пиксель вниз self.rect.y += self.change_y if self.rect.y > screen_height: self.reset_pos() self.game.score -= 1
Вместе того, чтобы уничтожать блоки после столкновения, программа может вызвать функцию reset_pos, и блок переместится наверх экрана, снова готовый быть собранным.
# Проверить, столкнулся ли блок игрока с чем-нибудь. blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True) # Обработать список со столкновениями. if len(blocks_hit_list) > 0: score +=len(blocks_hit_list) print( score )
Найдите вышеприведённый код. Измените True на False, чтобы блоки не уничтожались. Поменяйте условие if на for, идущий через каждый блок, с которым столкнулся игрок. Вызовите block.reset_pos() на каждом из этих блоков. ProgramArcadeGames.com/python_examples/en/sprite_sheets
You are not logged in. Log in here and track your progress.
English version by Paul Vincent Craven
Spanish version by Antonio Rodríguez Verdugo
Russian version by Vladimir Slav
Turkish version by Güray Yildirim
Portuguese version by Armando Marques Sobrinho and Tati Carvalho
Dutch version by Frank Waegeman
Hungarian version by Nagy Attila
Finnish version by Jouko Järvenpää
French version by Franco Rossi
Korean version by Kim Zeung-Il
Chinese version by Kai Lin