Тема моей статьи — разработка клиент-серверного приложения на Ас3. В этой статье я постараюсь поделиться основными моментами с которыми я сталкивался при создании таких приложений. Надеюсь, эта статья окажется полезной.
Что содержит статья: • Основные моменты при разработке клиентской части. • Понятие игрового протокола. Выводим протокол для нашей будущей игры. • Разработка клиентской части, создание игрового поля. • Программирование серверной части, обработка данных, синхронизация. • Доработка клиентской части. It's Still Alive!
Основные моменты при разработке клиентской части. Мы будем делать приложение «Рисовалка», когда несколько человек в режиме реального времени могут рисовать на одном флеш объекте. Пакет – набор данных «упакованных» нашим протоколом. В дальнейшем я буду использовать только это понятие.
Понятие игрового протокола. Выводим протокол для нашей игры. Игровой протокол не имеет ничего общего с протоколами передачи данных, он имеет совсем другой смысл. Примерно такой: Игровой протокол — метод упаковки данных для передачи их серверу. Смысл упаковки данных – оптимизация. При правильном подходе наш сервер сможет быстрее обрабатывать данные и совершать нужные операции в более краткие сроки.
Что из себя представляет игровой протокол? Я пишу эту статью на примере создания простейшего клиент-серверного приложения с движением объектов. Для того, чтобы добиться отображения движения одного клиента у остальных, мы должны сообщать серверу текущие координаты, а он в свою очередь передавать их другим клиентам. Как будет выглядеть протокол:
Теперь подробнее: • ID — идентификатор пакета. Позднее, при разработке клиента и сервера мы столкнемся с проблемой определения пакетов (что и какой значит). • PId – ид игрока. • X, Y – новые координаты. Вот эти данные мы и будем отдавать серверу.
Разработка клиентской части, создание игрового поля. Давайте определимся с поставленной задачей. У нас есть игровое поле и наш персонаж. Но мы же делаем сетевую игру! А это значит? Это значит то, что таких персонажей может быть множество. Для этого мы будем использовать динамическое создание объектов. Для начала набросаем функции рисования, повесим движение/клик мыши на события:
Опишем переменные:
Code
private var nowdraw:Boolean = false; private var server:String = "localhost"; private var serverPort:int = 443; private var colorClient:uint; private var serverSocket:XMLSocket = new XMLSocket(); private var MyId:String = "0"; private var TexteField:TextField = new TextField();
Как вы видите, я повесил на события: нажатие кнопки мыши, перемещение курсора, отжатие кнопки – 3 функции.
Теперь добавим эти функции:
Code
public function start(event:MouseEvent):void { graphics.lineStyle(1,colorClient); graphics.moveTo( mouseX, mouseY); nowdraw = true; }
public function draw(event:MouseEvent):void { if(nowdraw){ graphics.lineTo(mouseX, mouseY); } }
public function stop(event:MouseEvent):void { nowdraw = false; }
Переменная nowdraw – булевая переменная, её значение определяется в зависимости от того нажата или отпущена кнопка мыши. Если значение nowdraw равняется true, тогда при движении мыши мы рисуем линии.
Добавим функцию подключения к серверу:
Code
public function connectionserver():void { serverSocket.addEventListener(Event.CONNECT, serverConnected); serverSocket.addEventListener(Event.CLOSE, serverDeconnected); serverSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, serverForbidden); serverSocket.addEventListener(DataEvent.DATA, serverRecv); serverSocket.connect(server, serverPort); }
На каждое событие мы повесили функции. Ниже эти функции.
Функции «повешенные» на события с сервером:
Code
private function serverConnected(e:Event):void { TexteField.text = "Подключено ;)"; addChild(TexteField); }
private function serverDeconnected(e:Event):void { TexteField.text = "Вы были отключены от сервера ;("; addChild(TexteField); }
private function serverForbidden(e:Event):void { TexteField.text = "Невозможно подключиться к серверу ;("; }
Пока все.
Программирование серверной части, обработка данных, синхронизация.
Серверную часть я буду писать на языке Python. Но вы можете писать на чем угодно, принцип одинаковый.
Используемые модули: twisted.
Давайте условно определимся с идентификаторами пакетов: • 02 – подключение к серверу, в этом пакете сервер будет передавать ид пользователя и цвет его линий. • 03 – пакет, содержащий координаты мыши в момент нажатия. • 04 – пакет, содержащий координаты мыши при движении курсором (отправляется, когда зажата ЛКМ).
Теперь набросаем простой пример сервера:
Code
from twisted.internet.protocol import Protocol, Factory from twisted.internet import reactor
Что мы сделали? Мы принимаем наши пакеты и разбиваем их согласно нашему протоколу: id + x + y Далее, если это пакет 2 – мы вернем клиенту его ид и цвет (черный). Если это пакет 3 – отправим всем клиентам пакет о нажатии кнопки мыши. Если это пакет 4 – отправляем всем клиентам пакеты о координатах мыши.
Дорабатываем клиентскую часть:
Добавим функцию формирования и отправки данных:
Code
private function query(id:int, x:int, y:int):void { var packet:ByteArray = new ByteArray(); packet.writeByte(id); packet.writeByte(1); packet.writeUTFBytes(MyId); packet.writeByte(1); packet.writeUTFBytes(x.toString()); packet.writeByte(1); packet.writeUTFBytes(y.toString()); serverSocket.send(packet); }
Эта функция принимает параметры: id, x, y, потом формирует пакет и отправляет на сервер.
Добавим вызов этой функции к событию «подключено»:
Code
private function serverConnected(e:Event):void { TexteField.text = "Все ок ;)"; addChild(TexteField); query(2, 0, 0); }
Как вы видите, мы отправили серверу пакет с идентификатором «2».
Теперь допишем функцию принятия пакетов, введем условия и реакцию на них:
Code
private function serverRecv(e:DataEvent):void { var loc1:*; var loc2:*; var loc3:*; var loc4:*; var loc5:*; var x:*; var y:*; loc1 = e.data; loc2 = loc1.split(String.fromCharCode(1)); loc3 = loc2[0].charCodeAt(0); loc4 = loc2[1]; loc5 = loc2[2]; if (loc3 == 2) { colorClient = loc4; MyId = loc5; TexteField.text = "Теперь вы можете рисовать!"; this.addChild(TexteField); initGraph(); } if (loc3 == 3) { if (loc5 != MyId) { graphics.lineStyle(1, loc4); x = loc2[3]; y = loc2[4]; if (x) {graphics.moveTo(x, y);} } } if (loc3 == 4) { if (loc5 != MyId) { graphics.lineStyle(1, loc4); x = loc2[3]; y = loc2[4]; if (x) {graphics.lineTo(x, y);} } } }
Здесь ситуация как с сервером, с точностью да наоборот. Каждый раз, когда приходит пакет и идентификатором 3, мы перемещаем точку начала рисования. Каждый раз, когда приходит пакет с идентификатором 4, мы начинаем рисовать линию (согласно координатам этого пакета).
Чтобы сервер получал эти данные, мы будет отправлять пакеты с координатами в процессе рисования. Для этого немного изменим функции рисования:
Code
public function start(event:MouseEvent):void { graphics.lineStyle(1,colorClient); graphics.moveTo( mouseX, mouseY); query(3, mouseX, mouseY); nowdraw = true; }
public function draw(event:MouseEvent):void { if(nowdraw){ graphics.lineTo(mouseX, mouseY); query(4, mouseX, mouseY); } }
Теперь добавим в функцию Main:
Code
TexteField.width = 300; connectionserver();
Запустим сервер, 2 окошка с клиентом и попробуем *-*
На этом все. Код в статье демонстрирует взаимодействие клиента с сервером. Обмена данными, работы нескольких человек в режиме реального времени. Исходный код сервера и клиента: скачать
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «Разработка клиент-серверного приложения на Ас3», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.
По большому счету, инфу о работе с сокетами можно найти хоть в любимой новичками книге К.Мука, хоть в официальной документации от Adobe. Лучше бы рассказали о том, как эти самые сокеты поведут себя в реально действующей сети. Потому как описанный Вами вариант в реальных условиях будет падать или выдавать некорректный результат, когда Ваши пакеты данных начнут приходить по 3 пакета в одном TCP пакете или даже по полтора пакета.
Проблема нескольких пакетов решается допиливанием сервера. Возможно, в будущем, я напишу еще одну статью, где на примерах покажу как мною решались подобные фейлы.
Документации полно, писать очередной многостраничный мануал по сокетам нет смысла. Я поставил конкретную задачу - работа с координатами. И на примере рисовалки я показал как это делается, код предельно прост.