Результаты поиска
| |
Nanotentacle | Дата: Среда, 12 Февраля 2014, 09:32 | Сообщение # 1 | Тема: Ищу художника, геймдизайнера |
был не раз
Сейчас нет на сайте
| Добрый день Некоторое время веду разработку игры для социальной сети. Игра представляет из себя пошаговую стратегию в стиле настольной игры Battletech (известной по играм Mechwarrior), правда, с достаточно сильно переработанной идеей.
На данный момент уже есть работающий (правда, не окончательно оттестированный) вариант сервера, я представляю, что еще нужно сделать в игре для запуска. Клиент пока сделан на уровне скелета и малопрезентабелен. Поэтому необходима помощь.
Во-первых, нужен геймдизайнер. Задачи геймдизайнера - работа над вооружением и боевой техникой в игре, плюс принятие участия в обсуждении намечающихся изменений или введений новых систем в игру. Я понимаю, что многим хочется, чтобы я работал над их проектом и говорить мне, что стоит изменить в намеченным мной концепте, и я готов прислушиваться к небольшим и аргументированным изменениям. Но я не готов менять свой проект на ваш, а также не готов вносить глобальные изменения в то, над чем я работаю. Это обусловлено в первую очередь тем, что если я буду переделывать базовые вещи, то проще писать новую игру. Так что если вы готовы работать над тем, что уже имеется - я буду рад работать с вами плечом к плечу.
Во-вторых, требуется художник. Оплата услуг не подразумевается, но все зависит от качества выдаваемого результата. В плане графики игра будет разбита на две части: основные меню с кнопками и крупными картинками, и боевая часть с изометрической картой, тайлами и небольшой техникой.
Заинтересованным готов провести экскурсию по "преальфа" версии игры.
Если есть желающие поучавствовать - буду рад вашей помощи. Думаю, мы с вами сможем создать команду, которая осуществит еще много проектов.
Добавлю небольшой скриншот из боя. Строго прошу не судить, многие вещи пока сделаны на скорую руку. Например, таблицы с хитпоинтами планируется сделать в графическом виде. Карта тестовая, в дальнейшем на ней будут различные объекты с бонусами, вроде бункера, а также значительно увеличен ее размер:
Сообщение отредактировал Nanotentacle - Среда, 12 Февраля 2014, 11:04 |
|
| |
Nanotentacle | Дата: Среда, 04 Сентября 2013, 19:20 | Сообщение # 2 | Тема: Требуется гейм-дизайнер |
был не раз
Сейчас нет на сайте
| Итак, имеются планы на пошаговую стратегию, которая будет размещена в социальных сетях. Пока что над проектом я работаю в одиночку, на данный момент уже есть скелет игры, частично готов сервер и база данных. Ураганную скорость разработки обеспечить я не в состоянии, предупреждаю сразу. Работы, конечно, осталось много, но начинаю ощущать, что требуется помощь в гейм-дизайне, так как не всегда хватает времени и возможности обдумать все детали игры.
Что требуется от геймдизайнера: 1. Хорошо отвечать на вопросы "Зачем?", "Почему?", "Как?" и тому подобные. 2. Опыт не обязателен, но приветствуется. 3. Очень желательно наличие опыта и хотя бы поверхностное знакомство с настольными варгеймами, такими как Warhammer и Battletech.
На самом деле нужен человек, перед которым я смогу поставить вопросы о том, как правильно осуществить тот или иной элемент игры, как отладить баланс и тому подобное. Оплату не гарантирую, но готов рассмотреть варианты. В любом случае, если я плачу вам за работу до запуска игры, то о процентах с дохода не идет никакой речи, а если работаете на энтузиазме - то в случае успеха могу гарантировать ваш процент.
|
|
| |
Nanotentacle | Дата: Среда, 26 Июня 2013, 17:54 | Сообщение # 3 | Тема: Обратится к свойству объекта на другой форме |
был не раз
Сейчас нет на сайте
| А какую именно ошибку выдает? Access violation? Если да, то надо смотреть, как и в какой момент у тебя создается CheckBox1
|
|
| |
Nanotentacle | Дата: Пятница, 28 Декабря 2012, 14:03 | Сообщение # 4 | Тема: Delphi:Вопрос-Ответ |
был не раз
Сейчас нет на сайте
| Там именно a := random(2000). Перед всеми рандомами стоит randomize.
Я и раньше замечал, что с помощью рандома не получается делать случайные события. Допустим, после x := random(100) все попытки разделить вероятности, например, по 20 путем if x <= 20 if (x > 20) and(x <=40) ни к чему не приводило, приходилось подбирать некие коэффициенты, чтобы получать те самые 20 процентов, которые мне требовались. Возможно, дело в том, что у меня не 10 миллионов итераций, а порядка 100-1000.
Сообщение отредактировал Nanotentacle - Пятница, 28 Декабря 2012, 14:08 |
|
| |
Nanotentacle | Дата: Пятница, 28 Декабря 2012, 09:15 | Сообщение # 5 | Тема: Delphi:Вопрос-Ответ |
был не раз
Сейчас нет на сайте
| Да, сейчас проверил собственноручно, вы правы. Но тогда возникает вопрос: в моей программе при создании объекта вычисляется случайная величина, и каждый раз она оказывается как раз в промежутке 1700-2000. Не было ни одного случая, чтобы значение оказывалось меньше 1700. С чем такое может быть связано?
|
|
| |
Nanotentacle | Дата: Четверг, 27 Декабря 2012, 06:59 | Сообщение # 6 | Тема: Delphi:Вопрос-Ответ |
был не раз
Сейчас нет на сайте
| Встроенный в Delphi 7 генератор случайных чисел дает достаточно кучный результат. Если мне надо получить случайное число из диапазона 0-2000, то с вероятностью в 95% эти числа попадают в промежуток 1700-2000 (randomize используется, если что). Есть ли более "случайные" генераторы для Делфи или лучше написать его самостоятельно?
Сообщение отредактировал Nanotentacle - Четверг, 27 Декабря 2012, 06:59 |
|
| |
Nanotentacle | Дата: Четверг, 13 Декабря 2012, 12:43 | Сообщение # 7 | Тема: Delphi:Вопрос-Ответ |
был не раз
Сейчас нет на сайте
| Возникла необходимость поработать с указателями(pointer) и хотелось бы узнать, как делать правильно. Ситуация такова: имеется динамический массив данных. При удалении элемента не из конца массива происходит смещение всех элементов на один в сторону уменьшения путем простого присвоения. Т.е., в моем понимании, происходит копирование элемента в новую "ячейку" оперативной памяти, а старая "ячейка" затирается данными от следующего элемента. При такой операции расположение в памяти меняется, и указатели, которые были расставлены ранее, уже ведут в лучшем случае не к требующемуся элементу. Внимание, вопрос: правильно ли я понимаю ситуацию с указателями, и если да, то есть ли возможность присвоить переменной не значение, а адрес в памяти?
UPD: Вот дочитался до некоторых вещей. Судя по одному из источников, при переназначении длины динамического массива, он переписывается в другой участок памяти, соответствующий новому размеру, а старый участок памяти высвобождается. Однако, моими экспериментами с указателем это не подтвердилось. Указатель продолжал ссылаться на нужное мне место даже после переназначения длины массива. Кто прав?
Плюс, судя по всему, у меня было неправильное представление самого понятия динамического массива. Доступные для управления элементы как раз и являются типизированными указателями на память, а не переменной. Тогда не совсем понятно, что происходит при присваивании одного элемента другому внутри массива.
SOLVED: Все решено. В моем случае, после каждого изменения внутри массива буду переписывать связанные с ними указатели. Единственный вариант, на мой взгляд.
Сообщение отредактировал Nanotentacle - Четверг, 13 Декабря 2012, 14:25 |
|
| |
Nanotentacle | Дата: Вторник, 11 Декабря 2012, 11:21 | Сообщение # 8 | Тема: Free Pascal: проеверка с 2-мя вариантами |
был не раз
Сейчас нет на сайте
| В данном случае case неприменим. Он не работает со String. "Ordinal expression expected" - если не вдаваясь в буквоедческий перевод, то он требует, чтобы переменная была исчислимого типа. Т.е., например, integer, каждый элемент которого можно последовательно посчитать (один, два, три и т.д.). В данном примере придется обойтись конструкцией if - then.
|
|
| |
Nanotentacle | Дата: Воскресенье, 09 Декабря 2012, 10:16 | Сообщение # 9 | Тема: Delphi:Вопрос-Ответ |
был не раз
Сейчас нет на сайте
| Если не ошибаюсь, то движок - это все же набор классов, иногда и компонентов, которые позволяют любому программисту создавать игры, не вникая в суть того же DirectX или OpenGL, пользуясь лишь методами уже созданных классов. По сути же, если глядеть в глубину любого движка, то чаще всего они как раз и представляют собой те самые DirectX и\или OpenGL. По сути, как для приятной и комфортной езды на автомобиле не требуется знать, как работает двигатель внутреннего сгорания, так обстоит дело и тут. Не стоит только забывать, что если не умеешь рулить и выбирать скорость в поворотах, то это закончится плачевно.
С другой стороны, если ты сделаешь те же самые классы и компоненты, которые использовали бы, скажем, классический TBitmap и TImage, и значительно упрощали создание изометрической игры для всех, кому лень вникать в суть этого TBitmap, то думаю да, это тоже можно будет назвать движком. TBitmap тут лишь для красного словца, использовать его в играх я бы очень не рекомендовал.
Сам я начинал создание игр сначала с простого - DelphiX, потом мне стало нехватать функционала и я попробовал Andorra2D. Жаль, что оба этих движка приказали долго жить. В общем-то, если преследуешь целью только сделать игру, а не движок, то я бы рекомендовал поискать что-то подобное.
|
|
| |
Nanotentacle | Дата: Четверг, 29 Ноября 2012, 15:53 | Сообщение # 10 | Тема: Создание сервера на Delphi |
был не раз
Сейчас нет на сайте
| Успехи пока что меня вдохновляют :). Бота почти дописал, скоро начну тесты. Дополнительно продолжил искать возможные подводные камни, о которых сразу не подумал. Про динамические списки - это великолепно, я подумаю, как их можно применить в моем случае. На самом деле, о таком простом и элегантном способе я и не думал. Дополнительно мне посоветовали почитать про хэш-списки, тоже сейчас вникаю и разбираюсь, как они могут мне помочь.
Поскольку эту тему я создал не только для того, чтобы получать советы (которые, надо сказать, во многом меня сильно радуют и позволяют взглянуть на свой же проект со стороны), но и для того, чтобы если кто-то решит пойти по моим стопам, то он мог ознакомиться с материалом и лучше понимать, что ему предстоить делать.
Итак, хотелось бы отписаться о программе-боте и небольшом изменении сетевого движка. Программа-бот будет представлять собой динамически создаваемые ClientSocket, их кол-во зависит от моих потребностей. Каждый бот-клиент присоединится к серверу, и будет совершать действия, похожие на действия игрока - давать команды на перемещения, на стрельбу, в идеале - умирать и воскрешаться. Зная структуру запросов к серверу, ничего сложного здесь нет. Хватит всего лишь задать обработку пары-тройки случайных событий.
А вот с сетевым движком все интереснее. Пока что я провожу испытания на своей же машине, т.е. клиент подключается к адресу 127.0.0.1. В данной ситуации пинг является если не нулевым, то минимальным. Дальше я буду рассказывать достаточно очевидные вещи, но они могут оказаться для кого-нибудь полезными. Ранее я брал допущение (замечу сразу, это неправильное допущение и оно всегда приведет к неприятностям, если им пользоваться в реальном сервере), что пинг в игре отсуствует. Т.е. сервер получает от игрока информацию о том, что игрок сменил направление движения, внес информацию об этом в свои переменные и отправил игроку сообщение, где он должен находиться на момент этой смены. Поскольку задержки были равны нулю, это приводило к тому, что обсчет движения, столкновения с объектами на карте я мог производить на сервере, не задействуя клиент.
Однако, это все никуда не годится. В реальном интернете нельзя не учитывать пинг игрока. Т.е. игрок будет всегда находиться в некотором запаздывании от сервера. И чтобы это запаздывание нивелировать, клиент обсчитывает перемещение и столкновения самостоятельно, априори считая свои расчеты верными. Но тут мы сталкиваемся с еще одной проблемой - расчеты на сервере и у клиента идут не одинаково. Это может быть обусловлено разными факторами. Тем более, что клиент и сервер пишутся на разных языках программирования. Поэтому приходится в действия клиента вносить поправки, которые при правильно подобранных скоростях перемещения и правильно составленных формулах столкновения будут очень малыми и для игрока незаметными.
На данный момент я полностью сменил систему общения клиента и сервера во всем, что касается перемещения. Теперь в пакете с сообщением о смене направления движения клиент пересылает идентификатор - число в шестнадцатеричной форме - и запоминает координаты, на которых находился игрок в этот момент. Пока пакет дойдет до сервера и вернется обратно, успеет пройти некоторое время (иногда достаточно значительное), и данные с сервера потеряю сиюминутную актуальность, т.к. игрок в клиенте мог, и даже скорее всего уехал с той позиции, где он посылал данные. Поэтому при получении пакета клиент сравнивает идентификатор, находит его в массиве и проводит сравнение координат собственного массива и полученных данных. Поправка будет равна разности каждой из координат. В идеале, для игрока эта поправка будет незаметна.
А вот что делать с выстрелом я пока не придумал. На данный момент обсчет выстрела, столкновения, взрыва и повреждений ведет сервер, сообщая об этих события клиенту. Но система, как я и писал выше, нежизнеспособна. Видимо, придется доверить клиенту обсчет и этих вещей. Хотя обсчет повреждений я намерен оставить серверу, даже если информация будет приходить с задержкой. Я очень надеюсь, что мне удастся сделать так, что столкновения снаряда и игрока и на сервере, и на клиенте будут максимально приближены друг к другу и тогда ситуации, когда клиент показывает игроку, что он попал и повредил соперника, а сервер это не подтверждает, будут крайне редки. Возможно, есть более элегантные способы?
В дальнейшем, когда проект будет все ближе подходить к полной реализации, я буду стараться давать все больше информации и выдавать больше технических моментов.
Update: После полунедельного затишья продолжил работу. Сейчас, как и хотел, переписал сервер и привел его в более удобный вид. Начал оптимизировать с самого начала - например, определился с необходимыми типами данных, чтобы не было лишнего выделения памяти. Как результат - сервер начал есть в два раза меньше оперативной памяти, а код выглядит более строго и "архитектурно". Последовал совету TimKruz и уменьшил код запроса до одного символа. На данный момент хватает за глаза.
Также попробовал перейти к динамическим массивам, но все же отказался от этой идеи. Слишком много нюансов, которые я пока не могу предсказать. Например, насколько быстро будет создание-удаление игроков. Теперь у меня есть константы, которые задают размер массивов, так что изменить из емкость я могу буквально одним росчерком пера.
Также поработал с клиентом. Теперь он не привязан напрямую к серверу, а лишь сверяется с ним. Уже все выглядит достаточно плавным и приятным, однако в этом вопросе есть куда стремиться. Очень здорово удалось перенести модель столкновения с объектами из сервера в клиент, в результате совпадение получилось тютелька в тютельку.
Единственный вопрос, в котором я очень хотел бы помощи - это система логгирования. Пока я приглядываюсь к MemoryStream или FileStream, но вплотную этим вопросом не занимался. Т.е. хочу вести лог на каждого игрока, на первом этапе - полный, в дальнейшем оптимизирую на хранение неопознанных пакетов или явно читерских. Но насколько это себя оправдает в плане скорости и результата с удовольствием бы от вас послушал.
Сообщение отредактировал Nanotentacle - Пятница, 14 Декабря 2012, 14:21 |
|
| |
Nanotentacle | Дата: Понедельник, 26 Ноября 2012, 09:49 | Сообщение # 11 | Тема: Создание сервера на Delphi |
был не раз
Сейчас нет на сайте
| Большое спасибо за ответ, был приятно удивлен.
Quote (TimKruz) Лучше использовать динамический список, потому что удаление элементов из середины будет быстрее. Правда, доступ к элементу только перебором всех имеющихся элементов (иногда прямого доступа к ячейке вообще не нужно, все они так и так по кругу обрабатываются), но зато быстро меняется длина, занимается памяти ровно столько, сколько нужно, и не нужен целый блок памяти, как для массивов...
По динамическим массивам да, я соглашусь. Скорее всего, при переписывании сервера перейду именно на этот вариант. Единственно, что вызывает у меня сомнения - это сложность удаления элемента из центра массива. Насколько я знаю, для этого придется обнулить сам элемент, и индекс всех вышестоящих элементов уменьшить на единицу, после чего "отрезать" из конца массива лишний элемент. По-моему, это достаточно громоздкое решение. Мб есть что-то более элегантное, про которое я не в курсе?
Quote (TimKruz) Вот запросы нужно сильно оптимизировать. Чтобы не слать огромные структуры с кучей мусора каждую миллисекунду. Только самое важное, только в свёрнутом виде. Просто интересно узнать формат запросов. В идеале это должно представлять собой строго определённый код, где каждый байт имеет своё имя и назначение. А то я где-то тут видел, как кто-то шлёт огромные XML-файлы с информацией, которую можно сжать в пару десятков байт.
Средний запрос у меня стандартизирован. Первые три байта - код команды или запроса, затем "тело" запроса с данными, со строгим размером данных. Например, при перемещении передается только четыре вектора направления в булевых переменных. Для передачи использую один байт, который передается в виде числа в шестнадцатеричной системе. Если же есть изменения в направлении (например, игрок нажал или отпустил кнопку), то передается еще две координаты положения, по 6 байт в каждой координате. Учитывая, что целая часть будет не больше 4х симоволов, точность получается приемлимая. Правда, как там ужать данные пока не сообразил и, честно говоря, не сильно и обдумывал, оставив на потом. Оптимизация - это для меня вопрос серьезный, но который я пока решил оставить до полного написания сервера.
Quote (TimKruz) Переменная типа Boolean занимает 1 байт (потому что меньше нельзя, адресуются только байты), но значение имеет только один бит. Используй битовый сдвиг. Если, например, используется 8 булевых переменных, их можно свернуть в один байт битовым сдвигом, а потом снова развернуть (для удобства использования). Но если используешь 7 булевых переменных, по-любому останется 1 "лишний" бит, который никуда не используешь, если все остальные данные занимают целые байты. Однако есть ли смысл задумываться о каком-то лишнем бите, когда скорости передачи данных гораздо быстрее?
Да, именно к такому способу я и пришел, проанализировав, как могу уменьшить объем передаваемых данных. Булевые переменные могут оптимизироваться просто великолепно, но вот что делать с float - ума не приложу. Фактически, чтобы закодировать цифру нам избыточно даже 4 бита, но при передаче данных я использую 8. Возможно, стоит перейти также в шестнадцатеричную систему, и это даст свой выигрыш.
Quote (TimKruz) Можно чисто теоретически подсчитать затраты ресурсов, но лучше напиши программу-бота, которая будет симулировать среднюю или максимальную активность игрока плюс теоретический разброс времени ответа (пинг) клиента и проблем соединения (потеря пакетов, лишние/фальшивые пакеты, резкое падение скорости или выброс игрока из игры), и подключай её к серверу (желательно, чтобы она симулировала сразу несколько игроков). Так можно быстро на практике оценить мощность сервера, оценить возможные проблемы... По-любому такой тест придётся делать перед тестом с настоящими игроками.
На данный момент как раз пишу такую программу-бота. Единственно чего опасаюсь - что мои иллюзии о том, что код написан хорошо, являются лишь иллюзиями :).
Quote (TimKruz) Не понимаю смысла многопоточности в таких ситуациях. Всё равно реально процессор параллельно обрабатывает столько инструкций, сколько у него ядер, т.е. для двухъядерного процессора реальный прирост скорости может быть только от двух параллельных потоков вместо одного, который выполняет функции этих двух, но подряд. А потоки ещё нужно синхронизировать с ядром программы и вообще контролировать, так что проще без них...
А вот тут вопрос спорный. Если я не ошибаюсь, то вопрос идет даже не в том, что они должны выполняться параллельно, а в процессорном времени. Все дальше написанное - это то, как я понимаю многопоточность. Поток, сам по себе, представляет собой программу в программе. Поэтому процессорное время выделенное на программу в общем, при применении потоков, увеличивается. Плюс, в моем исполнении один поток отрабатывает свой цикл просчетов, и после этого уходить в sleep на 30 мс, тем самым освобождая процессорное время соседнему потоку. С синхронизацией все проще. Я сейчас воплощаю систему, где основной поток и остальные потоки не используют совместных переменных, чтобы полностью избежать подвисаний и проблем. Хотя вплотную я этим вопросом не занимался, и могу ошибаться. В любом случае, попробовать на практике это стоит :).
|
|
| |
Nanotentacle | Дата: Среда, 21 Ноября 2012, 12:58 | Сообщение # 12 | Тема: Выбор движка\конструктора для онл.игры |
был не раз
Сейчас нет на сайте
| Я немного перефразирую aalla: вопрос создания игр - это не просто поиск движка и втыкивание в него своих картинок, зачастую (и я пока не встречал исключений) это трудная работа по написанию скриптов, создания полного дизайна игры и прочих крупных и мелких деталей. В любом случае, ты уже должен представлять, что такое алгоритм и обладать навыками составления этих самых алгоритмов.
Флеш - это уже язык программирования, а не движок (ну, вернее, as3 точно им является, голый флеш мало кому нужен). В общем-то, если ты собираешься писать онлайн игру, то этого будет недостаточно. Ты на нем сможешь написать только клиент. Поэтому куда полезнее будет для начала поизучать вопросы попроще, и сделать свой "Hello, world".
Ну а в дальнейшем можно почитать тут: http://gcup.ru/forum/47-2030-1
Сообщение отредактировал Nanotentacle - Среда, 21 Ноября 2012, 13:00 |
|
| |
Nanotentacle | Дата: Среда, 21 Ноября 2012, 10:13 | Сообщение # 13 | Тема: Создание сервера на Delphi |
был не раз
Сейчас нет на сайте
| Здравствуйте, уважаемые форумчане.
Месяц назад в голову ударила идея по созданию простой игры для социальной сети. Опыта воплощения, в общем-то, было совершенно немного, поэтому для начала перекопал литературу, посмотрел некоторые ключевые моменты программирования и приступил к делу. В данной теме хотел рассказать о процессе разработки серверной части, а также выслушать любые советы о том, как лучше сделать/переделать что-то в моей наработке.
Немного истории: мысль о том, чтобы делать игру, будоражит меня уже порядка трех лет. За это время периодически подчитывал различные статьи, темы о том, как правильно заниматься их разработкой. Первый проект, который я начал, закономерно окончился ничем. Весь игровой код был в одном модуле, лишь изредка разделенный на процедуры для исполнения рутинных действий. Я с трудом понимал, что такое потоки и как с ними работать. Конечно, ничего толкового выйти не могло. После того, как было выполненно несколько сторонних проектов, я сел за более глубокое изучение Делфи и ООП как такового, начал лучше разбираться в классах и смог делать более красивый код. Знаний все равно было недостаточно. Однако ощущение, что до настоящего мастерства и понимания всего мне предстоит большой путь, не отпускает меня и сейчас. Каждый новый день приносит что-то новое, дает новые знания, которые требуют переделывания всего, что уже было сделано. Но всему свое время.
Возможно, этот текст поможет кому-нибудь быстрее пройти тот путь, и не отказаться от своих мечтаний. Итак, приступим.
Работать я начал с Delphi 7, как наиболее знакомой и обеспечивающей, на данном этапе, достаточные возможности. Первым делом я определился, что хочу получить в результате: это была обычная флеш-игра (про клиент я пока ничего говорить не буду, так как не по теме, затрону только разработку серверной части), игроки могут присоединяться в игровые комнаты и вести там сражения. Максимум - 8 игроков в одной комнате. Соответственно, надо было создать классы для игрока, и для комнаты. Чтобы избежать задержек, обусловленных динамическими массивами, в основном модуле создавался массив для игроков на 1000 человек, и массив комнат на 100 комнат. Да, вполне вероятно, что это будет занимать больше оперативной памяти, но для меня на данном этапе это не сильно критично (кстати, если кто-то в курсе, подскажите, насколько это станет критичным при больших нагрузках?). Обслуживать все подключения, по первоначальному плану, должен был единственный ServerSocket, прослушивающий один порт. Само приложение хотел сделать однопоточным. Увы, в таком виде это было нежизнеспособно.
Первая моя проблема, с которой я столкнулся - незнание такой простой вещи, как pointer. Как я понял, это величайшая вещь в плане оптимизации кода и удобства разработки. Ранее, до того как я начал пользоваться поинтерами, чтобы понять, от кого же пришло то или иное сообщение на сервер, мне приходилось перерывать весь массив игроков на соответствие хэндла (тот, что я приписывал игроку при подключении и тот, что был приписан к сокету), и после определения игрока уже вел с ним беседу. Я воздаю хвалу высшим силам, что я все это поправил на первом же этапе. Особенно, учитывая, что уже в самом сокете предусмотрен поинтер, которому можно присвоить адрес соответствующего элемента массива игроков. Код становился элегантнее буквально на глазах.
Написав свой "Хэллоу ворлд" на флеше, я смог его заставить общаться с сервером. Тут столкнулся с интересной ситуацией: флеш при соединении запрашивает файл политик безопасности. Сначала я этого не знал, и не мог понять, почему же происходит дисконнект. Но, введя запрос в поисковик, быстро справился с проблемой. На первом этапе, пока я работал с одним клиентом лишь для проверки "общения" клиента и сервера, все было прекрасно. Однако, при подключении большего количества клиентов начались проблемы. Тут следует немного отклониться от темы и рассказать про "доверие" к клиенту.
Все мы знаем, что если доверить клиенту слишком много, то нечестные люди могут начать этим пользоваться и обманывать сервер, подменяя пакеты, либо вычленяя из информации, присланной сервером то, что им знать совершенно ни к чему. При этом, зачастую не очень-то и важно, каким методом шифрования вы пользуетесь. Да, я знаю, что я параноик, но хочется все сделать на совесть. Тут я видел два решения проблемы: либо дать клиенту волю, но ставить жесткие проверки на сервере, либо проводить параллельные вычисления на стороне сервера, который априори не доверяет информации с клиента. Оба варианта меня не сильно устраивали, как крайние, но склонился я ко второму варианту.
Впихнув код обработки перемещения игроков в комнате в основную программу, я значительно замедлил выполнение. Меня это не устраивало еще в тот момент, когда я осознал саму необходимость подобного "нововведения". Так что следующим этапом изучения для меня стала многопоточность. В теории все стало выглядеть великолепно. Представив, как каждая комната будет обсчитываться независимо от другой комнаты, я впал в экстаз и был в невероятном восторге. Но в очередной раз получилось "увы". Многопоточность имеет массу своих маленьких особенностей. Особенно эти особенности неприятны в том, что всегда надо синхронизировать свои действия с основным потоком, что, в свою очередь, может приводить к так называемым "бутылочным горлышкам" - это когда к одному и тому же ресурсу пытаются получить доступ сразу несколько потоков, но при этом работать с этим ресурсом может одновременно только один поток. Про полные блокировки и зависания я промолчу, т.к. на практике с ними не сталкивался.
А вот "бутылочное горлышко" дало о себе знать. Во-первых, я попытался работать напрямую с массивом игроков и комнат из потока, а во-вторых, я попытался отправлять сообщения клиентам прямо из потока, используя наш один-единственный сервер на одном единственном порту. Даже при 6ти игроках весь сервер начинало колбасить и передвижения игроков стали больше походить на пошаговую стратегию. Временным (потому как трудно предположить, что будет при большой загрузке), и на данный момент действующим, решением стало:
1) для каждого потока создать свой локальный экземпляр комнаты и игроков, играющих в ней, куда и передавать все необходимые данные из основного потока. После просчета очередной итерации полученные данные переписываются обратно в основной поток. Сейчас я обдумываю то, как же можно сделать так, чтобы избежать переписываний туда-сюда, а всю информацию хранить строго в потоке, и выгружать ее обратно только при выходе игрока из игры или из боя. Без этого, думаю, при определенном количестве комнат и игроков "пошаговость" игры неминуема. Но это теория. В общем-то, тут не вижу ничего сложного, надо только время и немного мозговой деятельности. Если вам будет интересно, потом я смогу рассказать, как и что я предприму для исправления ситуации;
2) разделить процедуры. Т.е. загрузка-выгрузка данных из основного потока происходит в отдельной процедуре и вызывается отдельно методом synchronize(), чтобы не "застолбить" массивы основного потока на время выполнения расчетов. Также отдельно происходит и сам расчет, использующий исключительно локальные переменные потока, чтобы не создавать тех самых "бутылочных горлышек".
3) для каждой комнаты создал свой сервер. Вернее, при создании комнаты сервер создается и запускается, при удалении - удаляется (что, впрочем, логично). Перестали появляться очереди в отправке сообщений клиентам. Номер порта легко определяется, и у клиента не возникает проблем с подключением.
4) Слегка оптимизировал запросы. Ранее клиент каждый обработанный фрейм (а при 50 фпс это 50 сообщений в секунду) отправлял информацию о направлении перемещения, координатах. Теперь же отправка идет исключительно при изменении направления движения. Сервер считает перемещение, и при изменениях выдает координаты игрока, где он должен находиться. В общем-то, удалось "синхронизировать" клиент и сервер по скоростям так, что отправлять клиенту его положение в каждый фрейм нет необходимости.
На самом деле вопрос оптимизации запросов мне еще только предстоит затронуть в своем изучении. Ведь, представьте, переменная типа Boolean занимает всего 1 бит. Для пересылания по сети 1го знака я использую 1 байт информации - а это в 8 раз больше, чем мне требуется! Я понимаю, что методы архивирования придуманы уже давно, и их надо изучать, но, согласитесь, до таких вещей лучше дойти своей головой и понимать, зачем оно надо. Так что еще одной задачей для себя я ставлю максимальное сжатие траффика.
На данный момент сервер без труда держит 8 игроков, загружая процессор не более 1% при заполненной комнате (учитывая, что процессор тут отнюдь не самый мощный). Мне пока очень трудно предсказать, как же игра поведет себя не в лабораторных условиях, но радует, что пока все выглядит оптимистично и мне интересно работать над проектом, узнавать новые вещи и решать сложившиеся трудности.
Те, кто смог прочитать все до конца, и разбирается в сути вопроса, я бы очень хотел выслушать мнение, с какими подводными камнями я могу столкнуться в будущем, и вообще любые советы. Я понимаю, что не предоставил ни строчки кода, ни каких-либо серьезных технических выкладок, но при необходимости я могу дополнять текст и отвечать на вопросы.
Сообщение отредактировал Nanotentacle - Среда, 21 Ноября 2012, 10:24 |
|
| |
|