Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 1.0/2.0 (http://www.flasher.ru/forum/forumdisplay.php?f=93)
-   -   Основы создания онлайн флеш игр (http://www.flasher.ru/forum/showthread.php?t=85739)

miramax 03.10.2006 17:44

Цитата:

Сообщение от Хемуль
Флеш в конце концов не для игр делался...

Угу. Для сайтов и, особенно, для поисковых систем.

Dendroid 03.10.2006 19:02

Вложений: 1
По теме, вот мой простой и надёжный способ синхронизации между двумя игроками на основе getTimer() - синхронизируем все события относительно количества пройденных миллисекунд одного из игроков (в дальнейшем "мастера"). AS 3, вполне рабочий код - вставить в первый фрейм и скомпилировать:

Код:

import flash.*;

var connection:NetConnection;
var game_so:SharedObject;

// количество циклов для синхронизации:
var so_cycles:int = 12;

NetConnection.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;
SharedObject.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;

// имена игроков берутся из передаваемых переменных login и adv, этот код для тестирования на локальной машине (чтобы имена были разные):
if (loaderInfo.parameters.login==null) {
        var mySo = SharedObject.getLocal("testname");
        if (mySo.data.name == "player1") {
                login = "player2"
                adv = "player1";
        }else{
                login = "player1"
                adv = "player2";
        }
        mySo.data.name = login;
        mySo.flush();
        delete mySo;
} else {
        login = loaderInfo.parameters.login;
        adv = loaderInfo.parameters.adv;
}

// определяем кто будет мастер (по чьему таймлайну будут синхронизироваться все события в игре (самый тупой способ):
var so_main:Boolean = login>adv;

// чтобы каждая пара игроков (имена уникальны на сервере) получала уникальный sharedoject в пользование:
var so_name:String = so_main?login+"__"+adv:adv+"__"+login;

// переменная, которая будет определять сдвиг времени для событий, чтобы привести их к таймлайну мастера (у мастера это значение останется нулём):
var timeShift:Number = 0;

var timeShiftStat:Array = new Array(so_cycles);

connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
connection.connect("rtmp://[ваше приложение]");

function netStatusHandler(event:NetStatusEvent):void {
        switch (event.info.code) {
        case "NetConnection.Connect.Success":
                connectSO();
                break;
        case "NetConnection.Connect.Failed":
                trace("failed");
                break;
        }
}

function connectSO () {
        game_so = SharedObject.getRemote(so_name, connection.uri, false);
        if(game_so){
                game_so.addEventListener(SyncEvent.SYNC, soOnSync);
                // нужно, если игроки могут присоединяться по локальной сети (маленький пинг):
                game_so.fps = 1000;
                game_so.connect(connection);
        }
}


function soOnSync(event:SyncEvent):void {
        if (game_so.data.ts == null) {
                if (!so_main) {
                        // начинает синхронизацию слейв, путём инициализации значения ts.n нулём:
                        game_so.setProperty("ts",{n:0,t:getTimer()});
                }
        } else {
                if (game_so.data.ts.n<so_cycles) {
                        // в массиве сохраняем время каждого события синхронизации:
                        timeShiftStat[game_so.data.ts.n] = game_so.data.ts.t;
                        // четные значения посылаются слейвом, нечётные мастером:
                        if (game_so.data.ts.n%2 ^ so_main) {
                                game_so.setProperty("ts",{n:game_so.data.ts.n+1,t:getTimer()});
                        }
                } else {
                        calculateTimeShift();
                }
        }
}

// подсчитаем сдвиг времени для слейва:
function calculateTimeShift () {
        var arr:Array=[];
        for (var i:int=1; i<so_cycles-2; i+=2) {
                arr.push((timeShiftStat[i+2]+timeShiftStat[i])/2-timeShiftStat[i+1]);
        }
        // для небольшой дисперсии вполне хватает такого тривиального выбора среднего (для более точного подсчёта можно вычислять равноудалённое, среднее арифметическое, и не забыть отбросить слишком большие и слишком маленькие значения):
        arr.sort();
        timeShift = arr[Math.floor(arr.length/2)];
}

Как теперь работать с объектами? Этот код здесь не приведён, зависит от структуры игры. Это очень просто: пусть игрок слэйв хочет запустить новый объект (мяч, ракету), или провзаимодействовать уже с существующим, ему достаточно передать момент создания этого объекта, его положение и скорость, например в новой (или уже существующей - если объект уже был) переменной того же шаредобжекта: "game_so.setProperty("ball1",{x:10,y:10,vx:1,vy:0,t:getTimer()+timeShift});" Когда мастер получит эти значения, он создаст (переместит уже существующий объект) в нужное место (не забываем, что время создания уже в прошлом, поэтому объект надо переместить сразу в положение {x,y} + {vx,vy}*(getTimer()-t). Далее объект обсчитывается как движущийся независимо (не требует новых передач данных по сети), при этом он может взаимодействовать с другими объектами, движущимися независимо - это тоже не требует новых данных и будет работать синхронно для всех игроков, пока не провзаимодействует с одним из объектов, управляемых игроком (тогда переменная ball1 должна быть изменена или удалена в случае уничтожения объекта).

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

Метод удобен для игр, где есть объекты, которые движутся по заданным тракториям, пока на них не подействует один из игроков, когда не надо постоянно транслировать картину игры друг другу (аркады очень многие, мноопользовательские рпг, разбитые на локейшоны). Достаточно передавать изменения и новую траекторию объекта. Эти объекты синхронизируются идеально (у меня получается разница порядка 10миллисекунд при пингах в районе 300-500, это значит, например, что поставив два компьютера рядом, и законнектив их через сервер на другом полушарии, вы не сможите увидеть разницу в движении независимых объектов).

Проблема, естественно, остаётся с объектами, контролируемыми игроками, при пинге порядка полусекунды, если мы будем просто транслировать текущие координаты - будет заметно дёрганье, но тут есть хитрость: для этих объектов можно использовать различные алгоритмы компенсации, в самом простом случае передаём кроме положения ещё и скорость объекта. Пока не поступили новые данные, движим объект равномерно и прямолинейно. Как только поступили новые координаты удалённого игрока - не перемещаем объект сразу в место, где он должен быть, а делаем это плавно, в течении, скажем 300 миллисекунд - это существенно сгладит рывки объекта. В идеале оперировать надо кроме положения и скорости ещё и ускорением, чтобы вторая производная тоже была гладкой - тогда рывков вообще не будет заметно и будет полное впечатление, что синхронизация постоянная, как на локальной машине. :) Да, при таком "размытом" определении положения объекта игрока не сделать какое-нибудь полноконтактное взаимодействие (сложный фехтовальный бой или что-то вроде мортал комбата - но это проблема не только во флэше) - просто не будет хватать передаваемых данных, интерактивности взаимодействия.

Ещё приведённый выше кода и подход в целом хорош тем, что не требует никакой серверной части, скажу больше: он даже не требует своего сервера, ведь нужно только права открывать свои шареные обжекты, достаточно присоединиться к любому rtmp приложению, открытому в веб (к примерам на Адобе или на сервере примеров red5 ;) Но так делать нехорошо, разве что для теста...). Вся обработка событий вынесена на сторону клиента, поэтому скорость симметрична относительно разницы пинга игроков, фактически работаем с суммой пингов, это обеспечивает один из условий fairplay (игрок с маленьким пингом не имеет преимущества перед игроком с большим пингом).

Вот ещё картинка, поясняющая, как мы считаем timeShift (в данном случае первым было запущено приложение слэйва (на рисунке справа), он установил значение t0 и ждёт, кода мастер (слева на временной шкале) продолжит синхронизацию. timeShift в этом примере получится отрицательным и равным (3200+2000)/2-9150= -6550 (т.е. по усреднению выборки считаем, что событие t4 у слэйва произошло в точности посередине событий t3 и t5 у мастера). Черные точки на линиях показывают, в какой момент событие может доходить до сервера и почему это не влияет на вычисления (из симметрии).

Dendroid 03.10.2006 19:03

Но это так, вкратце, тема-то неисчерпаемая ;)

FlexBuilder 03.10.2006 19:12

Цитата:

Сообщение от ArseN_givi
ну так поведайте стандартные приемчики... может для меня это будет ново!

ничего нового нету:
http://www.gamedev.ru/code/forum/?id=16529
http://www.gamedev.ru/code/forum/?id=50394
и т.д.

ArseN_givi 03.10.2006 21:07

по моему вопросу ответьте плиз!

ArseN_givi 05.10.2006 12:46

Спасибки всем! Бду пробовать разные методы

Kyber Anton 05.10.2006 19:23

Цитата:

Сообщение от Хемуль
Флеш в конце концов не для игр делался...

Вот и меня эта фраза задела. Извините, что не по делу пишу - но вы, Хемуль, очень недооцениваете флэш. Очень.

Хемуль 05.10.2006 20:43

2 Kyber Anton:
Я не писал, что игры невозможно делать на Флеше. Это было бы глупо с моей стороны, поскольку таковых бесчисленное множество. Но я повторю, что Флеш делался не для игр. Что ни говорите, а ни один разработчик не решится создавать что-то серьёзное на Флеше. Слишком медленная тут графика.
Я искренне люблю Флеш и если бы он был девушкой, наверное, я бы на нём женился, но стоит смотреть правде в глаза... Флеш - отличная вещь и границы его применения широки, но не стоит считать, что он удобен для создания игр и для этого создавался. Да, может удобен... Как и любой движок со Scene-Graph...И то, для чего-то маленького... А из-за того, что флешки работают по-разному не только на разных компьютерах, но и под разными броузерами, согласитесь, лучше он не становится...

miramax 05.10.2006 23:14

Цитата:

Сообщение от Хемуль
2 Kyber Anton:
Я не писал, что игры невозможно делать на Флеше. Это было бы глупо с моей стороны, поскольку таковых бесчисленное множество. Но я повторю, что Флеш делался не для игр. Что ни говорите, а ни один разработчик не решится создавать что-то серьёзное на Флеше. Слишком медленная тут графика.
Я искренне люблю Флеш и если бы он был девушкой, наверное, я бы на нём женился, но стоит смотреть правде в глаза... Флеш - отличная вещь и границы его применения широки, но не стоит считать, что он удобен для создания игр и для этого создавался. Да, может удобен... Как и любой движок со Scene-Graph...И то, для чего-то маленького... А из-за того, что флешки работают по-разному не только на разных компьютерах, но и под разными броузерами, согласитесь, лучше он не становится...

Ты просто никогда не писал и даже не пробовал писать игрушки. Поэтому и говорит что флеш игры фуфло. Для чего по-твоему сделали флеш?. Уже на каждом втором диске авторан флешевский. Начинается тотальное использование flash UI в виндовых приложениях.
И игры писать на флеше можно, если правильно работать с битмапдатами, всё можно. Может не таике крутые и быстрые как на Си, но можно же. Стратегу типа первого варкрафта точно можно написать.

iNils 05.10.2006 23:17

Ближе к сути вопроса пожалуйста.


Часовой пояс GMT +4, время: 16:33.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.