Как написать динозаврика на питоне

Не знаете, чем заняться на новогодних праздниках? Предлагаем отложить нарезку оливье и взяться за новый проект — написать свою игру для тачбара. В тексте показываем, как это сделать на Python всего за час.

Вот что получится, если будете следовать инструкции.

С 2016 года у некоторых моделей MacBook Pro есть сенсорная OLED-панель. Она заменяет функциональные клавиши, закладки и элементы настроек.

Для программирования тачбара не обязательно погружаться в Swift и AppKit — достаточно знания Python и библиотеки PyTouchBar. С последним познакомимся подробней: напишем игру с динозавриком и освоим встроенные инструменты модуля.

Используйте навигацию, если нужно изучить конкретные шаги, а не читать инструкцию целиком:

  • Делаем меню и знакомимся с элементами библиотеки
  • Загружаем игровую сцену из кактусов
  • Заставляем динозаврика бежать
  • Выводим количество очков
  • На что еще способна библиотека?

Делаем меню и знакомимся с элементами библиотеки

Кнопка «играть»

PyTouchBar работает в связке с Tkinter. Для начала нужно установить и первый, и второй модули. А после — подготовить GUI-окно, которое будет отображаться на тачбаре. И добавить, например, кнопку «играть».

from tkinter import *
import PyTouchBar

# создание окна Tkinter
root = Tk()
# параметризация кнопки
starter = PyTouchBar.TouchBarItems.Button(title=’играть’, color=(PyTouchBar.Color.green))

# добавление элемента
PyTouchBar.set_touchbar([starter])
# подготовка окна
PyTouchBar.prepare_tk_windows(root)

root.mainloop()

После запуска программы кнопка отобразится на панели.

Для окрашивания кнопки можно использовать встроенную константу PyTouchBar.Color. Или передать в функцию кортеж (r, g, b, a), где r, g, b, a — значения от 0 до 1.

Если нажать на кнопку, ничего не произойдет. Для запуска подпрограммы нужно добавить аргумент action и сослаться на имя функции.

# PyTouchBar, добавление функции для action.

def start(button):
# здесь будет запуск игровой сцены game
print(‘Hello world’)

starter = PyTouchBar.TouchBarItems.Button(title=’играть’, color=(PyTouchBar.Color.green), action=start)

Подпрограмма start нужна для запуска игровой сцены game.

Настройка скорости динозаврика

Библиотека поддерживает не только простые кнопки, но и так называемые «степперы» — с помощью них можно вводить числовые значения. В нашем случае — скорость динозаврика.

# PyTouchBar, добавление степпера.

# минимальная скорость
speed = 2

def set_speed(stepper):
global speed
size = int(speed.value)
print (‘Скорость динозавра:’, speed)

speed_p = PyTouchBar.TouchBarItems.Stepper(min = 2, max = 7, action = set_speed) # параметризация степпера

# добавление кнопки и степпера
PyTouchBar.set_touchbar([speed_p, starter])

После запуска программы элементы отобразятся на панели.

На самом деле PyTouchBar поддерживает больше элементов. Некоторые из них мы добавим в игру ниже. Полный список ищите в официальной документации.

Загружаем игровую сцену из кактусов

Представление 2D-сцены

После нажатия кнопки «играть» должна сработать специальная функция game, которая нужна для отрисовки сцены — динозаврика и кактусов. Один из вариантов — добавить их с помощью кнопок, которые мы будем называть чанками.

Каждый чанк — целочисленное значение:

  • -2 — динозавр врезался в кактус,
  • -1 — кактус,
  • 0 — плоскость,
  • 1 — динозаврик,
  • 2 — динозавр перепрыгнул через кактус.

Карту можно представить так:

map = [1, 0, 0, -1, 0, -1, 0]

Визуализация элементов

Кнопки поддерживают параметр image: на фон можно поставить любое статическое изображение.

Так, например, можно «пройтись» циклом по списку map и наполнить список buttons кнопками с изображениями, выбранными по значениям чанков.

# Отрисовка карты map с помощью кнопок.

for chunk in range(len(map)):
if map[chink] == 1:
buttons[chunk] = PyTouchBar.TouchBarItems.Button(image=’assets/trex.png’, color=(PyTouchBar.Color.black), action=jumping)
elif map[chunk]== 0:
buttons[chunk] = PyTouchBar.TouchBarItems.Button(image=’assets/platform.png’, color=(PyTouchBar.Color.black))
else:
buttons[chunk] = PyTouchBar.TouchBarItems.Button(image=’assets/cactus.png’, color=(PyTouchBar.Color.black))

В результате схема карты преобразится в игровую сцену.

Что нужно учитывать

Для запуска сцены нужно закрыть root-окно и запустить новое. PyTouchBar не поддерживает обновление Tkinter-программ.

def game(map):
# отрисовка карты map

def prepare():
root = Tk()

def start(button): # запускается по клику кнопки «играть»
root.destroy()

# генерируем карту и передаем в функцию игровой сцены
game(map)


PyTouchBar.set_touchbar([starter])
PyTouchBar.prepare_tk_windows(root)
root.mainloop()

prepare()

Но как тогда заставить динозаврика бежать?

Заставляем динозаврика бежать

Чтобы динозаврик побежал, нужно как-то обновлять сцену без root.update(). То есть уничтожать настоящую сцену с помощью root.destroy() и запускать новую с обновленными параметрами map. Получается некое обновление кадров.

Удаление старых кадров

Автоматизировать удаление старых кадров с помощью root.destroy() можно с помощью встроенного метода root.after(). Он умеет запускать отложенные функции.

# root.after(), пример вызова метода destroy.

# после запуска Tkinter удалит кадр через 1 секунду
root.after(1000, start.destroy)
root.mainloop()

1000 — время, спустя которое удалится root-окно. Чем меньше значение, тем быстрее бежит динозаврик.

Создание новых кадров

Сам динозаврик не двигается. Обновляется только задний план — ландшафт сцены.

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

# Генерация новых кадров. Одна итерация — один новый кадр и чанк.

# бесконечная генерация новых чанков и кадров
while True:
new_map = map[1:]
# первый чанк — всегда динозавр (1)
new_map[0] = 1
# условие, чтобы не генерировать два кактуса подряд
if map[-1] == 0:
new_map.append(random.choice([0, -1]))
else:
new_map.append(0)
game(new_map)

На тачбаре это выглядит вот так:

Покадровое обновление игровой сцены.

Для большей плавности нужно создать ассеты для промежуточных кадров. И добавить в игровую сцену дополнительный цикл при отрисовке чанков.

Добавление событий

Предпоследний этап — то, ради чего играют в Google-динозаврика, — «паркур по кактусам».

Чтобы добавить прыжок, нужно завести переменную jump — к ней мы будем прибавлять единицу при нажатии на кнопку с динозавром. И модифицировать список map таким образом, чтобы в первом чанке кактус и динозавр могли встретиться несколькими способами.

Динозаврик врезался в кактус — чанк -2. Комбинация [1, -1], jump = 0.

Динозаврик перепрыгнул кактус — чанк 2. Комбинация [1, -1], jump = 1.

Вот как «сценарии» записаны в программе:

# Ситуативная генерация новых кадров.

jump = 0
# первый элемент — комбинация значений, где второе значение — следующий чанк
map = [[1,0], 0, 0, -1, 0, -1, 0]

while True:
# итоговое значение для комбинации:
# [1,0] → 1 кактуса нет, динозаврик бежит
# [1,-1] → кактус есть: если jump = 1, все хорошо
zero_chunk = 1
# записываем комбинацию
map[0] = [1,map[1]]
# динозаврик не прыгнул на прошлом чанке и врезался
if jump == 0 and map[0] == [1, -1]:
zero_chunk = -2
# на чанке без кактуса jump обнуляется
elif jump >= 1 and map[0] == [1, 0]:
jump = 0
zero_chunk = 1
# динозаврик прыгнул на прошлом чанке, все хорошо
elif jump == 1 and map[0] == [1,-1]:
zero_chunk = 2
points += 1

# настраиваем формат карты для передачи в функцию
new_map = map[1:]
new_map[0] = zero_chunk
if map[-1] == 0:
new_map.append(random.choice([0, -1]))
else:
new_map.append(0)

map = new_map
game(new_map)

В коде отрисовки сцены также нужно добавить новые события:

# Отрисовка игровой сцены.

def game(buttons)

for b in range(len(map)):
# если динозаврик не перепрыгнул, загружаем ассет со столкновением
if map[b] == -2:
buttons[b] = PyTouchBar.TouchBarItems.Button(image=’assets/loss.png’, color=(PyTouchBar.Color.black))
# если динозаврик перепрыгнул, загружаем ассет с прыжком
elif map[b] == 2:
buttons[b] = PyTouchBar.TouchBarItems.Button(image=’assets/lucky.png’, color=(PyTouchBar.Color.black))

На тачбаре это выглядит вот так:

Итоговый результат.

Выводим количество очков

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

Подсчет очков

Для подсчета очков нужно завести переменную points и прибавлять к ней единицу каждый раз, когда динозаврик перепрыгивает через кактус. Но с выводом сообщения немного сложней.

Вывод сообщения

Чтобы вывести сообщение, нужно создать новое окно Tkinter, подготовить его и добавить текстовое поле.

# PyTouchBar, добавление элемента Label.

def finish(points):

# объявление элемента label
label = PyTouchBar.TouchBarItems.Label(text = f’Упс:( Вы набрали: {points}’)

Элемент Label поддерживает разные шрифты, цвета и масштабы. Полный список параметров есть в официальной документации.

Притом вызвать функцию finish нужно после отрисовки сцены.

# Обработка окончания игры.

while True:
points = 0

# динозаврик не прыгнул на прошлом чанке и врезался
if jump == 0 and map[0] == [1, -1]:
zero_chunk = -2
elif jump == 1 and map[0] == [1, -1]:
zero_chunk = 2
points += 1

game(new_map)

# если динозаврик врезался — вызвать finish()
if zero_chunk == -2:
finish(points)

Как закрыть сообщение и программу?

У PyTouchBar есть особенность: с помощью библиотеки можно модифицировать встроенную кнопку escape. Например, сделать ее кнопкой для закрытия программы.


def exit_f(button):
exit()

esc = PyTouchBar.TouchBarItems.Button(title = «exit», action = exit_f)
PyTouchBar.set_touchbar(… , esc_key = esc)

Полная версия кода доступна на GitHub. Подключайтесь и предлагайте свои улучшения.

На что еще способна библиотека?

Даже с ограничениями библиотека кажется интересной. С помощью нее можно написать софт для решения повседневных задач. Например, сделать дополнительный ряд кнопок для всяких спецсимволов, если надоела раскладка Бирмана.

Но Doom с помощью PyTouchBar запустить будет сложно: не понятно, как «вытягивать» отдельные кадры и управлять игрой через панель. Для более сложных проектов лучше «прыгнуть в нору за кроликом» и программировать тачбар с помощью Objective-C.

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

Читайте также:

  • Как я локализовал игру в слова с ИИ: делюсь инструкцией и ссылкой для тестов
  • Какой тип облака выбрать: частное, публичное или гибридное? Объясняем на рыбах и удочках
  • Как начать работать с крупным бизнесом? Советы разработчикам SaaS

Время на прочтение
8 мин

Количество просмотров 5.1K

С 2016 года у некоторых моделей MacBook Pro есть сенсорная OLED-панель. По сути, она просто заменяет функциональные клавиши. Но с ней чуть интересней: на тачбар можно вывести закладки и даже медиаэлементы.

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

В конце статьи — конкурс на плюшевого тирекса.

Меню игры: основные элементы библиотеки


Кнопка «играть». PyTouchBar работает в связке с Tkinter. Для начала нужно установить и первый, и второй модули. А после — подготовить GUI-окно, которое будет отображаться на тачбаре. И добавить, например, кнопку «играть».

from tkinter import *
import PyTouchBar

# создание окна Tkinter
root = Tk() 
# параметризация кнопки
starter = PyTouchBar.TouchBarItems.Button(title='играть', color=(PyTouchBar.Color.green)) 

# добавление элемента
PyTouchBar.set_touchbar([starter])
# подготовка окна 
PyTouchBar.prepare_tk_windows(root) 

root.mainloop()

Подготовка, добавление кнопки.

После запуска программы кнопка отобразится на панели.

Для окрашивания кнопки я использую встроенную константу PuTouchBar.Color, хотя то же самое можно сделать через rgba. Для этого в функцию нужно передать кортеж формата (r, g, b, a), где r, g, b, a — значения от 0 до 1.

Если нажать на кнопку, ничего не произойдет. Для запуска подпрограммы нужно добавить аргумент action и сослаться на имя функции.

...

def start(button):
   # здесь будет запуск игровой сцены game
   print('Hello world')

starter = PyTouchBar.TouchBarItems.Button(title='играть', color=(PyTouchBar.Color.green), action=start)

...

Добавление функции для action кнопки.

Подпрограмма start нужна для запуска игровой сцены game.

Настройка скорости динозаврика. Библиотека поддерживает не только простые кнопки, но и так называемые «степперы» — с помощью них можно вводить числовые значения. В нашем случае — скорость динозаврика.

...

# минимальная скорость
speed = 2 

def set_speed(stepper): 
  global speed
  speed = int(stepper.value)

# параметризация степпера
speed_p = PyTouchBar.TouchBarItems.Stepper(min = 2, max = 8, action = set_speed)

# добавление кнопки и степпера
PyTouchBar.set_touchbar([speed_p, starter]) 

...

Добавление степпера.

После запуска программы элементы отобразятся на панели.

На самом деле PyTouchBar поддерживает больше элементов. Среди них — палитры, текстовые лейблы, слайдеры и другие. Некоторые из них мы добавим в игру ниже. С полным списком можно ознакомиться в официальной документации.

Статическая сцена: загрузка карты и ассетов


Представление 2D-сцены. После нажатия кнопки «играть» должна сработать специальная функция game, которая нужна для отрисовки сцены — динозаврика и кактусов. Их я тоже добавил с помощью кнопок, которые условно называю чанками.

Каждый чанк — целочисленное значение:

  • -2 — динозавр врезался в кактус,
  • -1 — кактус,
  • 0 — плоскость,
  • 1 — динозаврик,
  • 2 — динозавр перепрыгнул через кактус.

Карту можно представить так:

map = [1, 0, 0, -1, 0, -1, 0]

Визуализация элементов. Кнопки поддерживают параметр image: на фон можно поставить любое статическое изображение.

Так, например, можно «пройтись» циклом по map и наполнить список buttons кнопками с изображениями, выбранными по значениям чанков.

for chunk in range(len(map)):
   if map[chunk] == 1:
       buttons[chunk] = PyTouchBar.TouchBarItems.Button(image='assets/trex.png', color=(PyTouchBar.Color.black), action=jumping)
   elif map[chunk] == 0:
       buttons[chunk] = PyTouchBar.TouchBarItems.Button(image='assets/platform.png', color=(PyTouchBar.Color.black))
   else:
       buttons[chunk] = PyTouchBar.TouchBarItems.Button(image='assets/cactus.png', color=(PyTouchBar.Color.black))

Отрисовка карты map с помощью кнопок.

В результате схема карты преобразится в игровую сцену.

Представление игровой сцены.

Что нужно учитывать. Для запуска сцены нужно закрыть root-окно и запустить новое. PyTouchBar не поддерживает обновление Tkinter-программ.

def game(map):
    # создание нового root-окна
    root = Tk()
    # отрисовка карты map
    ...
    # запуск нового root-окна
    root.mainloop()

def prepare():
    root = Tk()
    
    def start(button): # запускается по клику кнопки «играть»
        root.destroy()
        ...
        # генерируем карту и передаем в функцию игровой сцены
        game(map, speed)
           
    ...

    PyTouchBar.set_touchbar([starter])
    PyTouchBar.prepare_tk_windows(root)
    root.mainloop()
           
prepare()

Переключение между окнами.

Но как тогда заставить динозаврика бежать?

Динамическая сцена: работа с кадрами


Чтобы динозаврик побежал, нужно как-то обновлять сцену без root.update(). То есть уничтожать настоящую сцену с помощью root.destroy() и запускать новую с обновленными параметрами map. Получается некое обновление кадров.

Удаление старых кадров. Автоматизировать удаление старых кадров с помощью root.destroy() можно несколькими способами.

  1. Использовать запаздывание time. Можно запустить отдельный «поток», который будет периодически «заглядывать» в основной и удалять root-окно. А отсчет времени реализовать, например, на базе time.sleep().
  2. Использовать встроенный метод root.after(). С помощью него я удаляю старые кадры.

...

# после запуска Tkinter удалит кадр через 1 секунду при speed = 2
root.after(1200 - speed*100, root.destroy) 
root.mainloop()

...

root.after(), пример вызова метода destroy.

Первый аргумент — время, спустя которое удалится root-окно. С помощью него можно установить скорость игры: чем быстрее обновляются кадры, тем быстрее бежит динозаврик.

Создание новых кадров. По сути, генерировать новые кадры можно разными способами. Я выбрал один из самых простых: делаю срез списка map на один элемент и добавляю рандомный чанк в конец. А после — запускаю на новой карте игровую сцену game.

# бесконечная генерация новых чанков и кадров
while True:
     new_map = map[1:]
     # первый чанк — всегда динозавр (1)
     new_map[0] = 1

     # условие, чтобы не генерировать два кактуса подряд  
     if map[-1] == 0:
               new_map.append(random.choice([0, -1]))
     else:
               new_map.append(0)

     map = new_map
     game(new_map, speed)

Генерация новых кадров. Одна итерация — один новый кадр и чанк.

На тачбаре это выглядит вот так:

Для большей плавности нужно создать ассеты для промежуточных кадров. И добавить в игровую сцену дополнительный цикл при отрисовке чанков.

Добавление событий. Предпоследний этап — то, ради чего играют в Google-динозаврика, — «паркур по кактусам».

Чтобы добавить прыжок, нужно завести переменную jump — к ней мы будем прибавлять единицу при нажатии на кнопку с динозавром. И модифицировать список map таким образом, чтобы в первом чанке кактус и динозавр могли встретиться несколькими способами.

  • Динозаврик врезался в кактус — чанк -2. Комбинация [1, -1], jump = 0.

  • Динозаврик перепрыгнул кактус — чанк 2. Комбинация [1, -1], jump = 1.

Вот как «сценарии» записаны в программе:

...

jump = 0
# первый элемент — комбинация значений, где второе значение — следующий чанк
map = [[1,0], 0, 0, -1, 0, -1, 0]

...

while True:
     # итоговое значение для комбинации: 
     # [1,0] → 1 кактуса нет, динозаврик бежит
     # [1,-1] → кактус есть: если jump = 1, все хорошо
     zero_chunk = 1
     # записываем комбинацию 
     map[0] = [1,map[1]]
           
     # динозаврик не прыгнул на прошлом чанке и врезался
     if jump == 0 and map[0] == [1, -1]:
               zero_chunk = -2
     # на чанке без кактуса jump обнуляется
     elif jump >= 1 and map[0] == [1, 0]:
               jump = 0
               zero_chunk = 1
     # динозаврик прыгнул на прошлом чанке, все хорошо
     elif jump == 1 and map[0] == [1,-1]:
               zero_chunk = 2
               points += 1
  
     # настраиваем формат карты для передачи в функцию
     new_map = map[1:]
     new_map[0] = zero_chunk
     if map[-1] == 0:
          new_map.append(random.choice([0, -1]))
     else:
          new_map.append(0)

     map = new_map 
     game(new_map, speed)

Ситуативная генерация новых кадров.

В коде отрисовки сцены также нужно добавить новые события:

def game(buttons)
...

     for b in range(len(map)):
          # если динозаврик не перепрыгнул, загружаем ассет со столкновением
          if map[b] == -2:
               buttons[b] = PyTouchBar.TouchBarItems.Button(image='assets/loss.png', color=(PyTouchBar.Color.black))
          # если динозаврик перепрыгнул, загружаем ассет с прыжком
          elif map[b] == 2:
               buttons[b] = PyTouchBar.TouchBarItems.Button(image='assets/lucky.png', color=(PyTouchBar.Color.black))

...

Отрисовка игровой сцены.

На тачбаре это выглядит вот так:

Динозаврик научился бегать и прыгать!

Возможно, эти тексты тоже вас заинтересуют:

→ Docker на роутере MikroTik: как развернуть и не утонуть в багах
→ Паттерны взаимодействия с ботами в Telegram: неочевидные практики на Python и баг в мессенджере
→ Делаем тетрис в QR-коде, который работает

Сообщение об окончании игры: элемент Label


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

Подсчет очков. Для подсчета очков нужно завести переменную points и прибавлять к ней единицу каждый раз, когда динозаврик перепрыгивает через кактус. Но с выводом сообщения немного сложней.

Вывод сообщения. Чтобы вывести сообщение, нужно создать новое окно Tkinter, подготовить его и добавить текстовое поле.

def finish(points):
    ...

    # объявление элемента label
    label = PyTouchBar.TouchBarItems.Label(text = f'Упс:( Вы набрали: {points}')

    ...

Добавление элемента Label.

Элемент Label поддерживает разные шрифты, цвета и масштабы. Полный список параметров есть в официальной документации.

Притом вызвать функцию finish нужно после отрисовки сцены.

while True:
    points = 0 
    ...

    # динозаврик не прыгнул на прошлом чанке и врезался
    if jump == 0 and map[0] == [1, -1]:
        zero_chunk = -2
    elif jump == 1 and map[0] == [1, -1]:
        zero_chunk = 2
        points += 1
    ...
    game(new_map, speed)
  
    # если динозаврик врезался — вызвать finish()
    if zero_chunk == -2:
        finish(points)

Обработка события «конец игры».

Арендуйте выделенный сервер с запуском от 2 минут и бесплатной заменой комплектующих. И используйте его ресурсы для гейминга.

Как закрыть сообщение и программу? У PyTouchBar есть особенность: с помощью библиотеки можно модифицировать встроенную кнопку escape. Например, сделать ее кнопкой для закрытия программы.

...

def exit_f(button):
    exit()

esc = PyTouchBar.TouchBarItems.Button(title = "exit", action = exit_f)
PyTouchBar.set_touchbar(... , esc_key = esc)

...

Полная версия кода доступна на GitHub. Подключайтесь и предлагайте свои улучшения.

Особенности в работе с PyTouchBar


Отсутствие настройки расстояний. Минимальное расстояние между кнопками фиксированное. Это плохо, если нужно сделать «непрерывное» изображение на панели.

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

«Сырые» контроллеры. В библиотеке есть контроллеры (Control). По сути, это те же кнопки, но сопряженные между собой. Хотя у них нет некоторых параметров. Например, нельзя задать цвет фона.

А другие настройки и вовсе работают хуже, чем в элементе Button. Например, чтобы добавить изображение, его нужно «подогнать» под размеры контроллера. И, возможно, дополнительно использовать параметр image_scale, перебирая различные константы в поисках лучшего разрешения картинки.

Элементы не поддерживают gif. Это плохо, если нужно написать программу с большим количеством анимаций. Конечно, можно сделать раскадровку самостоятельно и обновлять окно приложения с заданной периодичностью. Но это сильно усложняет алгоритм.

«Непрямое» обновление окон. Единственный способ обновить окно — закрыть его и создать заново. Метод root.update() не работает.

В сети нет подробной документации. О назначении некоторых функций остается только догадываться. Документация ограничивается репозиторием на GitHub. А некоторая ее часть не актуальна.

Например, есть раздел про интеграцию библиотеки с Pygame. Буквально несколько строчек кода — и все, больше ничего нет. К тому же загрузка Pygame через PyTouchBar на данный момент не работает. Будем ждать апдейтов от разработчиков.

На что способна библиотека?


Даже с ограничениями библиотека кажется интересной. С помощью нее можно написать софт для решения повседневных задач. Например, сделать дополнительный ряд кнопок для всяких спецсимволов, если надоела раскладка Бирмана.

Но Doom с помощью PyTouchBar запустить будет сложно: не понятно, как «вытягивать» отдельные кадры и управлять игрой через панель. Для более сложных проектов лучше «прыгнуть в нору за кроликом» и программировать тачбар с помощью Objective-C. А если нужно просто подключить какой-то виджет, лучше установить утилиту вроде BetterTouchTool.

Придумайте, какую еще программу или игру можно написать для тачбара. Самому креативному комментатору отправим нашего маскота — плюшевого тирекса Selectel.

Improve Article

Save Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    What would you see in your Chrome browser when there is no internet connection ? Yes, everybody knows that dinosaur game that comes on screen. So, in this article, we are going to build a simple python bot that plays Chrome Dino Game without user interaction. Here we are not using any machine learning or artificial intelligence to counter this problem but we will use simple image/screen processing. 
     

    We will work with Pyautogui and PIL (Python Imaging Library) for implementation. This project is very basic and consists of only about 50 lines of code but its result will make you surprise. 
    Some libraries used are: 

    1. PIL : Python Imaging Library (PIL) is a free library for the Python programming language that adds support for opening, manipulating, and saving many different image file formats. 
       
    2. Pyautogui : PyAutoGUI is a Python module for programmatically controlling the mouse and keyboard without any user interaction.
    3. Time : Python “Time” Module which allows us to handle various operations regarding time, its conversions and representations, which find its use in various applications in life.
    4. Numpy :NumPy is a library for the Python programming language, adding support for large, multi-dimensional arrays and matrices, along with a large collection of high-level mathematical functions to operate on these arrays.

    Algorithm – 

    1. Click on the restart button using Pyautogui library using “replaybutton” coordinates.
    2. Calculate the sum of all white pixels values present in the box in front of Dinosaur.
    3. If the sum of pixels values present at any time in the box becomes less than the sum of white pixels values, it means either “bush” or “bird” is coming. So either we have to make our Dino jump or bend down.
    4. In order to protect Dino from “Bush”, we make a jump.
    5. In order to protect Dino from “Bird”, we always keep our Dino down.

    Below is the Python implementation – 

    Python3

    from PIL import ImageGrab, ImageOps

    import pyautogui

    import time

    import numpy as np 

    class coordinates():

        replaybutton =(360, 214)

        dinasaur = (149, 239 )

    def restartGame():

        pyautogui.click(coordinates.replaybutton)

        pyautogui.keyDown('down')

    def press_space():

        pyautogui.keyUp('down')

        pyautogui.keyDown('space')

        time.sleep(0.05)

        print("jump")

        time.sleep(0.10)

        pyautogui.keyUp('space')

        pyautogui.keyDown('down')

    def imageGrab():

        box = (coordinates.dinasaur[0]+30, coordinates.dinasaur[1],

               coordinates.dinasaur[0]+120, coordinates.dinasaur[1]+2)

        image = ImageGrab.grab(box)

        grayImage = ImageOps.grayscale(image)

        a = np.array(grayImage.getcolors())

        print(a.sum())

        return a.sum()

    restartGame()

    while True:

         if(imageGrab()!= 435):  

            press_space() 

            time.sleep(0.1)  

    Output : 

    Improvements : Over a period of time, the Dino Bot Game becomes fast. The Birds and Bushes start coming very fast. So we are not making our Bot to learn all these things, changing its speed based on past learning. So our bot will function for around 2000 score. In order to score more, we have to apply machine learning and artificial intelligence. 

    Chrome-Dinosaur

    by Pun Waiwitlikhit 29 September 2018 for Brighton College Programming Club

    What are libraries?

    • Libraries are a collection of functions which adds functions to a language.
    • A video game library in python might add functions such as createSprite() which are not usable in normal python.
    • Libraries are essentially a bunch of functions that can be imported to another file where it can be used.
    • Pygame is a video game library that is written in python.

    Intro to Pygame

    • Pygame is a library meaning that you have to download it and import it into your code before you are able to use it.
      You can install pygame by typing this in your TERMINAL:

    pip3 install pygame

    To import pygame into your python code, add this to your python code:

    import pygame

    Initializing

    The first thing we would like to do is initialize the project: We do this by

    import pygame
    pygame.init() #this ‘starts up’ pygame
    
    size = width,height = 640, 480#creates tuple called size with width 400  and height 230
    gameDisplay= pygame.display.set_mode(size) #creates screen
    
    while True: #gameLoop it draws the frames of the game
    
    
      for event in pygame.event.get(): #Check for events
        if event.type == pygame.QUIT:
          pygame.quit() #quits
          quit()
    
      pygame.display.update() #updates the screen
    
    

    The important parts of this code is the contents of while True: as it is the game loop, or the loop which draws the frame every second and updates the state of the game. The event loop (for event in pygame.event.get()) loops through all the events that have just happened — an example of this being the user pressing the exit button on the window — and then decides how to respond to the user input. Anything before the gameloop is just initialization code.

    Drawing Shapes

    To draw shapes in pygame, we use predefined commands from the pygame library. To do this, we edit the game loop

    white = 255,255,255 #Define the RGB value of white as a tuple
    while True:
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          pygame.quit()
          quit()			
      pygame.draw.rect(gameDisplay, white, [30,30,40,50])
      #draws a rectangle at coordinate (30 ,30) with width 40 pixel, height 50 pixels and with colour white on the surface ’gameDisplay’
    
      pygame.display.update()
    

    Drawing the Ground

    Now that we know how to draw a shape, we would like to have the practical use of the shape in the game. To do this, we will draw a ground. The ground is essentially a rectangle which left corner is on the edge and the width of the rectangle is as wide as the window. As we may want to experiment with the height of the ground we will use a variable to store it.

    GROUND_HEIGHT = height-200#The y coordinate of the floor which is 200 pixels away from the bottom

    To draw the ground, add this code to the main loop

    pygame.draw.rect(gameDisplay,white, [0,GROUND_HEIGHT, width, height-GROUND_HEIGHT])

    As an update, your code should now look like this.

    #main.py
    
    import pygame
    pygame.init() #this ‘starts up’ pygame
    size = width,height = 640, 480 #creates tuple called size with width 400 and height 230
    gameDisplay= pygame.display.set_mode(size) #creates screen
    GROUND_HEIGHT = height-100
    black = 0,0,0
    white = 255,255,255 #Define the RGB value of white as a tuple
    xPos = 0
    yPos = 0
    while True: #gameLoop it draws the frames of the game
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          pygame.quit() #quits
          quit()
      gameDisplay.fill(black)
      pygame.draw.rect(gameDisplay,white, [0,GROUND_HEIGHT, width, height-GROUND_HEIGHT])
      xPos += 1
      yPos += 1
      pygame.display.update() #updates the screen
    

    The Dinosaur

    To create the dinosaur, we will first create a class defining a dinosaur and then create a dinosaur object which we will manipulate in the gameloop. To create a class, we start a new file called dinosaur.py in the same project folder as the main.py code. The class should look like this.

    import pygame
    dinocolour = 255,255,255
    DINOHEIGHT = 40
    DINOWIDTH = 20
    class Dinosaur:
      def __init__(self, surfaceHeight):
        self.x = 60
        self.y = 0
        self.yvelocity = 0
        self.height = DINOHEIGHT
        self.width = DINOWIDTH
        self.surfaceHeight = surfaceHeight
      def jump(self): #When adding classes into function, the first parameter must be the parameter
        if(self.y == 0): #Only allow jumping if the dinosaur is on the ground to prevent mid air jumps.
          self.yvelocity = 300
      def update(self, deltaTime): #Updates the y position of the dinosaur each second
        self.yvelocity += -500*deltaTime #Gravity
        self.y += self.yvelocity * deltaTime
        if self.y < 0: #if the dinosaur sinks into the ground, make velocity and y = 0
          self.y = 0
          self.yvelocity = 0
    
      def draw(self,display):
        pygame.draw.rect(display,dinocolour,[self.x,self.surfaceHeight-self.y-self.height,self.width,self.height])
    

    Now that we have created the class, we need to import the class into the game and create the dinosaur object to do that, we add the following code OUTSIDE the game loop.

    from dinosaur import Dinosaur #import the class Dinosaur from the file ’dinosaur’
    dinosaur = Dinosaur(GROUND_HEIGHT)
    

    As our functions require a deltaTime (change in time between the current Game loop and the previous gameloop) which makes our dinosaur move relative to time not the speed of the computer running the game. To do that, we add this before the gameloop

    dinosaur = Dinosaur(GROUND_HEIGHT)

    and this at the start of the gameloop

    deltaTime = (t-lastFrame)/1000.0 #Find difference in time and then convert it to seconds
    lastFrame = t #set lastFrame as the current time for next frame.

    Now we want to draw and update the dinosaur

    dinosaur.draw(gameDisplay) #Draw dinosaur on gameDisplay
    

    After that, we would like to jump if the user presses space.

    if event.key == pygame.K_SPACE: #If that key is space
    	dinosaur.jump() #Make dinosaur jump
    

    In the end, your main.py should look like the following

    import pygame
    from dinosaur import Dinosaur #import the class Dinosaur from the file ’dinosaur’
    
    pygame.init() #this ‘starts up’ pygame
    
    #initialize game
    size = width,height = 640, 480#creates tuple called size with width 400  and height 230
    gameDisplay= pygame.display.set_mode(size) #creates screen
    xPos = 0
    yPos = 0
    GROUND_HEIGHT = height-100
    
    # create Dinosaur
    dinosaur = Dinosaur(GROUND_HEIGHT)
    
    #create lastframe variable
    lastFrame = pygame.time.get_ticks() #get ticks returns current time in milliseconds
    
    #define game colours
    white = 255,255,255
    black = 0,0,0
    
    while True: #gameLoop it draws the frames of the game
        t = pygame.time.get_ticks() #Get current time
        deltaTime = (t-lastFrame)/1000.0 #Find difference in time and then convert it to seconds
        lastFrame = t #set lastFrame as the current time for next frame.
    
        for event in pygame.event.get(): #Check for events
            if event.type == pygame.QUIT:
                pygame.quit() #quits
                quit()
            if event.type == pygame.KEYDOWN: #If user uses the keyboard
                if event.key == pygame.K_SPACE: #If that key is space
                    dinosaur.jump() #Make dinosaur jump
    
    
        gameDisplay.fill(black)
    
        dinosaur.update(deltaTime)
        dinosaur.draw(gameDisplay)
    
        pygame.draw.rect(gameDisplay,white, [0,GROUND_HEIGHT, width, height-GROUND_HEIGHT])
        pygame.display.update() #updates the screen

    
    

    The Obstacle

    Just like the dinosaur, we will create the class for the obstacles on a completely separate file. I will name mine obstacle.py

    # obstacle.py
    
    import pygame
    
    colour = 0,0,255
    class Obstacle:
        def __init__(self, x, size, GroundHeight):
            self.x = x
            self.size = size
            self.GroundHeight = GroundHeight
    
        def draw(self, gameDisplay):
            pygame.draw.rect(gameDisplay, colour, [self.x, self.GroundHeight-self.size, self.size, self.size])
    
        def update(self, deltaTime, velocity):
            self.x -= velocity*deltaTime
    
        def checkOver(self):
            if self.x < 0:
                return True
            else:
                return False
    

    Initializing the obstacle

    To initialize the obstacle, we add this before the gameloop in your main.py file

    # main.py
    
    import random
    from obstacle import Obstacle
    MINGAP = 200
    VELOCITY = 300
    MAXGAP = 600
    obstacles = []
    num_of_obstacles = 4
    lastObstacle = width
    SCORE = 0
    obstaclesize = 50
    for i in range(4):
    	lastObstacle += MINGAP+(MAXGAP-MINGAP)*random.random() #Make distance between rocks random
    	obstacles.append(Obstacle(lastObstacle, obstaclesize, GROUND_HEIGHT))
    

    Making the Obstacles move

    To make the obstacles move, we would need to add the following to the main.py file
    Now that we have created obstacles, we have to use the update function on them. In the initializing code above, we have defined VELOCITY which will be the speed at which the obstacles will move. Add the following into the main loop.

    for obs in obstacles:
    	obs.update(deltaTime, VELOCITY)
    	obs.draw(gameDisplay)
    

    To check if the obstacle has passed, we need add the if statement into the for loop above. Each time the obstacle touches the edge of the screen, it resets its position and the player also scores a point.

    if(obs.checkOver()):
    	SCORE += 1
    	lastObstacle += MINGAP+(MAXGAP-MINGAP)*random.random()
    	obs.x = lastObstacle
    

    Also, in each frame of the game, we have to update the position of the lastObstacle (Keeps track of the position of the final obstacle so that the obstacles can add itself to the back of the queue. We do this by

    lastObstacle -= VELOCITY*deltaTime
    

    https://learnopengl.com/img/in-practice/breakout/collisions_overlap.png

    Chrome-Dinosaur

    by Pun Waiwitlikhit 29 September 2018 for Brighton College Programming Club

    What are libraries?

    • Libraries are a collection of functions which adds functions to a language.
    • A video game library in python might add functions such as createSprite() which are not usable in normal python.
    • Libraries are essentially a bunch of functions that can be imported to another file where it can be used.
    • Pygame is a video game library that is written in python.

    Intro to Pygame

    • Pygame is a library meaning that you have to download it and import it into your code before you are able to use it.
      You can install pygame by typing this in your TERMINAL:

    pip3 install pygame

    To import pygame into your python code, add this to your python code:

    import pygame

    Initializing

    The first thing we would like to do is initialize the project: We do this by

    import pygame
    pygame.init() #this ‘starts up’ pygame
    
    size = width,height = 640, 480#creates tuple called size with width 400  and height 230
    gameDisplay= pygame.display.set_mode(size) #creates screen
    
    while True: #gameLoop it draws the frames of the game
    
    
      for event in pygame.event.get(): #Check for events
        if event.type == pygame.QUIT:
          pygame.quit() #quits
          quit()
    
      pygame.display.update() #updates the screen
    
    

    The important parts of this code is the contents of while True: as it is the game loop, or the loop which draws the frame every second and updates the state of the game. The event loop (for event in pygame.event.get()) loops through all the events that have just happened — an example of this being the user pressing the exit button on the window — and then decides how to respond to the user input. Anything before the gameloop is just initialization code.

    Drawing Shapes

    To draw shapes in pygame, we use predefined commands from the pygame library. To do this, we edit the game loop

    white = 255,255,255 #Define the RGB value of white as a tuple
    while True:
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          pygame.quit()
          quit()			
      pygame.draw.rect(gameDisplay, white, [30,30,40,50])
      #draws a rectangle at coordinate (30 ,30) with width 40 pixel, height 50 pixels and with colour white on the surface ’gameDisplay’
    
      pygame.display.update()
    

    Drawing the Ground

    Now that we know how to draw a shape, we would like to have the practical use of the shape in the game. To do this, we will draw a ground. The ground is essentially a rectangle which left corner is on the edge and the width of the rectangle is as wide as the window. As we may want to experiment with the height of the ground we will use a variable to store it.

    GROUND_HEIGHT = height-200#The y coordinate of the floor which is 200 pixels away from the bottom

    To draw the ground, add this code to the main loop

    pygame.draw.rect(gameDisplay,white, [0,GROUND_HEIGHT, width, height-GROUND_HEIGHT])

    As an update, your code should now look like this.

    #main.py
    
    import pygame
    pygame.init() #this ‘starts up’ pygame
    size = width,height = 640, 480 #creates tuple called size with width 400 and height 230
    gameDisplay= pygame.display.set_mode(size) #creates screen
    GROUND_HEIGHT = height-100
    black = 0,0,0
    white = 255,255,255 #Define the RGB value of white as a tuple
    xPos = 0
    yPos = 0
    while True: #gameLoop it draws the frames of the game
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          pygame.quit() #quits
          quit()
      gameDisplay.fill(black)
      pygame.draw.rect(gameDisplay,white, [0,GROUND_HEIGHT, width, height-GROUND_HEIGHT])
      xPos += 1
      yPos += 1
      pygame.display.update() #updates the screen
    

    The Dinosaur

    To create the dinosaur, we will first create a class defining a dinosaur and then create a dinosaur object which we will manipulate in the gameloop. To create a class, we start a new file called dinosaur.py in the same project folder as the main.py code. The class should look like this.

    import pygame
    dinocolour = 255,255,255
    DINOHEIGHT = 40
    DINOWIDTH = 20
    class Dinosaur:
      def __init__(self, surfaceHeight):
        self.x = 60
        self.y = 0
        self.yvelocity = 0
        self.height = DINOHEIGHT
        self.width = DINOWIDTH
        self.surfaceHeight = surfaceHeight
      def jump(self): #When adding classes into function, the first parameter must be the parameter
        if(self.y == 0): #Only allow jumping if the dinosaur is on the ground to prevent mid air jumps.
          self.yvelocity = 300
      def update(self, deltaTime): #Updates the y position of the dinosaur each second
        self.yvelocity += -500*deltaTime #Gravity
        self.y += self.yvelocity * deltaTime
        if self.y < 0: #if the dinosaur sinks into the ground, make velocity and y = 0
          self.y = 0
          self.yvelocity = 0
    
      def draw(self,display):
        pygame.draw.rect(display,dinocolour,[self.x,self.surfaceHeight-self.y-self.height,self.width,self.height])
    

    Now that we have created the class, we need to import the class into the game and create the dinosaur object to do that, we add the following code OUTSIDE the game loop.

    from dinosaur import Dinosaur #import the class Dinosaur from the file ’dinosaur’
    dinosaur = Dinosaur(GROUND_HEIGHT)
    

    As our functions require a deltaTime (change in time between the current Game loop and the previous gameloop) which makes our dinosaur move relative to time not the speed of the computer running the game. To do that, we add this before the gameloop

    dinosaur = Dinosaur(GROUND_HEIGHT)

    and this at the start of the gameloop

    deltaTime = (t-lastFrame)/1000.0 #Find difference in time and then convert it to seconds
    lastFrame = t #set lastFrame as the current time for next frame.

    Now we want to draw and update the dinosaur

    dinosaur.draw(gameDisplay) #Draw dinosaur on gameDisplay
    

    After that, we would like to jump if the user presses space.

    if event.key == pygame.K_SPACE: #If that key is space
    	dinosaur.jump() #Make dinosaur jump
    

    In the end, your main.py should look like the following

    import pygame
    from dinosaur import Dinosaur #import the class Dinosaur from the file ’dinosaur’
    
    pygame.init() #this ‘starts up’ pygame
    
    #initialize game
    size = width,height = 640, 480#creates tuple called size with width 400  and height 230
    gameDisplay= pygame.display.set_mode(size) #creates screen
    xPos = 0
    yPos = 0
    GROUND_HEIGHT = height-100
    
    # create Dinosaur
    dinosaur = Dinosaur(GROUND_HEIGHT)
    
    #create lastframe variable
    lastFrame = pygame.time.get_ticks() #get ticks returns current time in milliseconds
    
    #define game colours
    white = 255,255,255
    black = 0,0,0
    
    while True: #gameLoop it draws the frames of the game
        t = pygame.time.get_ticks() #Get current time
        deltaTime = (t-lastFrame)/1000.0 #Find difference in time and then convert it to seconds
        lastFrame = t #set lastFrame as the current time for next frame.
    
        for event in pygame.event.get(): #Check for events
            if event.type == pygame.QUIT:
                pygame.quit() #quits
                quit()
            if event.type == pygame.KEYDOWN: #If user uses the keyboard
                if event.key == pygame.K_SPACE: #If that key is space
                    dinosaur.jump() #Make dinosaur jump
    
    
        gameDisplay.fill(black)
    
        dinosaur.update(deltaTime)
        dinosaur.draw(gameDisplay)
    
        pygame.draw.rect(gameDisplay,white, [0,GROUND_HEIGHT, width, height-GROUND_HEIGHT])
        pygame.display.update() #updates the screen

    
    

    The Obstacle

    Just like the dinosaur, we will create the class for the obstacles on a completely separate file. I will name mine obstacle.py

    # obstacle.py
    
    import pygame
    
    colour = 0,0,255
    class Obstacle:
        def __init__(self, x, size, GroundHeight):
            self.x = x
            self.size = size
            self.GroundHeight = GroundHeight
    
        def draw(self, gameDisplay):
            pygame.draw.rect(gameDisplay, colour, [self.x, self.GroundHeight-self.size, self.size, self.size])
    
        def update(self, deltaTime, velocity):
            self.x -= velocity*deltaTime
    
        def checkOver(self):
            if self.x < 0:
                return True
            else:
                return False
    

    Initializing the obstacle

    To initialize the obstacle, we add this before the gameloop in your main.py file

    # main.py
    
    import random
    from obstacle import Obstacle
    MINGAP = 200
    VELOCITY = 300
    MAXGAP = 600
    obstacles = []
    num_of_obstacles = 4
    lastObstacle = width
    SCORE = 0
    obstaclesize = 50
    for i in range(4):
    	lastObstacle += MINGAP+(MAXGAP-MINGAP)*random.random() #Make distance between rocks random
    	obstacles.append(Obstacle(lastObstacle, obstaclesize, GROUND_HEIGHT))
    

    Making the Obstacles move

    To make the obstacles move, we would need to add the following to the main.py file
    Now that we have created obstacles, we have to use the update function on them. In the initializing code above, we have defined VELOCITY which will be the speed at which the obstacles will move. Add the following into the main loop.

    for obs in obstacles:
    	obs.update(deltaTime, VELOCITY)
    	obs.draw(gameDisplay)
    

    To check if the obstacle has passed, we need add the if statement into the for loop above. Each time the obstacle touches the edge of the screen, it resets its position and the player also scores a point.

    if(obs.checkOver()):
    	SCORE += 1
    	lastObstacle += MINGAP+(MAXGAP-MINGAP)*random.random()
    	obs.x = lastObstacle
    

    Also, in each frame of the game, we have to update the position of the lastObstacle (Keeps track of the position of the final obstacle so that the obstacles can add itself to the back of the queue. We do this by

    lastObstacle -= VELOCITY*deltaTime
    

    https://learnopengl.com/img/in-practice/breakout/collisions_overlap.png

    Dino Game in Python

    Who has not played Google’s famous Dino Game whenever we are not connected to the internet? Probably everyone might have played this game once. Today, in this article, we will help you develop a Dino Game in Python. This tutorial will include an in-depth explanation of each line of code along with reference materials. We will try our level best to make our readers understand this project in detail and thoroughly. The task record for the Python version of the Dino Game includes picture documents and Python material. GUI makes use of the pygame library.

    We will use one of the most famous Python libraries that is PyGame. Apart from that, we will also use random, os, and sys libraries for the development of this Dino Game in Python. Before moving on to the actual coding let us take a brief overview of What Dino Game is all about? How does it work? etc. After that, we will take a look at the list of features that we need to add to this game. So let us initialize this article without any further ado.

    Basic Idea of the Dino Game in Python

    The main objective of this simplified game is to score an increasing amount of points without becoming distracted by any obstacles. The same playing techniques are used in all games. As stated the core of this mini-game is to accumulate points without coming into contact with any obstacles. The user must use two keyboard keys to play this straightforward game. Jump with the spacebar, and cover with the down arrow. The gaming environment has been modified in this copy compared to the original.

    Having a basic idea of what exactly this game is all about. Let us talk about the mandatory features that need to be there in this project of Dino Game in Python

    Features of this game

    The set of features for Dino Game includes the following:

    • Display previous high score and current score
    • Keyboard support
    • Sound for jump and when dinosaurs die
    • Checkpoint sound
    • Option to replay the game

    Now let us move on to the actual coding of this project.

    Coding Dino Game in Python

    Basic library import

    import os
    import sys
    import pygame
    import random
    from pygame import *
    
    pygame.init()

    Explanation:

    Here we imported all the libraries that we are going to use in the development of this project. The last line pygame. init() is used to initialize all the imported pygame modules.

    Setting up the display window and title

    screenDisplay = (width_screen, height_screen) = (600, 400)
    FPS = 60
    gravity = 0.6
    
    black_color = (0,0,0)
    white_color = (255,255,255)
    backgroundColor = (235, 235, 235)
    
    highest_scores = 0
    
    screenDisplay = pygame.display.set_mode(screenDisplay)
    timerClock = pygame.time.Clock()
    pygame.display.set_caption("Dino Run - CopyAssignment ")

    Explanation:

    In this section of code in Dino Game in Python, we have used the various functions of PyGame in order to set the window size, title, etc. We used to display.set_mode will initialize a window or screen for display. In order to set the title of the window we used set_caption

    Basic resources addition

    soundOnJump = pygame.mixer.Sound('resources/jump.wav')
    soundOnDie = pygame.mixer.Sound('resources/die.wav')
    soundOnCheckpoint = pygame.mixer.Sound('resources/checkPoint.wav')

    Explanation:

    Here w declared three variables that are basically to add various sounds in the game. We made a folder named resources and in that, we have our three .wav files. In order to send sound to our game, we made use of a mixer.Sound(). We will use these three sounds in the other parts of the code.

    Functions to load the images

    def load_image(
        name,
        sx=-1,
        sy=-1,
        colorkey=None,
        ):
    
        fullname = os.path.join('resources', name)
        img = pygame.image.load(fullname)
        img = img.convert()
        if colorkey is not None:
            if colorkey == -1:
                colorkey = img.get_at((0, 0))
            img.set_colorkey(colorkey, RLEACCEL)
    
        if sx != -1 or sy != -1:
            img = pygame.transform.scale(img, (sx, sy))
    
        return (img, img.get_rect())
    
    def load_sprite_sheet(
            s_name,
            namex,
            namey,
            scx = -1,
            scy = -1,
            c_key = None,
            ):
        fullname = os.path.join('resources', s_name)
        sh = pygame.image.load(fullname)
        sh = sh.convert()
    
        sh_rect = sh.get_rect()
    
        sprites = []
    
        sx = sh_rect.width/ namex
        sy = sh_rect.height/ namey
    
        for i in range(0, namey):
            for j in range(0, namex):
                rect = pygame.Rect((j*sx,i*sy,sx,sy))
                img = pygame.Surface(rect.size)
                img = img.convert()
                img.blit(sh,(0,0),rect)
    
                if c_key is not None:
                    if c_key == -1:
                        c_key = img.get_at((0, 0))
                    img.set_colorkey(c_key, RLEACCEL)
    
                if scx != -1 or scy != -1:
                    img = pygame.transform.scale(img, (scx, scy))
    
                sprites.append(img)
    
        sprite_rect = sprites[0].get_rect()
    
        return sprites,sprite_rect

    Explanation:

    Onto the other block of code in Dino Game in Python, this section is mainly responsible for loading images on the game window of Dino Game. Here we used Python’s os. path.join() function that intelligently joins one or more path components. With the exception of the last path component, this approach concatenates different path components by placing exactly one directory separator (‘/’) after each non-empty portion. A directory separator (‘/’) is added at the end of the final path component to be linked is empty.

    pygame. image.load() this helps us to load the image and then in the for loop, we used the set_colorkey() that will basically set the transparent color key. In the same way, we used the above functions in another user-defined function named load_sprite_sheet

    To display the game over the message

    def gameover_display_message(rbtn_image, gmo_image):
        rbtn_rect = rbtn_image.get_rect()
        rbtn_rect.centerx = width_screen / 2
        rbtn_rect.top = height_screen * 0.52
    
        gmo_rect = gmo_image.get_rect()
        gmo_rect.centerx = width_screen / 2
        gmo_rect.centery = height_screen * 0.35
    
        screenDisplay.blit(rbtn_image, rbtn_rect)
        screenDisplay.blit(gmo_image, gmo_rect)
    
    def extractDigits(num):
        if num > -1:
            d = []
            i = 0
            while(num / 10 != 0):
                d.append(num % 10)
                num = int(num / 10)
    
            d.append(num % 10)
            for i in range(len(d),5):
                d.append(0)
            d.reverse()
            return d

    Explanation:

    Here in this function, we made use of two rectangles in order to display the two images: One of the “Game Over” image and another of the “Replay Image”. We used blit() which means Block Transfer which refers to the process of copying material from one surface to another Surface. The screen you made and the new Surface are the two surfaces in concern. So, this Surface will be taken and placed on top of the screen by the blit() function. The approach requires two arguments. Another function that we defined is extractDigits() – this function is responsible for keeping the track of user’s score.

    Defining the Dino class

    class Dino():
        def __init__(self, sx=-1, sy=-1):
            self.imgs, self.rect = load_sprite_sheet('dino.png', 5, 1, sx, sy, -1)
            self.imgs1, self.rect1 = load_sprite_sheet('dino_ducking.png', 2, 1, 59, sy, -1)
            self.rect.bottom = int(0.98 * height_screen)
            self.rect.left = width_screen / 15
            self.image = self.imgs[0]
            self.index = 0
            self.counter = 0
            self.score = 0
            self.jumping = False
            self.dead = False
            self.ducking = False
            self.blinking = False
            self.movement = [0,0]
            self.jumpSpeed = 11.5
    
            self.stand_position_width = self.rect.width
            self.duck_position_width = self.rect1.width
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def checkbounds(self):
            if self.rect.bottom > int(0.98 * height_screen):
                self.rect.bottom = int(0.98 * height_screen)
                self.jumping = False
    
        def update(self):
            if self.jumping:
                self.movement[1] = self.movement[1] + gravity
    
            if self.jumping:
                self.index = 0
            elif self.blinking:
                if self.index == 0:
                    if self.counter % 400 == 399:
                        self.index = (self.index + 1)%2
                else:
                    if self.counter % 20 == 19:
                        self.index = (self.index + 1)%2
    
            elif self.ducking:
                if self.counter % 5 == 0:
                    self.index = (self.index + 1)%2
            else:
                if self.counter % 5 == 0:
                    self.index = (self.index + 1)%2 + 2
    
            if self.dead:
               self.index = 4
    
            if not self.ducking:
                self.image = self.imgs[self.index]
                self.rect.width = self.stand_position_width
            else:
                self.image = self.imgs1[(self.index) % 2]
                self.rect.width = self.duck_position_width
    
            self.rect = self.rect.move(self.movement)
            self.checkbounds()
    
            if not self.dead and self.counter % 7 == 6 and self.blinking == False:
                self.score += 1
                if self.score % 100 == 0 and self.score != 0:
                    if pygame.mixer.get_init() != None:
                        soundOnCheckpoint.play()
    
            self.counter = (self.counter + 1)
    

    Explanation:

    This class can be considered the heart of Dino Game in Python. It is mainly responsible for handling all the functions of the dinosaur. Initially, we hard-coded all the different variables of the dino like its speed, jump movements, etc. Apart from that in order to show its movement, we used the function update() that will keep track of all the movements like ducking, jumping, death, etc of the dino.

    Defining the Cactus class

    class Ground():
        def __init__(self,speed=-5):
            self.image,self.rect = load_image('ground.png',-1,-1,-1)
            self.image1,self.rect1 = load_image('ground.png',-1,-1,-1)
            self.rect.bottom = height_screen
            self.rect1.bottom = height_screen
            self.rect1.left = self.rect.right
            self.speed = speed
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
            screenDisplay.blit(self.image1, self.rect1)
    
        def update(self):
            self.rect.left += self.speed
            self.rect1.left += self.speed
    
            if self.rect.right < 0:
                self.rect.left = self.rect1.right
    
            if self.rect1.right < 0:
                self.rect1.left = self.rect.right

    Explanation:

    This class is responsible for handling the placement of cacti in this Dino Game in Python. At first, we load the cactus image from our resources folder and set its place, movement, etc. To remove the cactus that are passed from the screen, we made use of an update(). Inside that, we set and if block with the condition that self. rect.right < 0 then we will call the self.kill()

    Defining the Birds class

    class birds(pygame.sprite.Sprite):
        def __init__(self, speed=5, sx=-1, sy=-1):
            pygame.sprite.Sprite.__init__(self,self.containers)
            self.imgs, self.rect = load_sprite_sheet('birds.png', 2, 1, sx, sy, -1)
            self.birds_height = [height_screen * 0.82, height_screen * 0.75, height_screen * 0.60]
            self.rect.centery = self.birds_height[random.randrange(0, 3)]
            self.rect.left = width_screen + self.rect.width
            self.image = self.imgs[0]
            self.movement = [-1*speed,0]
            self.index = 0
            self.counter = 0
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self):
            if self.counter % 10 == 0:
                self.index = (self.index+1)%2
            self.image = self.imgs[self.index]
            self.rect = self.rect.move(self.movement)
            self.counter = (self.counter + 1)
            if self.rect.right < 0:
                self.kill()

    Explanation:

    This class is responsible for handling the placement of cacti in this Dino Game in Python. At first, we load the cactus image from our resources folder and set its place, movement, etc. To remove the cactus that are passed from the screen, we made use of an update(). Inside that, we set and if block with the condition that self.rect.right < 0 then we will call the self.kill(). It is used to remove the widget from the screen and so we use kill().

    Defining the Ground class

    class Ground():
        def __init__(self,speed=-5):
            self.image,self.rect = load_image('ground.png',-1,-1,-1)
            self.image1,self.rect1 = load_image('ground.png',-1,-1,-1)
            self.rect.bottom = height_screen
            self.rect1.bottom = height_screen
            self.rect1.left = self.rect.right
            self.speed = speed
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
            screenDisplay.blit(self.image1, self.rect1)
    
        def update(self):
            self.rect.left += self.speed
            self.rect1.left += self.speed
    
            if self.rect.right < 0:
                self.rect.left = self.rect1.right
    
            if self.rect1.right < 0:
                self.rect1.left = self.rect.right

    Explanation

    In the same way, as we defined the birds class, we defined the ground class and for the movement of the ground, we used the same functions as we did in birds.

    Defining the Cloud class

    class Cloud(pygame.sprite.Sprite):
        def __init__(self,x,y):
            pygame.sprite.Sprite.__init__(self,self.containers)
            self.image,self.rect = load_image('cloud.png',int(90*30/42),30,-1)
            self.speed = 1
            self.rect.left = x
            self.rect.top = y
            self.movement = [-1*self.speed,0]
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self):
            self.rect = self.rect.move(self.movement)
            if self.rect.right < 0:
                self.kill()

    Explanation:

    Moving on to another class in Dino Game in Python. Clouds are also one of the components of this game. Its function and movement are totally the same as the ground. The functions in this class will be the same as those we used in the ground class.

    Handling the scores

    class Scoreboard():
        def __init__(self,x=-1,y=-1):
            self.score = 0
            self.scre_img, self.screrect = load_sprite_sheet('numbers.png', 12, 1, 11, int(11 * 6 / 5), -1)
            self.image = pygame.Surface((55,int(11*6/5)))
            self.rect = self.image.get_rect()
            if x == -1:
                self.rect.left = width_screen * 0.89
            else:
                self.rect.left = x
            if y == -1:
                self.rect.top = height_screen * 0.1
            else:
                self.rect.top = y
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self,score):
            score_digits = extractDigits(score)
            self.image.fill(backgroundColor)
            for s in score_digits:
                self.image.blit(self.scre_img[s], self.screrect)
                self.screrect.left += self.screrect.width
            self.screrect.left = 0

    Explanation:

    Now we have to work on handling the scoreboard in Dino Game. We did this by tracking the movement of the screen. We used our “numbers.png” images to update the scores. On top of that, we called our extractDigits() function that we declared previously to extract single- single digits from the image and then display it based on the movement of the components on the window.

    Introduction screen

    def introduction_screen():
        ado_dino = Dino(44,47)
        ado_dino.blinking = True
        starting_game = False
    
        t_ground,t_ground_rect = load_sprite_sheet('ground.png',15,1,-1,-1,-1)
        t_ground_rect.left = width_screen / 20
        t_ground_rect.bottom = height_screen
    
        logo,l_rect = load_image('logo.png',300,140,-1)
        l_rect.centerx = width_screen * 0.6
        l_rect.centery = height_screen * 0.6
        while not starting_game:
            if pygame.display.get_surface() == None:
                print("Couldn't load display surface")
                return True
            else:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        return True
                    if event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
                            ado_dino.jumping = True
                            ado_dino.blinking = False
                            ado_dino.movement[1] = -1*ado_dino.jumpSpeed
    
            ado_dino.update()
    
            if pygame.display.get_surface() != None:
                screenDisplay.fill(backgroundColor)
                screenDisplay.blit(t_ground[0], t_ground_rect)
                if ado_dino.blinking:
                    screenDisplay.blit(logo, l_rect)
                ado_dino.draw()
    
                pygame.display.update()
    
            timerClock.tick(FPS)
            if ado_dino.jumping == False and ado_dino.blinking == False:
                starting_game = True

    Explanation:

    This screen will be displayed t first whenever the user will run this program of Dino Game in Python. This screen will initially load some of the components of the game like the ground and the logo image only. We used if-else to display a message that “Couldn’t load display surface” just in case our image does not load up. Apart from that, we used the three keys that are Upward and Downward arrow keys and Spacebar to start the game. The game will only start if the user presses any of these keys. The handling of key presses is done using the event.

    Handling the overall gameplay

    def gameplay():
        global highest_scores
        gp = 4
        s_Menu = False
        g_Over = False
        g_exit = False
        gamer_Dino = Dino(44,47)
        new_grnd = Ground(-1*gp)
        score_boards = Scoreboard()
        highScore = Scoreboard(width_screen * 0.78)
        counter = 0
    
        cactusan = pygame.sprite.Group()
        smallBird = pygame.sprite.Group()
        skyClouds = pygame.sprite.Group()
        last_end_obs = pygame.sprite.Group()
    
        Cactus.containers = cactusan
        birds.containers = smallBird
        Cloud.containers = skyClouds
    
        rbtn_image,rbtn_rect = load_image('replay_button.png',35,31,-1)
        gmo_image,gmo_rect = load_image('game_over.png',190,11,-1)
    
        t_images,t_rect = load_sprite_sheet('numbers.png',12,1,11,int(11*6/5),-1)
        ado_image = pygame.Surface((22,int(11*6/5)))
        ado_rect = ado_image.get_rect()
        ado_image.fill(backgroundColor)
        ado_image.blit(t_images[10],t_rect)
        t_rect.left += t_rect.width
        ado_image.blit(t_images[11],t_rect)
        ado_rect.top = height_screen * 0.1
        ado_rect.left = width_screen * 0.73
    
        while not g_exit:
            while s_Menu:
                pass
            while not g_Over:
                if pygame.display.get_surface() == None:
                    print("Couldn't load display surface")
                    g_exit = True
                    g_Over = True
                else:
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            g_exit = True
                            g_Over = True
    
                        if event.type == pygame.KEYDOWN:
                            if event.key == pygame.K_SPACE:
                                if gamer_Dino.rect.bottom == int(0.98 * height_screen):
                                    gamer_Dino.jumping = True
                                    if pygame.mixer.get_init() != None:
                                        soundOnJump.play()
                                    gamer_Dino.movement[1] = -1*gamer_Dino.jumpSpeed
    
                            if event.key == pygame.K_DOWN:
                                if not (gamer_Dino.jumping and gamer_Dino.dead):
                                    gamer_Dino.ducking = True
    
                        if event.type == pygame.KEYUP:
                            if event.key == pygame.K_DOWN:
                                gamer_Dino.ducking = False
                for c in cactusan:
                    c.movement[0] = -1*gp
                    if pygame.sprite.collide_mask(gamer_Dino,c):
                        gamer_Dino.dead = True
                        if pygame.mixer.get_init() != None:
                            soundOnDie.play()
    
                for p in smallBird:
                    p.movement[0] = -1*gp
                    if pygame.sprite.collide_mask(gamer_Dino,p):
                        gamer_Dino.dead = True
                        if pygame.mixer.get_init() != None:
                            soundOnDie.play()
    
                if len(cactusan) < 2:
                    if len(cactusan) == 0:
                        last_end_obs.empty()
                        last_end_obs.add(Cactus(gp,40,40))
                    else:
                        for l in last_end_obs:
                            if l.rect.right < width_screen*0.7 and random.randrange(0, 50) == 10:
                                last_end_obs.empty()
                                last_end_obs.add(Cactus(gp, 40, 40))
    
                if len(smallBird) == 0 and random.randrange(0,200) == 10 and counter > 500:
                    for l in last_end_obs:
                        if l.rect.right < width_screen*0.8:
                            last_end_obs.empty()
                            last_end_obs.add(birds(gp, 46, 40))
    
                if len(skyClouds) < 5 and random.randrange(0,300) == 10:
                    Cloud(width_screen, random.randrange(height_screen / 5, height_screen / 2))
    
                gamer_Dino.update()
                cactusan.update()
                smallBird.update()
                skyClouds.update()
                new_grnd.update()
                score_boards.update(gamer_Dino.score)
                highScore.update(highest_scores)
    
                if pygame.display.get_surface() != None:
                    screenDisplay.fill(backgroundColor)
                    new_grnd.draw()
                    skyClouds.draw(screenDisplay)
                    score_boards.draw()
                    if highest_scores != 0:
                        highScore.draw()
                        screenDisplay.blit(ado_image, ado_rect)
                    cactusan.draw(screenDisplay)
                    smallBird.draw(screenDisplay)
                    gamer_Dino.draw()
    
                    pygame.display.update()
                timerClock.tick(FPS)
    
                if gamer_Dino.dead:
                    g_Over = True
                    if gamer_Dino.score > highest_scores:
                        highest_scores = gamer_Dino.score
    
                if counter%700 == 699:
                    new_grnd.speed -= 1
                    gp += 1
    
                counter = (counter + 1)
    
            if g_exit:
                break
    
            while g_Over:
                if pygame.display.get_surface() == None:
                    print("Couldn't load display surface")
                    g_exit = True
                    g_Over = False
                else:
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            g_exit = True
                            g_Over = False
                        if event.type == pygame.KEYDOWN:
                            if event.key == pygame.K_ESCAPE:
                                g_exit = True
                                g_Over = False
    
                            if event.key == pygame.K_RETURN or event.key == pygame.K_SPACE:
                                g_Over = False
                                gameplay()
                highScore.update(highest_scores)
                if pygame.display.get_surface() != None:
                    gameover_display_message(rbtn_image, gmo_image)
                    if highest_scores != 0:
                        highScore.draw()
                        screenDisplay.blit(ado_image, ado_rect)
                    pygame.display.update()
                timerClock.tick(FPS)
    
        pygame.quit()
        quit()

    Explanation:

    The gameplay function comes into action whenever the user presses the three keys that we described above to start the game. Once the game starts, it is the responsibility of the gameplay() function to control the movement of each and every component in the game. Besides that, the key presses for various types of movement of the dino are also controlled in this function. The constant display of birds, cacti, clouds, etc. In the end, if the player loses then the game automatically gets into the quit() state. This will help us to take the game into the quit state and display the two images of replay and game over.

    main function

    def main():
        isGameQuit = introduction_screen()
        if not isGameQuit:
            gameplay()
    
    main()

    Explanation:

    This function will call the introduction_screen() if the user quits the game. If that is not the case then the gameplay() function will be called. That simply means that the game will again be in a state wherein the user will be able to play.

    Output:

    Image output:

    Dino Game in Python - Output

    Start Game window
    Game over window
    Game Over window

    Video output:

    Complete Code for Dino Game in Python

    import os
    import sys
    import pygame
    import random
    from pygame import *
    
    pygame.init()
    
    screenDisplay = (width_screen, height_screen) = (600, 400)
    FPS = 60
    gravity = 0.6
    
    black_color = (0,0,0)
    white_color = (255,255,255)
    backgroundColor = (235, 235, 235)
    
    highest_scores = 0
    
    screenDisplay = pygame.display.set_mode(screenDisplay)
    timerClock = pygame.time.Clock()
    pygame.display.set_caption("Dino Run - CopyAssignment ")
    
    soundOnJump = pygame.mixer.Sound('resources/jump.wav')
    soundOnDie = pygame.mixer.Sound('resources/die.wav')
    soundOnCheckpoint = pygame.mixer.Sound('resources/checkPoint.wav')
    
    def load_image(
        name,
        sx=-1,
        sy=-1,
        colorkey=None,
        ):
    
        fullname = os.path.join('resources', name)
        img = pygame.image.load(fullname)
        img = img.convert()
        if colorkey is not None:
            if colorkey == -1:
                colorkey = img.get_at((0, 0))
            img.set_colorkey(colorkey, RLEACCEL)
    
        if sx != -1 or sy != -1:
            img = pygame.transform.scale(img, (sx, sy))
    
        return (img, img.get_rect())
    
    def load_sprite_sheet(
            s_name,
            namex,
            namey,
            scx = -1,
            scy = -1,
            c_key = None,
            ):
        fullname = os.path.join('resources', s_name)
        sh = pygame.image.load(fullname)
        sh = sh.convert()
    
        sh_rect = sh.get_rect()
    
        sprites = []
    
        sx = sh_rect.width/ namex
        sy = sh_rect.height/ namey
    
        for i in range(0, namey):
            for j in range(0, namex):
                rect = pygame.Rect((j*sx,i*sy,sx,sy))
                img = pygame.Surface(rect.size)
                img = img.convert()
                img.blit(sh,(0,0),rect)
    
                if c_key is not None:
                    if c_key == -1:
                        c_key = img.get_at((0, 0))
                    img.set_colorkey(c_key, RLEACCEL)
    
                if scx != -1 or scy != -1:
                    img = pygame.transform.scale(img, (scx, scy))
    
                sprites.append(img)
    
        sprite_rect = sprites[0].get_rect()
    
        return sprites,sprite_rect
    
    def gameover_display_message(rbtn_image, gmo_image):
        rbtn_rect = rbtn_image.get_rect()
        rbtn_rect.centerx = width_screen / 2
        rbtn_rect.top = height_screen * 0.52
    
        gmo_rect = gmo_image.get_rect()
        gmo_rect.centerx = width_screen / 2
        gmo_rect.centery = height_screen * 0.35
    
        screenDisplay.blit(rbtn_image, rbtn_rect)
        screenDisplay.blit(gmo_image, gmo_rect)
    
    def extractDigits(num):
        if num > -1:
            d = []
            i = 0
            while(num / 10 != 0):
                d.append(num % 10)
                num = int(num / 10)
    
            d.append(num % 10)
            for i in range(len(d),5):
                d.append(0)
            d.reverse()
            return d
    
    class Dino():
        def __init__(self, sx=-1, sy=-1):
            self.imgs, self.rect = load_sprite_sheet('dino.png', 5, 1, sx, sy, -1)
            self.imgs1, self.rect1 = load_sprite_sheet('dino_ducking.png', 2, 1, 59, sy, -1)
            self.rect.bottom = int(0.98 * height_screen)
            self.rect.left = width_screen / 15
            self.image = self.imgs[0]
            self.index = 0
            self.counter = 0
            self.score = 0
            self.jumping = False
            self.dead = False
            self.ducking = False
            self.blinking = False
            self.movement = [0,0]
            self.jumpSpeed = 11.5
    
            self.stand_position_width = self.rect.width
            self.duck_position_width = self.rect1.width
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def checkbounds(self):
            if self.rect.bottom > int(0.98 * height_screen):
                self.rect.bottom = int(0.98 * height_screen)
                self.jumping = False
    
        def update(self):
            if self.jumping:
                self.movement[1] = self.movement[1] + gravity
    
            if self.jumping:
                self.index = 0
            elif self.blinking:
                if self.index == 0:
                    if self.counter % 400 == 399:
                        self.index = (self.index + 1)%2
                else:
                    if self.counter % 20 == 19:
                        self.index = (self.index + 1)%2
    
            elif self.ducking:
                if self.counter % 5 == 0:
                    self.index = (self.index + 1)%2
            else:
                if self.counter % 5 == 0:
                    self.index = (self.index + 1)%2 + 2
    
            if self.dead:
               self.index = 4
    
            if not self.ducking:
                self.image = self.imgs[self.index]
                self.rect.width = self.stand_position_width
            else:
                self.image = self.imgs1[(self.index) % 2]
                self.rect.width = self.duck_position_width
    
            self.rect = self.rect.move(self.movement)
            self.checkbounds()
    
            if not self.dead and self.counter % 7 == 6 and self.blinking == False:
                self.score += 1
                if self.score % 100 == 0 and self.score != 0:
                    if pygame.mixer.get_init() != None:
                        soundOnCheckpoint.play()
    
            self.counter = (self.counter + 1)
    
    class Cactus(pygame.sprite.Sprite):
        def __init__(self, speed=5, sx=-1, sy=-1):
            pygame.sprite.Sprite.__init__(self,self.containers)
            self.imgs, self.rect = load_sprite_sheet('cactus-small.png', 3, 1, sx, sy, -1)
            self.rect.bottom = int(0.98 * height_screen)
            self.rect.left = width_screen + self.rect.width
            self.image = self.imgs[random.randrange(0, 3)]
            self.movement = [-1*speed,0]
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self):
            self.rect = self.rect.move(self.movement)
    
            if self.rect.right < 0:
                self.kill()
    
    class birds(pygame.sprite.Sprite):
        def __init__(self, speed=5, sx=-1, sy=-1):
            pygame.sprite.Sprite.__init__(self,self.containers)
            self.imgs, self.rect = load_sprite_sheet('birds.png', 2, 1, sx, sy, -1)
            self.birds_height = [height_screen * 0.82, height_screen * 0.75, height_screen * 0.60]
            self.rect.centery = self.birds_height[random.randrange(0, 3)]
            self.rect.left = width_screen + self.rect.width
            self.image = self.imgs[0]
            self.movement = [-1*speed,0]
            self.index = 0
            self.counter = 0
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self):
            if self.counter % 10 == 0:
                self.index = (self.index+1)%2
            self.image = self.imgs[self.index]
            self.rect = self.rect.move(self.movement)
            self.counter = (self.counter + 1)
            if self.rect.right < 0:
                self.kill()
    
    
    class Ground():
        def __init__(self,speed=-5):
            self.image,self.rect = load_image('ground.png',-1,-1,-1)
            self.image1,self.rect1 = load_image('ground.png',-1,-1,-1)
            self.rect.bottom = height_screen
            self.rect1.bottom = height_screen
            self.rect1.left = self.rect.right
            self.speed = speed
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
            screenDisplay.blit(self.image1, self.rect1)
    
        def update(self):
            self.rect.left += self.speed
            self.rect1.left += self.speed
    
            if self.rect.right < 0:
                self.rect.left = self.rect1.right
    
            if self.rect1.right < 0:
                self.rect1.left = self.rect.right
    
    class Cloud(pygame.sprite.Sprite):
        def __init__(self,x,y):
            pygame.sprite.Sprite.__init__(self,self.containers)
            self.image,self.rect = load_image('cloud.png',int(90*30/42),30,-1)
            self.speed = 1
            self.rect.left = x
            self.rect.top = y
            self.movement = [-1*self.speed,0]
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self):
            self.rect = self.rect.move(self.movement)
            if self.rect.right < 0:
                self.kill()
    
    class Scoreboard():
        def __init__(self,x=-1,y=-1):
            self.score = 0
            self.scre_img, self.screrect = load_sprite_sheet('numbers.png', 12, 1, 11, int(11 * 6 / 5), -1)
            self.image = pygame.Surface((55,int(11*6/5)))
            self.rect = self.image.get_rect()
            if x == -1:
                self.rect.left = width_screen * 0.89
            else:
                self.rect.left = x
            if y == -1:
                self.rect.top = height_screen * 0.1
            else:
                self.rect.top = y
    
        def draw(self):
            screenDisplay.blit(self.image, self.rect)
    
        def update(self,score):
            score_digits = extractDigits(score)
            self.image.fill(backgroundColor)
            for s in score_digits:
                self.image.blit(self.scre_img[s], self.screrect)
                self.screrect.left += self.screrect.width
            self.screrect.left = 0
    
    
    def introduction_screen():
        ado_dino = Dino(44,47)
        ado_dino.blinking = True
        starting_game = False
    
        t_ground,t_ground_rect = load_sprite_sheet('ground.png',15,1,-1,-1,-1)
        t_ground_rect.left = width_screen / 20
        t_ground_rect.bottom = height_screen
    
        logo,l_rect = load_image('logo.png',300,140,-1)
        l_rect.centerx = width_screen * 0.6
        l_rect.centery = height_screen * 0.6
        while not starting_game:
            if pygame.display.get_surface() == None:
                print("Couldn't load display surface")
                return True
            else:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        return True
                    if event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
                            ado_dino.jumping = True
                            ado_dino.blinking = False
                            ado_dino.movement[1] = -1*ado_dino.jumpSpeed
    
            ado_dino.update()
    
            if pygame.display.get_surface() != None:
                screenDisplay.fill(backgroundColor)
                screenDisplay.blit(t_ground[0], t_ground_rect)
                if ado_dino.blinking:
                    screenDisplay.blit(logo, l_rect)
                ado_dino.draw()
    
                pygame.display.update()
    
            timerClock.tick(FPS)
            if ado_dino.jumping == False and ado_dino.blinking == False:
                starting_game = True
    
    def gameplay():
        global highest_scores
        gp = 4
        s_Menu = False
        g_Over = False
        g_exit = False
        gamer_Dino = Dino(44,47)
        new_grnd = Ground(-1*gp)
        score_boards = Scoreboard()
        highScore = Scoreboard(width_screen * 0.78)
        counter = 0
    
        cactusan = pygame.sprite.Group()
        smallBird = pygame.sprite.Group()
        skyClouds = pygame.sprite.Group()
        last_end_obs = pygame.sprite.Group()
    
        Cactus.containers = cactusan
        birds.containers = smallBird
        Cloud.containers = skyClouds
    
        rbtn_image,rbtn_rect = load_image('replay_button.png',35,31,-1)
        gmo_image,gmo_rect = load_image('game_over.png',190,11,-1)
    
        t_images,t_rect = load_sprite_sheet('numbers.png',12,1,11,int(11*6/5),-1)
        ado_image = pygame.Surface((22,int(11*6/5)))
        ado_rect = ado_image.get_rect()
        ado_image.fill(backgroundColor)
        ado_image.blit(t_images[10],t_rect)
        t_rect.left += t_rect.width
        ado_image.blit(t_images[11],t_rect)
        ado_rect.top = height_screen * 0.1
        ado_rect.left = width_screen * 0.73
    
        while not g_exit:
            while s_Menu:
                pass
            while not g_Over:
                if pygame.display.get_surface() == None:
                    print("Couldn't load display surface")
                    g_exit = True
                    g_Over = True
                else:
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            g_exit = True
                            g_Over = True
    
                        if event.type == pygame.KEYDOWN:
                            if event.key == pygame.K_SPACE:
                                if gamer_Dino.rect.bottom == int(0.98 * height_screen):
                                    gamer_Dino.jumping = True
                                    if pygame.mixer.get_init() != None:
                                        soundOnJump.play()
                                    gamer_Dino.movement[1] = -1*gamer_Dino.jumpSpeed
    
                            if event.key == pygame.K_DOWN:
                                if not (gamer_Dino.jumping and gamer_Dino.dead):
                                    gamer_Dino.ducking = True
    
                        if event.type == pygame.KEYUP:
                            if event.key == pygame.K_DOWN:
                                gamer_Dino.ducking = False
                for c in cactusan:
                    c.movement[0] = -1*gp
                    if pygame.sprite.collide_mask(gamer_Dino,c):
                        gamer_Dino.dead = True
                        if pygame.mixer.get_init() != None:
                            soundOnDie.play()
    
                for p in smallBird:
                    p.movement[0] = -1*gp
                    if pygame.sprite.collide_mask(gamer_Dino,p):
                        gamer_Dino.dead = True
                        if pygame.mixer.get_init() != None:
                            soundOnDie.play()
    
                if len(cactusan) < 2:
                    if len(cactusan) == 0:
                        last_end_obs.empty()
                        last_end_obs.add(Cactus(gp,40,40))
                    else:
                        for l in last_end_obs:
                            if l.rect.right < width_screen*0.7 and random.randrange(0, 50) == 10:
                                last_end_obs.empty()
                                last_end_obs.add(Cactus(gp, 40, 40))
    
                if len(smallBird) == 0 and random.randrange(0,200) == 10 and counter > 500:
                    for l in last_end_obs:
                        if l.rect.right < width_screen*0.8:
                            last_end_obs.empty()
                            last_end_obs.add(birds(gp, 46, 40))
    
                if len(skyClouds) < 5 and random.randrange(0,300) == 10:
                    Cloud(width_screen, random.randrange(height_screen / 5, height_screen / 2))
    
                gamer_Dino.update()
                cactusan.update()
                smallBird.update()
                skyClouds.update()
                new_grnd.update()
                score_boards.update(gamer_Dino.score)
                highScore.update(highest_scores)
    
                if pygame.display.get_surface() != None:
                    screenDisplay.fill(backgroundColor)
                    new_grnd.draw()
                    skyClouds.draw(screenDisplay)
                    score_boards.draw()
                    if highest_scores != 0:
                        highScore.draw()
                        screenDisplay.blit(ado_image, ado_rect)
                    cactusan.draw(screenDisplay)
                    smallBird.draw(screenDisplay)
                    gamer_Dino.draw()
    
                    pygame.display.update()
                timerClock.tick(FPS)
    
                if gamer_Dino.dead:
                    g_Over = True
                    if gamer_Dino.score > highest_scores:
                        highest_scores = gamer_Dino.score
    
                if counter%700 == 699:
                    new_grnd.speed -= 1
                    gp += 1
    
                counter = (counter + 1)
    
            if g_exit:
                break
    
            while g_Over:
                if pygame.display.get_surface() == None:
                    print("Couldn't load display surface")
                    g_exit = True
                    g_Over = False
                else:
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            g_exit = True
                            g_Over = False
                        if event.type == pygame.KEYDOWN:
                            if event.key == pygame.K_ESCAPE:
                                g_exit = True
                                g_Over = False
    
                            if event.key == pygame.K_RETURN or event.key == pygame.K_SPACE:
                                g_Over = False
                                gameplay()
                highScore.update(highest_scores)
                if pygame.display.get_surface() != None:
                    gameover_display_message(rbtn_image, gmo_image)
                    if highest_scores != 0:
                        highScore.draw()
                        screenDisplay.blit(ado_image, ado_rect)
                    pygame.display.update()
                timerClock.tick(FPS)
    
        pygame.quit()
        quit()
    
    def main():
        isGameQuit = introduction_screen()
        if not isGameQuit:
            gameplay()
    
    main()

    Reference Material and Link

    Images

    Sound Files

    NOTE: Add all the above files under the “resource” folder:

    Links

    • PyGame Tutorial: Detailed tutorial
    • List of Projects: PyGame projects
    • Random Official Documentation: Click here
    • Random Official Documentation: Click here
    • OS library Official Documentation: Click here
    • sys library Official Documentation: Click here
    • PyGame YouTube Tutorial

    Endnote

    This concludes our tutorial. Dino Game in Python has reached its conclusion. We have tried our level best to explain each and every concept of Dino Game in Python. We at CopyAssignments strongly believe that only by creating projects in Python, can get a strong grip on the various concept and libraries of Python. It is now up to our readers to change the look and add various other functionalities in order to make this project suitable for your resume. We have already utilized a range of libraries and developed a number of fundamental to intermediate-level functions. We really hope that the structure of this article was easy to understand. Keep learning, doing, and growing until we return with another lesson. We appreciate you visiting our website.


    Also Read:

    В Google есть хорошо известное яйцо: когда у вас возникнут проблемы с вашей сетью, появится «маленькая игра динозавров».

    (Если вы хотите играть в игру напрямую, вы можете ввести в адресную строку: Chrome: // Dino или ++ Buckle Skirt 609616831 бесплатно для получения исходного кода, чтобы играть самостоятельно)

    Сегодня мы покажем вам мимическую «маленькую игру динозавров» с Python!

    Не много ерунды, давайте начнем счастливо ~

    Инструменты разработки:

    Версия Python: 3.6.4

    Связанный модуль:

    Модуль Pygame; и некоторые модули Python.

    Экологическое строительство

    Установите Python и добавьте его в переменную среды, которые могут быть соответствующие модули, необходимые для установки PIP.

    Посмотрите, как быстро

    Просто запустите следующую команду на терминале:

    python Game7.py
    



    Введение кода

    Вот принцип реализации игры.

    Во -первых, мы выполняем необходимую работу по инициализации в игре:

    
    #    
    pygame.init()
    screen = pygame.display.set_mode(cfg.SCREENSIZE)
    pygame.display.set_caption('T-Rex Rush-Pikachu of Charles')
    # Импортировать все звуковые файлы
    sounds = {}
    for key, value in cfg.AUDIO_PATHS.items():
      sounds[key] = pygame.mixer.Sound(value)
    

    Затем давайте подумаем о том, какие элементы игры в игре:

    Динозавр: Игрок контролирует, чтобы избежать препятствий на дороге;

    тротуар: Фон игры;

    облако: Фон игры;

    Летающий дракон: Один из препятствий на дороге, маленькие динозавры умрут, когда столкнутся;

    кактус: Один из препятствий на дороге, маленькие динозавры умрут, когда столкнутся;

    Счет: Запишите текущий счет и исторический самый высокий балл.

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


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

    '''пол'''
    class Ground(pygame.sprite.Sprite):
      def __init__(self, imagepath, position, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        # #  
        self.image_0 = pygame.image.load(imagepath)
        self.rect_0 = self.image_0.get_rect()
        self.rect_0.left, self.rect_0.bottom = position
        self.image_1 = pygame.image.load(imagepath)
        self.rect_1 = self.image_1.get_rect()
        self.rect_1.left, self.rect_1.bottom = self.rect_0.right, self.rect_0.bottom
        # Определите некоторые необходимые параметры
        self.speed = -10
      '' 'Обновление пола' '
      def update(self):
        self.rect_0.left += self.speed
        self.rect_1.left += self.speed
        if self.rect_0.right < 0:
          self.rect_0.left = self.rect_1.right
        if self.rect_1.right < 0:
          self.rect_1.left = self.rect_0.right
      '' 'Нарисуйте пол на экране' '' '
      def draw(self, screen):
        screen.blit(self.image_0, self.rect_0)
        screen.blit(self.image_1, self.rect_1)
    
    '''облако'''
    class Cloud(pygame.sprite.Sprite):
      def __init__(self, imagepath, position, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        # #  
        self.image = pygame.image.load(imagepath)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = position
        # Определите некоторые необходимые параметры
        self.speed = -1
      '' Нарисуйте облако на экран '' '' '
      def draw(self, screen):
        screen.blit(self.image, self.rect)
      '' 'Обновление облака' '
      def update(self):
        self.rect = self.rect.move([self.speed, 0])
        if self.rect.right < 0:
          self.kill()
    
    '''кактус'''
    class Cactus(pygame.sprite.Sprite):
      def __init__(self, imagepaths, position=(600, 147), sizes=[(40, 40), (40, 40)], **kwargs):
        pygame.sprite.Sprite.__init__(self)
        # #  
        self.images = []
        image = pygame.image.load(imagepaths[0])
        for i in range(3):
          self.images.append(pygame.transform.scale(image.subsurface((i*101, 0), (101, 101)), sizes[0]))
        image = pygame.image.load(imagepaths[1])
        for i in range(3):
          self.images.append(pygame.transform.scale(image.subsurface((i*68, 0), (68, 70)), sizes[1]))
        self.image = random.choice(self.images)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.bottom = position
        self.mask = pygame.mask.from_surface(self.image)
        # Определите некоторые необходимые переменные
        self.speed = -10
      '' 'Нарисуйте на экран' '' ''
      def draw(self, screen):
        screen.blit(self.image, self.rect)
      '' rebend '' '' '
      def update(self):
        self.rect = self.rect.move([self.speed, 0])
        if self.rect.right < 0:
          self.kill()
    

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

    '' '' Parp Board '' ''
    class Scoreboard(pygame.sprite.Sprite):
      def __init__(self, imagepath, position, size=(11, 13), is_highest=False, bg_color=None, **kwargs):
        pygame.sprite.Sprite.__init__(self)
        # #  
        self.images = []
        image = pygame.image.load(imagepath)
        for i in range(12):
          self.images.append(pygame.transform.scale(image.subsurface((i*20, 0), (20, 24)), size))
        if is_highest:
          self.image = pygame.Surface((size[0]*8, size[1]))
        else:
          self.image = pygame.Surface((size[0]*5, size[1]))
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = position
        # Некоторые необходимые переменные
        self.is_highest = is_highest
        self.bg_color = bg_color
        self.score = '00000'
      '' 'Set Score' '' '
      def set(self, score):
        self.score = str(score).zfill(5)
      '' 'Нарисуйте на экран' '' ''
      def draw(self, screen):
        self.image.fill(self.bg_color)
        for idx, digital in enumerate(list(self.score)):
          digital_image = self.images[int(digital)]
          if self.is_highest:
            self.image.blit(digital_image, ((idx+3)*digital_image.get_rect().width, 0))
          else:
            self.image.blit(digital_image, (idx*digital_image.get_rect().width, 0))
        if self.is_highest:
          self.image.blit(self.images[-2], (0, 0))
          self.image.blit(self.images[-1], (digital_image.get_rect().width, 0))
        screen.blit(self.image, self.rect)
    

    Приведенный выше код использует is_houghest переменные, чтобы отличить, используется ли оценка для записи максимальной оценки игры, или это всего лишь запись текущего балла. Причина этого различия заключается в том, что максимальный счет игры — логотип HI перед игрой, поэтому пространство занимает больше:

    Определение Feilong немного сложнее, потому что оно должно быть не только двигаться влево, но и эффект постоянно раздувания крыльев. В частности, есть две фотографии Фейлонга:

    Все, что вам нужно сделать, это переключать текущие картинки Flying Dragon каждый раз, чтобы достичь эффекта Flying Dragon Fanwings:

    
    '' Flying Dragon ''
    class Ptera(pygame.sprite.Sprite):
      def __init__(self, imagepath, position, size=(46, 40), **kwargs):
        pygame.sprite.Sprite.__init__(self)
        # #  
        self.images = []
        image = pygame.image.load(imagepath)
        for i in range(2):
          self.images.append(pygame.transform.scale(image.subsurface((i*92, 0), (92, 81)), size))
        self.image_idx = 0
        self.image = self.images[self.image_idx]
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.centery = position
        self.mask = pygame.mask.from_surface(self.image)
        # Определите некоторые необходимые переменные
        self.speed = -10
        self.refresh_rate = 10
        self.refresh_counter = 0
      '' 'Нарисуйте на экран' '' ''
      def draw(self, screen):
        screen.blit(self.image, self.rect)
      '' rebend '' '' '
      def update(self):
        if self.refresh_counter % self.refresh_rate == 0:
          self.refresh_counter = 0
          self.image_idx = (self.image_idx + 1) % len(self.images)
          self.loadImage()
        self.rect = self.rect.move([self.speed, 0])
        if self.rect.right < 0:
          self.kill()
        self.refresh_counter += 1
      '' 'Картинки загружены в текущее состояние' '' '
      def loadImage(self):
        self.image = self.images[self.image_idx]
        rect = self.image.get_rect()
        rect.left, rect.top = self.rect.left, self.rect.top
        self.rect = rect
        self.mask = pygame.mask.from_surface(self.image)
    

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

    Вам просто нужно переключить две снимки лука дракона на одни и те же крылья, чтобы достичь эффекта, когда работают маленькие динозавры. Это также похоже на нормальное состояние:

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

    '' 'Маленькие динозавры' '
    class Dinosaur(pygame.sprite.Sprite):
      def __init__(self, imagepaths, position=(40, 147), size=[(44, 47), (59, 47)], **kwargs):
        pygame.sprite.Sprite.__init__(self)
        # Импортировать все фотографии
        self.images = []
        image = pygame.image.load(imagepaths[0])
        for i in range(5):
          self.images.append(pygame.transform.scale(image.subsurface((i*88, 0), (88, 95)), size[0]))
        image = pygame.image.load(imagepaths[1])
        for i in range(2):
          self.images.append(pygame.transform.scale(image.subsurface((i*118, 0), (118, 95)), size[1]))
        self.image_idx = 0
        self.image = self.images[self.image_idx]
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.bottom = position
        self.mask = pygame.mask.from_surface(self.image)
        # Определите некоторые необходимые переменные
        self.init_position = position
        self.refresh_rate = 5
        self.refresh_counter = 0
        self.speed = 11.5
        self.gravity = 0.6
        self.is_jumping = False
        self.is_ducking = False
        self.is_dead = False
        self.movement = [0, 0]
      '''Прыжок'''
      def jump(self, sounds):
        if self.is_dead or self.is_jumping:
          return
        sounds['jump'].play()
        self.is_jumping = True
        self.movement[1] = -1 * self.speed
      '' 'Low Head' '' '
      def duck(self):
        if self.is_jumping or self.is_dead:
          return
        self.is_ducking = True
      '' 'Не склонись головой' '' '
      def unduck(self):
        self.is_ducking = False
      '' 'умер' '' '' '
      def die(self, sounds):
        if self.is_dead:
          return
        sounds['die'].play()
        self.is_dead = True
      '' Нарисуйте динозавр на экран '' ''
      def draw(self, screen):
        screen.blit(self.image, self.rect)
      '' 'Картинки загружены в текущее состояние' '' '
      def loadImage(self):
        self.image = self.images[self.image_idx]
        rect = self.image.get_rect()
        rect.left, rect.top = self.rect.left, self.rect.top
        self.rect = rect
        self.mask = pygame.mask.from_surface(self.image)
      '' Обновление маленьких динозавров '' ''
      def update(self):
        if self.is_dead:
          self.image_idx = 4
          self.loadImage()
          return
        if self.is_jumping:
          self.movement[1] += self.gravity
          self.image_idx = 0
          self.loadImage()
          self.rect = self.rect.move(self.movement)
          if self.rect.bottom >= self.init_position[1]:
            self.rect.bottom = self.init_position[1]
            self.is_jumping = False
        elif self.is_ducking:
          if self.refresh_counter % self.refresh_rate == 0:
            self.refresh_counter = 0
            self.image_idx = 5 if self.image_idx == 6 else 6
            self.loadImage()
        else:
          if self.refresh_counter % self.refresh_rate == 0:
            self.refresh_counter = 0
            if self.image_idx == 1:
              self.image_idx = 2
            elif self.image_idx == 2:
              self.image_idx = 3
            else:
              self.image_idx = 1
            self.loadImage()
        self.refresh_counter += 1
    

    После определения игровых эльфов мы можем их создавать:

    
    # Определите некоторые необходимые элементы и переменные в игре
    score = 0
    score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(534, 15), bg_color=cfg.BACKGROUND_COLOR)
    highest_score = highest_score
    highest_score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(435, 15), bg_color=cfg.BACKGROUND_COLOR, is_highest=True)
    dino = Dinosaur(cfg.IMAGE_PATHS['dino'])
    ground = Ground(cfg.IMAGE_PATHS['ground'], position=(0, cfg.SCREENSIZE[1]))
    cloud_sprites_group = pygame.sprite.Group()
    cactus_sprites_group = pygame.sprite.Group()
    ptera_sprites_group = pygame.sprite.Group()
    add_obstacle_timer = 0
    score_timer = 0
    

    Затем напишите главную петлю игры:

    
    #        
    clock = pygame.time.Clock()
    while True:
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          pygame.quit()
          sys.exit()
        elif event.type == pygame.KEYDOWN:
          if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
            dino.jump(sounds)
          elif event.key == pygame.K_DOWN:
            dino.duck()
        elif event.type == pygame.KEYUP and event.key == pygame.K_DOWN:
          dino.unduck()
      screen.fill(cfg.BACKGROUND_COLOR)
      # -Random Добавить облако
      if len(cloud_sprites_group) < 5 and random.randrange(0, 300) == 10:
        cloud_sprites_group.add(Cloud(cfg.IMAGE_PATHS['cloud'], position=(cfg.SCREENSIZE[0], random.randrange(30, 75))))
      # -Randomly добавить кактус/летающий дракон
      add_obstacle_timer += 1
      if add_obstacle_timer > random.randrange(50, 150):
        add_obstacle_timer = 0
        random_value = random.randrange(0, 10)
        if random_value >= 5 and random_value <= 7:
          cactus_sprites_group.add(Cactus(cfg.IMAGE_PATHS['cacti']))
        else:
          position_ys = [cfg.SCREENSIZE[1]*0.82, cfg.SCREENSIZE[1]*0.75, cfg.SCREENSIZE[1]*0.60, cfg.SCREENSIZE[1]*0.20]
          ptera_sprites_group.add(Ptera(cfg.IMAGE_PATHS['ptera'], position=(600, random.choice(position_ys))))
      # -Update Elements Game
      dino.update()
      ground.update()
      cloud_sprites_group.update()
      cactus_sprites_group.update()
      ptera_sprites_group.update()
      score_timer += 1
      if score_timer > (cfg.FPS//12):
        score_timer = 0
        score += 1
        score = min(score, 99999)
        if score > highest_score:
          highest_score = score
        if score % 100 == 0:
          sounds['point'].play()
        if score % 1000 == 0:
          ground.speed -= 1
          for item in cloud_sprites_group:
            item.speed -= 1
          for item in cactus_sprites_group:
            item.speed -= 1
          for item in ptera_sprites_group:
            item.speed -= 1
      # -Проверка Impact
      for item in cactus_sprites_group:
        if pygame.sprite.collide_mask(dino, item):
          dino.die(sounds)
      for item in ptera_sprites_group:
        if pygame.sprite.collide_mask(dino, item):
          dino.die(sounds)
      # -Порада игровых элементов на экране
      dino.draw(screen)
      ground.draw(screen)
      cloud_sprites_group.draw(screen)
      cactus_sprites_group.draw(screen)
      ptera_sprites_group.draw(screen)
      score_board.set(score)
      highest_score_board.set(highest_score)
      score_board.draw(screen)
      highest_score_board.draw(screen)
      # -Update экран
      pygame.display.update()
      clock.tick(cfg.FPS)
      # -Будь окончилась игра
      if dino.is_dead:
        break
    

    Логика основной петли игры очень проста, то есть игра в игровом экране каждого кадра, нам всем нужно обнаружить работу игрока. Если игрок нажимает кнопку пространства или клавишу ↑, то маленький динозавр прыгает. Если игрок нажимает кнопку ↓, то маленький динозавр смотрит вниз, в противном случае маленькие динозавры будут нормально спешить вперед.

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

    Следует отметить, что мы должны использовать функцию coloride_mask для выполнения более точного обнаружения столкновений вместо предыдущей функции Color_rect:

    То есть, когда минимальный внешний прямоугольник двух целей перекрывается, Collide_Rect определит, что эти две цели имеют столкновения. Это, очевидно, неразумно и принесет плохой игровой опыт игрокам.

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

    Наконец, можно связать все текущие элементы игры с экраном и обновить текущий экран.
    Вероятно, это так.
    Здесь я все еще рекомендую группу по разработке и обмену (QQ) Python Development and Exchange (QQ): 609616831, группа разработана Python. Если вы изучаете Python, вы можете присоединиться. Dry Goods (только разработка программного обеспечения Python), включая новейший 2020 год. Python Advanced Data и Advanced Development Rutorial, добро пожаловать в расширенную нейтрализацию и небольшой партнер, который хочет проникнуть в Python. Код может ввести группу бесплатно

    Like this post? Please share to your friends:
  • Как написать динамический массив на си
  • Как написать динамит
  • Как написать диме масленникову
  • Как написать дилерское предложение
  • Как написать дилерское письмо