Программирование многопользовательских игр для подростков с помощью Python: Часть 1

Рейтинг: 4.6 из 5
Автор
Вадим Соколов
Рейтинг автора
4.6

Вы когда-нибудь задумывались, как устроена многопользовательская игра? Это руководство научит подростков и взрослых программированию многопользовательских игр на Python с PyGame.

Версия

  • Другой, Другой, Другой

Это сообщение члена группы обучения Джулиана Мейера, 13-летнего разработчика Python. Вы можете найти его в Google+ и Twitter.

Я уверен, что время от времени вы и ваши друзья выходите в сеть, чтобы поиграть в многопользовательскую игру. Вы когда-нибудь задумывались о внутренней части этой игры и о том, как все работает?

В этом руководстве вы узнаете о программировании многопользовательских игр, создав образец игры. Попутно вы также узнаете об объектно-ориентированном программировании.

В этом руководстве вы будете использовать модули Python и PyGame. Если вы новичок в Python или PyGame, вам следует сначала взглянуть на это более раннее руководство по началу программирования игр, в котором объясняются некоторые основы PyGame.

Начиная

Первый шаг - убедиться, что у вас установлен PyGame. Вы можете скачать установщик PyGame для Mac здесь. Убедитесь, что вы загрузили установщик Lion, если у вас Mac OSX 10.7 или выше. В противном случае загрузите установщик Snow Leopard.

Вы также можете загрузить и установить PyGame следующими способами:

  • С помощью MacPorts: sudo port install python2.7 py27-game
  • С использованием Fink: sudo fink install python27 pygame-py27
  • С Homebrew и pip, используя команду, найденную здесь.

Если вы используете Windows, вы можете найти свой установщик здесь.

Примечание. Если в последнем руководстве у вас возникли проблемы, убедитесь, что в вашей системе установлена ​​32-разрядная версия Python. Если у вас 64-битная система, вам нужно запустить python2.7-32 для запуска Python.

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

Правила игры

Игра, которую вы собираетесь создать в этом уроке, называется «Коробки». Возможно, вы были знакомы с игрой в эту бумажную игру с друзьями, когда учились в школе!

Если вы не знакомы с игрой, вот правила:

  1. Доска состоит из сетки точек 7 × 7 (которая образует сетку кубиков 6 × 6, если вы соедините точки).
  1. В свой ход игрок заполняет горизонтальный или вертикальный отрезок линии, соединяющий две соседние точки.
  1. Если заполнение отрезка линии завершает прямоугольник в сетке, игрок становится владельцем этого квадрата и получает очко. Игрок также может разместить еще один отрезок линии на том же ходу.
  1. Побеждает игрок, набравший наибольшее количество квадратов / очков в конце игры!

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

Объектно-ориентированное программирование: краткое введение

Прежде чем мы начнем, давайте обсудим нечто, называемое объектно-ориентированным программированием, которое вы собираетесь использовать в этом руководстве.

Объектно-ориентированное программирование, также известное как ООП, представляет собой тип программирования, основанного на объектах . Объект - это связки данных и связанной с ними логики. Например, у вас может быть объект «собака», который состоит из некоторых данных (имя собаки или любимое лакомство) и связанной логики (например, инструкций о том, как лаять).

Объекты состоят из шаблонов, называемых классами, которые определяют, какие типы данных может содержать объект и какие действия он может выполнять. Они известны как свойства и методы объекта соответственно.

Методы - это функции, которые представляют то, что вы можете попросить сделать объект. Например, оператор car.drive () можно интерпретировать как указание объекту в переменной «car» для «drive». Свойства - это переменные, принадлежащие объекту. Продолжая пример, ваш автомобильный объект может иметь свойство с именем gas, а выражение car.gas = 100 установит для автомобиля значение 100.

Эти два оператора управляют уже существующим автомобилем. Напомним, что класс автомобиля - это шаблон, который определяет, как создать объект автомобиля и что такое автомобиль, путем определения его свойств и методов. В определениях этих методов вы найдете код, который управляет автомобилем изнутри. Например, вместо car.gas = 100 вы можете найти self.gas = 100, который является автомобилем, говорящим сам себе - «я», понятно? - установить собственный газ на 100.

ООП - это обширная тема, но для начала вам достаточно всего лишь изложенных выше основ. Ваш код будет описывать игру Boxes как взаимодействие различных объектов. Все эти объекты имеют свойства и методы, которые вы определите в классе объекта. И когда вы пишете фрагмент кода, вы должны помнить, пишете ли вы код класса, который определяет, что объект может делать «изнутри» объекта, или код, который управляет объектом «снаружи» этого объекта. .

Настройка базовой объектно-ориентированной игры

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

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

Создайте в этом каталоге файл с именем box.py с помощью вашего любимого текстового редактора (если у вас его нет, вы можете использовать TextEdit на Mac или Блокнот в Windows). Затем добавьте этот импорт файла:

Это импортирует модуль PyGame для использования. Прежде чем идти дальше, вы должны проверить, работает ли по крайней мере это. Для этого откройте Терминал и перейдите в каталог ваших ящиков с помощью команды cd . Затем введите питона boxes.py . Например, вот как это выглядит на моей машине:

Если после запуска вы не получаете ошибок, это означает, что PyGame установлен правильно, и все готово.

Примечание. Если при выполнении приведенного выше кода возникает ошибка ImportError, в которой говорится, что «Нет модуля с именем pygame», значит, вы не установили PyGame или установили PyGame в копию Python, отличную от той, которую вы используете. Например, если вы использовали MacPorts для установки Python 2.7 и PyGame с портом install python2.7 py27-game, обязательно запустите тот же Python, вызвав python2.7 из Терминала.

Если запуск приведенного выше кода дает вам эту конкретную ошибку:

Это означает, что вам нужно запустить Python в 32-битном режиме, например:

Затем добавьте определение класса, а также одну вещь, которую должен иметь каждый класс:

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

Теперь вы заполните тело функции init, чтобы выполнить некоторую инициализацию PyGame. Добавьте это в код, который вы написали выше, вместо комментария, начинающегося с #put something here. :

Убедитесь, что вы сделали правильный отступ, чтобы все выровнялось до левого поля того места, где был комментарий «#put something here…» . Вы можете узнать больше об этом здесь: Отступы Python.

Давайте посмотрим на код, который вы только что добавили, по частям:

  1. Сначала вы инициализируете PyGame и две переменные, которые вы будете использовать для настройки экрана, ширины и высоты.
  2. Затем вы инициализируете экран, используя эти две переменные. Вы также устанавливаете заголовок экрана.
  3. Наконец, вы инициализируете часы PyGame, которые вам понадобятся для отслеживания времени в игре.

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

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

Запуск файла Python сейчас ничего не даст, поскольку все, что вы сделали, - это класс BoxesGame. Вам еще нужно создать объект этого класса и начать игру!

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

Добавьте этот код в конец файла, чтобы начать игру (левое поле должно быть равно левому полю файла):

Это хорошая вещь в объектно-ориентированном программировании: код, который действительно заставляет вещи происходить, состоит всего из трех строк!

На этом этапе весь файл должен выглядеть так:

Вот и все. Теперь было не так просто? Это хорошее время для запуска игры:

Как видите, запуск игры приводит к очень впечатляющему черному экрану! Ура!

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

Добавим еще один метод. Если вы не помните, что это значит, перечитайте раздел учебного пособия «Объектно-ориентированное программирование: краткое введение».

Рисование доски и линий на экране

В PyGame верхний левый угол окна имеет координаты (0, 0). Итак, давайте определим систему координат для точек в сетке Boxes, которая аналогична, где (0,0) представляет верхнюю левую точку, а (6,6) представляет нижнюю правую точку:

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

С точки зрения программирования список также известен как массив. И когда у вас есть список списков, таких как комбинации горизонтальных и вертикальных линий здесь, это называется 2D-массивом.

Например, чтобы представить горизонтальную линию от (0, 0) до (1, 1), это будет строка 0, столбец 0 в списке «горизонтальных линий».

Обратите внимание, что список горизонтальных линий состоит из 6 строк и 7 столбцов, а список вертикальных линий состоит из 7 строк и 6 столбцов.

Добавьте эти две строки в __init__, чтобы определить эти два массива:

Быстрый способ создать массив - это сделать следующее: [valuePerItem for x in y]. В этом случае вы заполняете массив массивом, заполненным значениями False. Ложь означает пустое место.

Теперь, когда у вас есть представление платы, давайте перейдем к коду отрисовки платы.

Прежде всего, создайте новый метод с именем initGraphics (). Этот метод будет тем, что вы вызываете из __init__, но для того, чтобы ваш код был организован, вы создаете отдельный метод только с целью загрузки графики. Добавьте это прямо перед функцией __init__:

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

У вас есть метод для загрузки всей графики, но вы его еще не вызывали. Попробуйте угадать, куда что добавить!

Получив ответ, нажмите кнопку « Показать» ниже, чтобы убедиться, что вы правы.

[spoiler title = "Решение"] Добавьте это в конец __init__:

Затем вы должны добавить код, который фактически рисует доску. Чтобы перебрать все x и y в сетке, вы должны добавить цикл for внутри цикла for. (Для всех вас, поклонников Inception, вариант for-loop-ception.) Вам нужен цикл, который перебирает значения x и y. Добавьте это сразу после метода __init__:

Этот код просто просматривает сетку и проверяет, была ли нажата эта часть сетки. Код делает это как для горизонтальных, так и для вертикальных линий. self.boardv [x] [y] и self.boardh [x] [y] возвращают либо true, либо false, в зависимости от того, был ли соответствующий сегмент линии заполнен yes.

Запуск программы сейчас по-прежнему ничего не даст. Все, что вы сделали, это определили, что игра должна делать, если когда-либо получит вызов этого метода.

Теперь добавим вызов метода к функции обновления. Добавьте это после того, как очистите экран с помощью screen.fill (0):

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

Запустите свой код сейчас. Когда вы это сделаете, вы должны увидеть сетку, нарисованную на экране:

Каждый раз, когда я пишу код для рисования карты, мне нравится тестировать его, потому что это весело и потому что это хороший способ находить ошибки. Добавьте это после инициализации плат, определив self.boardh и self.boardv:

Запустите код и, как видите, загорится одна горизонтальная линия - строка от (5, 3) до (5, 4):

Довольно круто, да? Удалите только что добавленную строку тестового кода.

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

Добавление других типов линий

Затем вам нужно найти линию, к которой мышь ближе всего, чтобы вы могли нарисовать линию наведения в этом месте.

Во-первых, в верхней части файла добавьте эту строку, чтобы импортировать математическую библиотеку, которая вам скоро понадобится:

Затем перед pygame.display.flip () добавьте этот большой кусок кода:

Вау! Это много кода. Давайте пройдемся по разделам один за другим:

  1. Сначала вы получаете положение мыши с помощью встроенной функции PyGame.
  2. Затем вы получаете положение мыши на сетке, используя тот факт, что каждый квадрат имеет размер 64x64 пикселя.
  3. Вы проверяете, находится ли мышь ближе к верху и низу или слева и справа, чтобы определить, находится ли пользователь над горизонтальной или вертикальной линией.
  4. Вы получаете новую позицию в сетке на основе переменной is_horizontal.
  5. Вы инициализируете переменную плату как boardh или boardv, в зависимости от того, что является правильным.
  6. Наконец, вы пытаетесь нарисовать линию наведения на экран, принимая во внимание, является ли она горизонтальной или вертикальной, сверху, снизу, слева или справа. Вы также проверяете, не выходит ли линия за пределы поля. Если это так или линия уже нарисована, вы не рисуете линию при наведении курсора.

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

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

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

Для этого вы собираетесь использовать встроенную функцию мыши PyGame, которая представляет собой просто pygame.mouse.get_pressed () [0]. Функция возвращает либо 1, либо 0, в зависимости от того, нажата ли кнопка мыши в данный момент.

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

[spoiler title = "Решение"] Добавьте это сразу после последнего блока кода, определяющего поведение при наведении курсора:

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

Однако одна проблема заключается в том, что если вы щелкнете в нижней части экрана (ниже, где нарисованы поля), игра выйдет из строя. Посмотрим, почему это так. Когда что-то выходит из строя, обычно выдается отчет об ошибке в Терминале. В этом случае отчет выглядит так:

Эта ошибка говорит о том, что панель массива, к которой вы пытались получить доступ, не доходит до того места, где вы щелкнули. Помните переменную isoutofbounds? Это пригодится здесь. Просто измените это:

Теперь, если вы попытаетесь щелкнуть мышью за пределами доски, игра не вылетит. Хорошая работа - вы только что продемонстрировали слово «отладка»!

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

Последние штрихи

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

Добавьте это в конец initGraphics ():

Теперь, когда ваше изображение загружено, давайте нарисуем каждую из 49 точек на экране. Добавьте это в конец drawBoard ():

Хорошо, хватит кода! Пришло время для пробного запуска. Запустите игру, и вы должны получить более красивую сетку.

Далее, давайте разместим проекционный дисплей или HUD внизу экрана. Во-первых, вам нужно создать метод drawHUD (). Добавьте этот код после drawBoard ():

Этот код также рисует фон панели оценок.

Позвольте мне рассказать о том, как PyGame обрабатывает шрифты. Есть три шага:

  1. Сначала вы определяете шрифт с заданным размером.
  2. Затем вы вызываете font.render («ваш текст здесь»), чтобы создать поверхность для этих букв в этом шрифте.
  3. Затем вы рисуете поверхность так же, как изображение.

Теперь, когда вы это знаете, вы можете использовать эту информацию, чтобы нарисовать следующую часть HUD: индикатор «Your Turn». Добавьте этот код в конец drawHUD ():

Также добавьте это после вызова pygame.init ():

Этот код создает шрифт, отображает его белым цветом и затем рисует на экране. Прежде чем пытаться запустить игру, добавьте это после вызова self.drawBoard ():

Запустите программу, и вы должны увидеть текст с надписью «Your Turn» внизу экрана. Если вы присмотритесь, вы также можете увидеть красиво текстурированный фон.

Это здорово, но вам все равно нужно добавить индикатор после текста «Your Turn», чтобы игрок знал, что это его раунд.

Однако прежде чем вы это сделаете, вы хотите, чтобы игра знала, чей сейчас ход. Убедитесь, что он знает, добавив это в конец __init__:

Теперь об индикаторе. Добавьте это в конец drawHUD ():

Запустите игру, и вы увидите зеленый индикатор очков. Вы можете вычеркнуть это из своего списка дел.

Затем давайте добавим текст для счета каждого игрока. Инициализируйте переменные для двух оценок, прикрепив это к концу __init__:

Здесь вы также добавляете еще одну переменную, которую будете использовать позже на этом шаге.

Помните, как добавлять текст? Вы будете делать то же самое, что и раньше, но с шрифтами другого размера. Добавьте это в конец drawHUD ():

Запустите игру, чтобы проверить свою работу.

Теперь вы официально закончили с HUD. На стороне клиента есть еще пара вещей, так что терпите меня.

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

Сначала инициализируйте другой массив, добавив его в конец __init__:

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

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

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

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

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

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

Но чтобы убедиться, что это работает, попробуйте вызвать метод finished () в последней части __init__. Вы должны получить игру поверх экрана, который выглядит как изображение справа.

Куда пойти отсюда?

Вот исходный код из руководства.

Поздравляю! Вы завершили клиентскую часть очень организованной и красивой игры. Это, конечно, не конец, ведь вы не реализовали никакой игровой логики, но на стороне клиента поработали отлично!

Теперь вам стоит взглянуть на вторую часть этого руководства, посвященную серверной стороне, и вы наконец начнете делать эту игру по-настоящему многопользовательской!

Новости спорта

Изначально сайт создавался для пользователей со всех стран мира. Международный домен ориентирован на самых разных пользователей. Страницы сайта переведены на 46 языков, среди которых есть и азербайджанский. Это выгодно выделяет платформу на фоне конкурентов, так как многие из них либо не работают на территории данной страны, либо не имеют местной локализации.

Больше новостей