Part 13

Анимация

Во многих играх есть движущиеся персонажи, поэтому логичный следующий шаг — создание анимаций. Мы можем создать иллюзию движения, рисуя одно и то же изображение в разных местах на экране и правильно рассчитывая время изменений.

Создание анимации

Следующий код создает анимацию, в которой робот движется слева направо в окне pygame:

import pygame

pygame.init()
window = pygame.display.set_mode((640, 480))

robot = pygame.image.load("robot.png")

x = 0
y = 0
clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()

    window.fill((0, 0, 0))
    window.blit(robot, (x, y))
    pygame.display.flip()

    x += 1
    clock.tick(60)

При выполнении результат должен выглядеть так:

Посмотрим подробнее на задействованные команды. Если мы хотим отслеживать движение изображения на экране, нам нужно знать его положение, поэтому у нас есть две переменные для координат верхнего левого угла изображения:

x = 0
y = 0

Также у нас есть часы, которые используются, чтобы убедиться, что скорость анимации именно такая, как нужно:

clock = pygame.time.Clock()

Главный цикл на каждой итерации рисует изображение в его текущем положении:

    window.fill((0, 0, 0))
    window.blit(robot, (x, y))
    pygame.display.flip()

Сначала метод fill заполняет окно черным цветом, как и раньше. Цвет передается как кортеж, содержащий RGB-значения цвета. В этом случае аргумент (0, 0, 0) означает, что все три компонента — красный, зеленый и синий — имеют значение 0. Каждый компонент может иметь значение от 0 до 255. Поэтому если бы мы передали (255, 255, 255) как аргумент, получили бы белое окно, а с (255, 0, 0) — красное окно. Цветовые коды RGB лежат в основе цифровой работы с цветом, и онлайн есть много инструментов для работы с ними, например RGB Color Codes Chart.

После заполнения окна цветом изображение рисуется в заданном месте методом blit. Затем содержимое окна обновляется функцией pygame.display.flip.

Наконец, значение, сохраненное в x, увеличивается, что заставляет изображение на каждой итерации перемещаться на один пиксель вправо:

    x += 1

В конце вызывается метод часов tick:

    clock.tick(60)

Метод tick отвечает за скорость анимации. Аргумент 60 означает, что цикл должен выполняться 60 раз в секунду, а значит изображение перемещается на 60 пикселей вправо каждую секунду. Это примерно соответствует значению FPS или frames per second, которое используется в играх.

В принципе, метод tick следит за тем, чтобы анимация работала с одинаковой скоростью на каждом компьютере. Если бы такого контроля времени не было, скорость анимации зависела бы от скорости компьютера.

Отскок от стены

Предыдущая анимация была хороша во всем, кроме одного: когда робот достигал стены, он просто продолжал уходить из виду. Сделаем так, чтобы робот отскакивал от стены.

import pygame

pygame.init()
window = pygame.display.set_mode((640, 480))

robot = pygame.image.load("robot.png")

x = 0
y = 0
velocity = 1
clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()

    window.fill((0, 0, 0))
    window.blit(robot, (x, y))
    pygame.display.flip()
    
    x += velocity
    if velocity > 0 and x+robot.get_width() >= 640:
        velocity = -velocity
    if velocity < 0 and x <= 0:
        velocity = -velocity

    clock.tick(60)

Запуск кода выше должен выглядеть так:

Появилась новая переменная velocity, которая определяет направление движения. Если значение больше нуля, движение идет вправо, а если меньше нуля — влево. Точнее, в этом случае при значении 1 робот движется вправо, а при значении -1 — влево.

Следующие строки заставляют робота отскакивать от боковых стен:

    if velocity > 0 and x+robot.get_width() >= 640:
        velocity = -velocity
    if velocity < 0 and x <= 0:
        velocity = -velocity

Если скорость больше нуля, так что робот движется вправо, и правый край изображения выходит за правый край окна, направление меняется на противоположное, и робот начинает двигаться влево. Аналогично, если скорость меньше нуля, так что робот движется влево, и левый край изображения достигает левого края окна, направление снова меняется, и робот снова начинает двигаться вправо.

Так робот движется по траектории от левого края окна к правому, затем обратно к левому, затем снова к правому, повторяясь бесконечно.

Вращение

Создадим еще одну анимацию. На этот раз робот должен вращаться по кругу вокруг центра окна:

import pygame
import math

pygame.init()
window = pygame.display.set_mode((640, 480))

robot = pygame.image.load("robot.png")

angle = 0
clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()

    x = 320+math.cos(angle)*100-robot.get_width()/2
    y = 240+math.sin(angle)*100-robot.get_height()/2

    window.fill((0, 0, 0))
    window.blit(robot, (x, y))
    pygame.display.flip()

    angle += 0.01
    clock.tick(60)

Запуск кода выше должен выглядеть так:

Вращение по достаточно точному кругу достигается с помощью нескольких базовых тригонометрических функций. Переменная angle содержит угол положения робота относительно центра окна и проходящей через него горизонтальной линии. Функции синуса и косинуса из библиотеки Python math используются для вычисления координат положения робота:

        x = 320+math.cos(angle)*100-robot.get_width()/2
        y = 240+math.sin(angle)*100-robot.get_height()/2

Робот вращается по окружности радиуса 100 вокруг центра окна. Гипотенуза в этой ситуации — радиус окружности. Функция косинуса дает длину прилежащего катета прямоугольного треугольника относительно гипотенузы, а значит дает нам координату x положения. Функция синуса дает длину противолежащего катета, то есть координату y. Затем положение корректируется с учетом размера изображения, чтобы центр окружности оказался в центре окна.

На каждой итерации значение angle увеличивается на 0.01. Поскольку мы используем радианы, полный круг равен 2π, то есть примерно 6.28. Роботу требуется около 628 итераций, чтобы пройти полный круг, а при 60 итерациях в секунду это занимает чуть больше 10 секунд.

Loading
Loading
Loading
Loading
Loading
Loading
Вы дошли до конца этого раздела! Перейти к следующему разделу:

Текущие баллы можно посмотреть в синем индикаторе в правом нижнем углу страницы.

В этой части:
  1. 1. Pygame

  2. 2. Анимация

  3. 3. События

  4. 4. Больше приемов pygame