Fella Posted November 19, 2013 Share Posted November 19, 2013 Собственно сабж. Делаю карту для рейса и хочу вставить в неё скрипт, который взрывал бы машины как только они попадают в воду. мне уже вот такой код клиентовский насоветовали: function isPlayerDiedinWater () vehicle = getPedOccupiedVehicle (getLocalPlayer()) if isElementInWater(vehicle) then blowVehicle (vehicle) end end addEventHandler("onClientRender", getLocalPlayer(), isPlayerDiedinWater) но по моим наблюдениям, если он что-то и делает, то не то что мне нужно. Мог бы кто-нибудь сказать, что с этим кодом не так и как его заставить работать? Большое спасибо заранее. Link to comment
Kenix Posted November 19, 2013 Share Posted November 19, 2013 Лучше это сделать в таймере, а не в рендере. Рендер предназначен для других целей, такие как прорисовка и т.п. addEventHandler("onClientRender", getLocalPlayer(), isPlayerDiedinWater) Второй аргумент должен быть root, а не локальный игрок т.к событие должно срабатывать для всех клиентов. Также не забывайте, что у Lua динамическое распределение памяти и делать такие конструкции не имеет смысла. vehicle = getPedOccupiedVehicle (getLocalPlayer()) if isElementInWater(vehicle) then blowVehicle (vehicle) end переменная vehicle станет глобальной, но в данной ситуации это вообще не нужно. Вот, накидал код. setTimer( function() if isPedInVehicle( localPlayer ) then local pVehicle = getPedOccupiedVehicle( localPlayer ); if isElementInWater( pVehicle ) then blowVehicle( pVehicle ); end end end, 1000, 0 ); Link to comment
Fella Posted November 20, 2013 Author Share Posted November 20, 2013 да, это работает, спасибо за помощь, но тут загвоздка ; как бы объяснить... короче, после того как тебя взрывает и ты начинаешь наблюдать за игроком, который ещё жив, тебя как бы "отбрасывает" от него каждую секунду, камеру сильно трясёт и раздаётся звук по типу запуска двигателя или вроде того. и как я уже сказал, это происходит ежесекундно. я так понимаю это связано с таймером и с тем, что скрипт как бы пытается тебя заново взорвать, хоть ты и умер уже по идее. возможно ли как-то убрать этот эффект? извиняюсь, что обременяю тебя. Link to comment
TheNormalnij Posted November 20, 2013 Share Posted November 20, 2013 if isElementInWater( pVehicle ) and not isVehicleBlown( pVehicle ) then Link to comment
Fella Posted November 20, 2013 Author Share Posted November 20, 2013 Большое спасибо, вот теперь всё прекрасно работает. Link to comment
Arisu Posted November 25, 2013 Share Posted November 25, 2013 Лучше это сделать в таймере, а не в рендере.Рендер предназначен для других целей, такие как прорисовка и т.п. Лучше всего сделать это в рендере, а не по таймеру. Потому что до выполнения таймера может гонка состояний произойти, и еще куча всего. И рендер это не только отрисовка, а событие обновления состояний объектов всего игрового мира. Поэтому и ловить новое состояние (попадание в воду) тут удобней всего. addEventHandler("onClientRender", root, function () -- берем списочек машин в зоне видимости и проходимся по нему for k, v in ipairs( getElementsByType( "vehicle", root, true ) ) do -- я отвечаю за состояние машинки в игре? if isElementSyncer( v ) then -- она в воде и еще живая? if isElementInWater( v ) and not isVehicleBlown( v ) then -- ну и умирает пусть тогда blowVehicle( v, false ) end end end end ) syncer тоже очень полезная вещь иногда. Имитировал таким способом умирание машин в воде, как в SA:MPе, когда писал свой мод. Link to comment
CocaColaBear Posted November 25, 2013 Share Posted November 25, 2013 И рендер это не только отрисовка, а событие обновления состояний объектов всего игрового мира. Вообще-то, рендер вызывается при каждой смене кадра. Если использовать стандартное ограничение кадров, то это максимум - 38 кадров. Следовательно лучше вызывать таймер каждую секунду для проверки, чем 38 раз в секунду проверять состояние автомобиля. А гонка за секунду не пропадет. P.S. Вот после таких вот действий в рендере люди жалуются: "А почему у меня фпс проседает?". Link to comment
Kernell Posted November 25, 2013 Share Posted November 25, 2013 Более того частота кадров у каждого клиента разная, и она не обязательно будет в пределах лимита, у некоторых оно может быть таким низким, что таймер в 50ms будет куда эффективнее. На самом деле куда лучше будет создать колшейпы в воде там где надо и привязать к ним Hit-событие P.S. 36, а не 38 Link to comment
TheNormalnij Posted November 25, 2013 Share Posted November 25, 2013 Главное не ставить triggerServerEvent в onClientRender Link to comment
Arisu Posted November 26, 2013 Share Posted November 26, 2013 Вообще-то, рендер вызывается при каждой смене кадра. таймер в 50ms будет куда эффективнее. Специально для любителей ловить всё таймерами, я привожу цепочку вызовов до onClientRender, глядя в исходники клиента. С комментариями и ссылками на строки. http://code.google.com/p/mtasa-blue/sou ... ce9.cpp#20: CProxyDirect3DDevice9::CProxyDirect3DDevice9 ( IDirect3DDevice9 * pDevice ) Здесь начало. В конструкторе класса CProxyDirect3DDevice9 захватывается объект Direct3D, выше мне копать тупо лень, поэтому глядим конструктор и по смыслу понимаем, что это так и есть. Метод этого же класса Present - не что иное, как сигнал того, что экранный буфер готов к отрисовке. Это проверяется гуглом и MSDN-ом. В теле метода - вызов http://code.google.com/p/mtasa-blue/sou ... e9.cpp#358: CDirect3DEvents9::OnPresent ( m_pDevice ); Здесь вызов статического метода класса CDirect3DEvents9::OnPresent. CDirect3DEvents9 это еще одна прослойка между движком MTA и Direct3D. В его теле нас интересует вызов http://code.google.com/p/mtasa-blue/sou ... s9.cpp#134: CCore::GetSingleton ().DoPostFramePulse (); Здесь: получение синглтона (это нагуглите в целях развития) класса CCore, и вызов его метода DoPostFramePulse(). В его теле: http://code.google.com/p/mtasa-blue/sou ... e.cpp#1284: m_pModManager->DoPulsePostFrame (); Вызов DoPulsePostFrame() в объекте-менеджере модов (один из модов - deathmatch). Метод в CModManager::DoPulsePostFrame вызывает http://code.google.com/p/mtasa-blue/sou ... er.cpp#289: m_pClientBase->PostFrameExecutionHandler (); В теле CClient::PostFrameExecutionHandler: http://code.google.com/p/mtasa-blue/sou ... nt.cpp#251: g_pClientGame->DoPulsePostFrame (); В CClientGame::DoPulsePostFrame: http://code.google.com/p/mtasa-blue/sou ... me.cpp#736: Тут останавливаемся, и начинаем смотреть в тело этого метода. http://code.google.com/p/mtasa-blue/sou ... me.cpp#925: DoPulses (); Спускаемся ниже в теле уже этого метода. http://code.google.com/p/mtasa-blue/sou ... e.cpp#1121: // Call onClientRender LUA event CLuaArguments Arguments; m_pRootEntity->CallEvent ( "onClientRender", Arguments, false ); И теперь самое занимательное. Это и есть точка вызова события onClientRender в скриптах. А теперь покрутим над этим вызовом и посмотрим внимательно, и над ним находится целая куча вызовов вида m_pUnoccupiedVehicleSync->DoPulse (); m_pPedSync->DoPulse (); #ifdef WITH_OBJECT_SYNC m_pObjectSync->DoPulse (); #endif И тому подобное. А это, если посмотреть внутрь методов соответствующих классов - код обновления положений, состояний и прочего для разнообразных игровых элементов: машин, объектов, и т.п.. Так вот, к чему я это пишу? Из этого кода видно, что вызов onClientRender производится сразу же после обновления мира. И поэтому, если нужно отследить какие-то изменения в игровом мире, нет ничего удобнее, чем поглядеть в вызове onClientRender. И внести свои изменения в него. И не нужно городить убербыстрых таймеров на 50ms, когда можно сделать всё и без них, сразу на месте. Это не будет слишком накладно, если использовать функции (getElementsByType(type = "vehicle", streamedIn = true)) правильно. Плюс, таймеры ненадежны, и могут иметь задержку до выполнения, тогда как какие-то изменения в мир нужно произвести немедленно. И лучше их делать сразу же в этом кадре. Вот так. Link to comment
Arisu Posted November 26, 2013 Share Posted November 26, 2013 Главное не ставить triggerServerEvent в onClientRender Одноразовый - можно. Ничего страшного не произойдет. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now