Photon: Базовый мультиплеер

другие уроки, мануалы, советы по Construct 2

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 02:27

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

Итак, нам понадобится AppID (который можно получить после регистрации на сайте Фотона, на панели Realtime Dashboard) и плагин Photon.

 Заготовка проекта
Теперь переходим непосредственно к игре. Перед запуском Констракта не забываем установить плагин Photon. Затем создаем новый проект и начинаем с клиентской части: создаем нашего персонажа. добавляем ему управление (я буду использовать 8Direction на WASD) и ScrollTo (изначально будет отключен, включим в процессе).
Я не стану объяснять, как настраивать контроллер персонажа и прочие элементарные вещи, ведь ты читаешь этот урок по мультиплееру, а это значит, что базовые навыки создания игр у тебя должны быть.
Итак, получилось у нас вот такое:
Изображение
Да вот, собственно, и вся заготовка. Дальше будем работать непосредственно с Фотоном.

 Часть 1: Подключение и синхронизация положения персонажей
Окей, теперь добавляем в проект заранее установленный плагин Photon, выбираем его и в окне Properties вставляем свой AppID. Сразу хочу сказать, что Фотон - это такой сервер/плагин/сервис, который основан на ивентах (не путать с ивентами Констракта), т.е. схема такая: [сделал что-то - отправил данные остальным игрокам через ивент]; [получил ивент - обработал его/сделал что-то].
Изображение
Дальше - добавляем переменную объекту Player. Пусть это будет UserID. Она будет использоваться для идентификации объекта игрока.
Теперь уже начинаем работать с ивентами:
На старте сцены/лайаута уничтожаем объект игрока и подключаемся к серверу
Изображение
Затем входим в случайную комнату. Если таких нет - создаем свою (я решил пропустить лобби и ручное создание комнаты, у меня все игроки входят в одну комнату)
Изображение
Если вход в комнату прошел успешно - создаем ивент Фотона (я упоминал о них чуть выше)
Изображение
Вот так выглядит окно этого ивента
Изображение
Code - это идентификатор ивента. Служит для выполнения действий именно того ивента, который был получен. Блин, даже не знаю как описать правильно. Короче, у меня так: ивент №1 - создание игрока; ивент №2 - перемещение игрока. К концу туториала вы поймете, что я пытаюсь объяснить.
Data - информация, которую мы будем передавать. Я влепил все в одну строку, которую потом разберу при помощи tokenat'а. Выглядеть это будет так: мойID|стартовое_положение_по_Х|теперь_по_Y|и_еще_angle
Receivers - это получатели. Можно отправить всем/All (и себе в том числе), остальным/Others (всем кроме тебя) и МастерКлиенту (сам в этом не разобрался, но думаю это что-то вроде хоста из стандартного плагина мультиплеера).
Все, остальные параметры нам пока не нужны.

Мы отправили ивент, но обработать его не сможем. Непорядок. Сейчас будем учиться обрабатывать входящие ивенты.
Изображение
Теперь давайте разберем. При получении ивента с кодом 1 мы выполняем такие действия:
Создаем объект игрока по координатам из ИвентДаты. Тут нам поможет tokenat.
Это выражение разбивает строку на части и возвращает запрашиваемую часть. Работает по такой схеме [tokenat(строка, индекс, сепаратор)]. В нашем случае:
строка - это Photon.EventData
индекс - это порядковый номер элемента (0 - ID_игрока; 1 - Х; 2 - Y; 3 - Angle)
сепаратор - это символ, который служит разделителем для элементов (я использовал вертикальную палку "|")
С этим вроде разобрались, возвращаемся к созданию игрока.
Изображение
Координаты вытаскиваем из Photon.EventData при помощи tokenata и конвертируем из строки в число при помощи int().
Аналогичным способом устанавливаем Angle и переменную UserID.
Теперь в под-ивенте сравниваем переменную UserID и наш ID (т.е. если UserID созданного игрока равен нашему ID - это наш игрок) и включаем камеру ScrollTo.
Также нужно добавить кое-что в разделе управления. Это нужно для того, чтоб мы могли контролировать только нашего игрока (игрока, чей UserID равен нашему ID)
Изображение

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

Теперь нужно сделать так, чтоб при подключении к комнате мы видели других игроков. Делается это так:
Изображение
Если мы уже находимся в комнате и кто-то другой подключился - мы отправляем ему ивент №1 с нашими текущими данными. Только теперь нужно отправить не всем игрокам, а одному:
Изображение
Параметр TargetActors позволяем нам отправлять ивенты конкретным игрокам. В нашем случае это Photon.ActorNr. Только не забываем сконвертировать в строку при помощи str(). Без этого не прокатит.

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

Начну с перемещения.
Изображение
Если персонаж движется и этот персонаж наш - отправляем всем остальным игрокам ивент №2 с нашими текущими данными:
Изображение
Хорошо, данные мы отправили, но их же еще и обработать нужно.
Изображение
Если мы получили ивент №2 и UserID какого-то персонажа равен ID из Photon.EventData - двигаем этого персонажа по координатам из Photon.EventData.

Теперь самая маленькая часть уничтожение отключившегося игрока.
Изображение
Если игрок отключился и у нас на уровне есть персонаж, у которого UserID равен ID отключившегося игрока - уничтожаем этого персонажа.

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

 Часть 2: Чат и система боя
Передвижение и синхронизация сделаны, а в этой части мы будет делать чат и систему боя (выстрелы, хп, смерть и респаун).
В первую очередь мы должны убрать у объекта Player поведение Solid (это поможет избежать некоторых багов) и ограничить кол-во отправляемых ивентов при передвижении. По-умолчанию отправляется 60 в секунду, но это много. Нам хватит и 20.
Изображение
Теперь добавим чат. Создаем 2 текстбокса: один для отображения сообщений (ChatBox), а другой - для ввода сообщения (ChatString). Самостоятельно устанавливаем их размер/стиль/положение/etc. Я эти два текстбокса переместил на отдельный слой UI (у которого параллакс на нулях) и запихнул в нижний левый угол при помощи Viewport'ов.
Изображение
Теперь делаем так, чтоб при нажатии на Enter мы отправляли сообщение и очищали строку ввода.
Изображение
Вот так выглядит окно ивента:
Изображение
В строке Data пишем свой ID в квадратных скобках и текст из ChatString. Отправляем всем/all.

Теперь обрабатываем полученное сообщение:
Изображение
Добавляем полученные данные в окно чата (ChatBox) и перелистываем в самый низ.
На этом создание чата окончено.

Теперь система боя. Тут будет сложновато. Самому потребовалось прилично времени потратить, чтоб разобраться в этом.
Добавляем в проект плагин Mouse. Затем в разделе управления делаем так, чтоб при зажатии ЛКМ наш персонаж поворачивался к ней:
Изображение
Теперь добавим выстрелы. Если зажата ЛКМ - персонаж будет каждые полсекунды спавнить пулю. Делать мы будем это через ивент, чтоб у всех игроков пули спавнились синхронно.
Изображение
Вот окно ивента:
Изображение
Передавать будем только свой ID и угол поворота персонажа. Отправляем опять всем/all.

Теперь давайте обработаем этот ивент
Изображение
Сперва создадим объект Bullet и добавим ему переменную UserID. Теперь если мы получаем ивент выстрела и у нас есть персонаж с ID из ИвентДаты - поворачиваем этого персонажа на угол из ИвентДаты и спавним объект Bullet. Переменной объекта Bullet даем значение из ИвентДаты (это нужно для проверки попадания).

Теперь займемся самой проверкой попаданий. Будем это проверять через столкновение объекта Bullet с объектом Player.
Изображение
Первый под-ивент: если ID пули не равен нашему ID (т.е. это не наша пуля) и ID персонажа не равен ID пули - пулю уничтожаем. Что это значит: это значит, что чужая пуля попала в кого-то, кроме своего хозяина.
Второй под-ивент: если наша пуля столкнулась с кем-то другим (не с нами) - пулю уничтожаем.
Третий под-ивент: если чужая пуля попала в нашего персонажа - уничтожаем пулю, уменьшаем кол-во ХП нашего персонажа (переменную HP нужно было заранее создать, но я конечно же забыл об этом сказать, потому говорю сейчас) и отправляем ивент с нашим ID и HP. Это нужно для того чтоб и у других игроков уменьшалось наше здоровье.
Изображение
Отправляем всем кроме себя.

Теперь обрабатываем:
Изображение
Выбираем персонажа с ID из ИвентДаты и меняем его значение HP.

Теперь перейдем к смерти. Проверятся будет только наш персонаж:
Изображение
Если здоровье нашего персонажа меньше или равно 0 - отправляем ивент смерти (№4) всем/all, в котором будет только наш ID, ждем 2 секунды (просто пример времени ожидания перед возрождением) и отправляем ивент №1 (такой же, как при входе в комнату).

Теперь обработаем ивент смерти:
Изображение
Ищем персонажа с ID равному ИвентДате и уничтожаем его.

Осталась лишь последняя маленькая деталь. Это объект Текст, который будет находиться на каждым персонажем и отображать его данные (в нашем случае - здоровье). Этот объект фигурирует во многих ивентах и дабы не заваливать вас кучей скринов - напишу словами, а как оно делается посмотрите в исходнике.
- настраиваем размер/цвет объекта Текст
- уничтожаем его on start of layout
- добавляем его в обработку ивента создания персонажа (№1), устанавливаем его положение и переменную UserID
- при получении ивента смерти (№4) уничтожаем текст вместе с персонажем
- если игрок вышел из игры - уничтожаем его Текст вместе с его персонажем
- everytick устанавливаем текст объекта Текст на значение HP персонажа, чей ID равен ID Текста
- everytick устанавливаем положение текста над головой персонажа с таким же ID

Ну, на этом все. Вторая часть окончена.


Исходник первой части
Photon tutorial.capx
(9.5 КБ) Скачиваний: 576


Исходник второй части
Photon tutorial.capx
(14.07 КБ) Скачиваний: 531
Последний раз редактировалось Bishop 07 июн 2016, 23:00, всего редактировалось 6 раз(а).
Аватара пользователя

Игродел
Сообщений: 893
Я тут с 06 июл 2015
Репутация 230 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 02:56

Для чайников пожалуйста, что делать с photon.c2addon? Ясно, архиватор.
Ваш добрый и честный Texackuu.
Приятного Вам аппетита.
Изображение
 Тык!
Когда ты помог, а тебе не поставили плюсик.
Изображение
Аватара пользователя

Участник
Сообщений: 198
Я тут с 01 июл 2014
Откуда: Казань
Skype: texackuu
Репутация 15 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 03:10

Ух, чувак, большое тебе спасибо за урок! + поставил
______________________________________
Мои игры: Think Faster
Аватара пользователя

Участник
Сообщений: 316
Я тут с 14 июн 2015
Откуда: Беларусь, Гомель
Репутация 6 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 04:06

Отправил плюс, спасибо большое
В работе над многим
Аватара пользователя

Участник
Сообщений: 639
Я тут с 28 июл 2015
Откуда: Комсомольск-на-Амуре
Репутация 19 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 07:18

Texackuu, давно пора знать про c2addon:
выриант 1) просто перетащить в окно констракта.после этого перезапустить констракт
вариант 2) переименовать в zip, распаковать, скопировать в нужную директорию (plugins или behaviors)
Аватара пользователя

Администратор
Сообщений: 2406
Я тут с 06 сен 2012
Откуда: Санкт-Петербург, Южно-Сахалинск
Skype: sirg1987
Репутация 268 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 10:42

Bishop, а не затратно 60 раз в секунду отправлять данные всем игрокам?
По всем вопросам писать в скайп DeXVinogradov
Аватара пользователя
DeX

Игродел
Сообщений: 2418
Я тут с 13 дек 2014
Откуда: Краснодар
Skype: DeXVinogradov
Репутация 480 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 10:54

DeX, этот урок делался больше для того, чтоб продемонстрировать игровую логику Фотона. Вопрос оптимизации я решил оставить на потом. Думаю, 10-20 раз будет самое то.
Аватара пользователя

Игродел
Сообщений: 893
Я тут с 06 июл 2015
Репутация 230 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 12:32

Bishop, Ты что то напутал с управлением в примере. Но + все равно поставил:) Спасибо огромное! :good:
Аватара пользователя

Участник
Сообщений: 40
Я тут с 03 июл 2015
Репутация 1 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 13:01

LesPaul98, что именно я напутал? У меня все работает отлично.
Аватара пользователя

Игродел
Сообщений: 893
Я тут с 06 июл 2015
Репутация 230 [ ? ]

Сообщение Photon: Базовый мультиплеер
» 08 авг 2015, 13:13

Bishop, не знаю как в исходнике... Он у меня :biggrin: почему то :biggrin: не открывается.
gif1.gif
Аватара пользователя

Участник
Сообщений: 40
Я тут с 03 июл 2015
Репутация 1 [ ? ]



Вернуться в Другие уроки по Construct 2

Сейчас эту тему просматривают

Зарегистрированные пользователи: нет зарегистрированных пользователей

Наверх