LINUX.ORG.RU

Вопрос по Lua

 , , ,


0

1

Встраиваю к себе lua после неудачной попытки отыскать встраиваемый C Встроить язык си в программу на языке си ::), всё хорошо через Lua C/API делаю вызовы С функций, через FFI делаю вызовы, из C вызываю функции lua и из lua вызываю С функции вызывающие lua код, короче наигрался. Но вот что я не пойму мы инициализируем lua_State затем загружаем скрипт к примеру luaL_loadfile(L,"./test.lua"); затем исполняем его lua_pcall(L, 0, 1, 0); он отрабатывает, возвращает мне что-то и что я получаю printf("Get script return value => %s\n",lua_tostring(L,-1));, а теперь я исполняю его снова иииии

test2
PANIC: unprotected error in call to Lua API (attempt to call a nil value)

Чуть подробнее C

    lua_State * L = luaL_newstate();
    luaL_openlibs(L);

    int status = luaL_loadfile(L,"./luatest2.lua");
    if(status)
    {
        debug("filed load script: %s ",lua_tostring(L, -1));
    }

    lua_pcall(L, 0, 1, 0);
    lua_pcall(L, 0, 1, 0);

Lua

print("hello");

Выхлоп (вызов только 1 раз, хотя я дёргаю два раза)

hello

Но вспоминаю я ж ничего не возвращаю и не читаю результат возврата и поэтому убираю возвраты

    lua_pcall(L, 0, 0, 0);
    lua_pcall(L, 0, 0, 0);

И получаю выхлоп

hello
PANIC: unprotected error in call to Lua API (attempt to call a nil value)

Я такой репу чешу и вызываю так

   luaL_loadfile(L,"./luatest2.lua");
   lua_pcall(L, 0, 0, 0);
   luaL_loadfile(L,"./luatest2.lua");
   lua_pcall(L, 0, 0, 0);

Выхлоп с двумя «hello» всё верно и ошибки нет.

И вот две вещи которых я недопойму, luaL_loadfile() или остальные функции загрузки кода надо каждый раз вызывать перед lua_pcall? Разве lua_State не хранит текущий кусок кода в себе? Ну и второй вопрос про lua_pcall с 0 параметром возврата это так и надо или нет?

Версия luajit ниже, самосбор, без ключей сборки просто make c си кодом линковка статическая если это важно (статик линковка для проверки возможности вызова функций из lua си функций из самой же программы без загрузки lib.so)

LuaJIT-2.0.5

Тему не читал, но с C API (и вообще с Lua) могут помочь в запрещённом мессенджере по умолчанию в канале ProLua.

Ceiling_QB ★★★★
()
Ответ на: комментарий от Ceiling_QB

могут помочь в запрещённом мессенджере по умолчанию в канале ProLua

Запрещённый месенджер меня задолбал то работает то нет поэтому я его выкинул (всё равно мне писать некому - я водяноооой я водянооой никто не дружится со мной ) Ну, я «ProLua» в заметки занёс если будет опять у меня конвертогалка то загляну к вам.

А вопрос сей простыни прост, похеру на ошибку это я разберусь, а вот то что перед lua_pcall надо каждый раз указывать исполняемую единицу (файл или буфер) выглядит странно для меня. Так и должно быть? Или можно где сказать что если уже указана исполняемая единица или буффер то просто переисполнять.

LINUX-ORG-RU ★★★★★
() автор топика

luaL_loadfile создало и затолкнуло в API стек скомпилированную Lua-функцию
потом ты эту функцию вызываешь через lua_pcall
lua_pcall функцию съедает, т.е., извлекает из стека и использует
второму lua_pcall есть уже нечего - первый всё съел
поэтому надо предварительно создать резервную копию этой функции (продублировать её в стеке) вызовом lua_pushvalue перед вызовом первого lua_pcall

в Lua мануале подробности о кол-ве съедаемых и порождаемых ячеек стека зашифровано в строке справа в углу каждой функции
например, для lua_pcall это строка [-(nargs + 1), +(nresults|1), -]
вот эта +1 после nargs - это как раз извлекаемая из стека функция (nargs - это извлекаемые аргументы)

Egor_
()
Ответ на: комментарий от Egor_

хм, спасибо за пояснения, но со множественным pcall всё равно чудно

Хочу я сделать вызов 3 раза делаю

                lua_pushvalue(L,1);
                lua_pushvalue(L,-1); -- тут return но мы его не используем

                lua_pcall(L, 0, 0, 0);
                lua_pcall(L, 0, 0, 0);
                lua_pcall(L, 0, 0, 0);

Дальше пожирая стек pcall последовательно делает три вызова.

test2
test2
test2

Но как я понимаю делать так лучше не надо.

Тогда что бы последовательно делать несколько вызовов надо делать типа так? Перезаписывая вершину стека?

                lua_pushvalue(L,1);
                lua_pcall(L, 0, 1, 0);
                printf("Get script return value => %s\n",lua_tostring(L,-1));
                lua_pushvalue(L,1);
                lua_pcall(L, 0, 1, 0);
                printf("Get script return value => %s\n",lua_tostring(L,-1));
                lua_pushvalue(L,1);
                lua_pcall(L, 0, 1, 0);
                printf("Get script return value => %s\n",lua_tostring(L,-1));

test2
Get script return value => 10
test2
Get script return value => 10
test2
Get script return value => 10

Но смысл вроде понял, вроде всё работает, спасибо. Надо садится и читать, я думал ладно стек все дала фиг с ним, но вот вызовы более как то сами собой работают =), хотя надо вдуплится ещё.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

От те на, и так тоже делать получается нельзя, если я пушу в голову функции то возврат каждой из них опять же сохраняется в стеке и сделай я for 100500 и получу лося в память отоже жблин.

Сделал дамп стека после каждого троектратного вызова

test2
Get script return value => 10
test2
Get script return value => 10
test2
Get script return value => 10
function  `10'  `10'  `10'  
test2
Get script return value => 10
test2
Get script return value => 10
test2
Get script return value => 10
function  `10'  `10'  `10'  `10'  `10'  `10'  
test2
Get script return value => 10
test2
Get script return value => 10
test2
Get script return value => 10
function  `10'  `10'  `10'  `10'  `10'  `10'  `10'  `10'  `10'  

Тогда надо кажого получеия результата от вызова одного и тогоже сбрасывать стек до единницыlua_settop(L, 1); а уже потом делать следующий вызов и перед этим естессна запушить аргументы если они есть.

Типа получается если я загружаю скрипт то для каждого нового его вызова я должен делать вот так?

                lua_pushvalue(L,1);    // сохраняем 
                lua_pcall(L, 0, 1, 0); // вызываем
                printf("Get script return value => %s\n",lua_tostring(L,-1));//получаем
                lua_settop(L, 1);//очищаем стек оставляя только точку вызова функции

Я правильно всё понимаю? Или херню порю :D

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

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

lua_load...(...);
int f = lua_gettop(L);
// или
// (global) int ref = luaL_ref(L, LUA_REGISTRYINDEX);

while (condition) {
  int top = lua_gettop(L);

  lua_pushvalue(f);
  // или
  // lua_rawgeti(L, LUA_REGISTRYINDEX, ref);

  ...push args...
  if (pcall(L, nargs, nres)) {
    // handle error
  } else {
    // use results
  }
  lua_settop(L, top); // удалил результаты
}
lua_pop(L, 1); // удалил f
// или ничего не делаем для ref

Или-блоки используй, если функцию надо сохранить надолго - это положит ее в “lua registry” под уникальным интеджером, и ее всегда можно оттуда будет достать lua_rawgeti().

anonymous
()
Ответ на: комментарий от LINUX-ORG-RU

Короче ошибка была вызвана тем что после вызова возврат помещался на голову стека, так как я не задавал возврата возврат был nil после этого последующий lua_pcall брал это значение стека и пытался исполнить как функцию что выдавало панику.

Вопрос закрыт по сути. Хотя странно что если я занесу в голову строковое значение в надежде опять получит панику из за несоотвецвия я получаю просто предупреждение, по идее логичнее при любых данных кроме как исполняемых надо либо всегда панику делать либо всегда просто игнорировать вызов как если бы там вообще ничего не было либо всегда выдавать предупреждение. Немного неясно почему такое разное поведение для однотипных ситуаций. Ну да ладно, и да на заметку может кому пригодится.

Для случая когда мы вкомпилили luajit статически и хотим вызывать через FFI функции прямо из исполняемого файла, а не из so библиотек (для случая если у нас программа просто 1 файл) то надо собирать конечную программу с -Wl,-E иначе ffi просто не найдёт cdecl. Затем в lua скрипте мы уже указываем имя программы как загружаемый объект вместо библиотекиlocal my_app = ffi.load("./app"); и вызываем внутренние функции ffi.C.app_func(); или my_app.app();

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

Ты можешь просто делать ffi.cdef “int myfunc(double, char *)”, если у тебя они в программе экспортированы. На винде это __declspec(dllexport) int myfunc(...), а в линуксе по дефолту должно быть для не-static функций, афаир.

anonymous
()
Ответ на: комментарий от LINUX-ORG-RU

Хотя странно что если я занесу в голову строковое значение в надежде опять получит панику из за несоотвецвия я получаю просто предупреждение,

Не уверен, что ты имеешь ввиду под этим, т.к. из пикола ты не можешь получить панику. Запушь нил и проверь. Вообще ни из чего не можешь. Вероятнее всего в сабжевом случае ты пиколил с одним аргументом, хотя на стеке вообще ничего не было, top==0. Так делать нельзя, это сорт оф уб в луа апи, хотя в данном случае тебе повезло.

anonymous
()
Ответ на: комментарий от anonymous

ffi.cdef “int myfunc(double, char *)”, если у тебя они в программе экспортированы.

Да, но я про случай когда я взял библиотеку A и код B и juaJit, затем скомпилировал всё статически в 1 исполняемый файл и теперь из lua мне надо вызывать функции из A. Без каких либо телодвижений по организации экспорта, без сборки с -Wl,-E у меня не завелось. А уж если делать функции экспортируемыми тогда наверное лучше через lua c / api экспортировать по нормальному с проверками прочим. Сырой ffi прямо из исполняемого файла хорошо когда надо по быстрому что-то делать. Удобно же. Либы рядом держать не надо, описывать ничего не надо. =)

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от anonymous

хотя на стеке вообще ничего не было, top==0

Блин, точно, я же запускал как lua_pcall(L, 0, 0, 0); и ошибку получал ибо да в стек возврат не был записан и он просто полностью опустел, а когда я делал тоже самое, но с указанием возврата lua_pcall(L, 0, 1, 0); он мне говорил attempt to call a string value ибо я запрашивал возврат как lua_tostring(L,-1) если запрошу как число он будет ругаьтся что я хочу исполнить число и так далее. Эх, нюансы мать их =) Спасибо за ремарочку

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

Да, я только что читнул про эти аргументы, сорян за шум.

лучше через lua c / api экспортировать по нормальному с проверками прочим

Я бы не сказал. ffi - rock solid, и вполне нормальный способ для общения «оттуда». Со стеком и обертками 1) намучаешься, если данные сложнее пары циферок и строк, 2) они тормознее, чем прямой вызов из трейса жита. Если жит отключить, то разницы конечно не будет, но для тебя это гора с плеч. Минусом идет потеря совместимости с ванильным луа, но это похрен, т.к. текущий луа уже ответвился в 5.2/5.3 диалекты, и не сказать, что они сильно удачнее оказались.

anonymous
()
Ответ на: комментарий от anonymous

Вот тут к слову у меня ещё вопросы есть

  • 1 Влияет ли на jit компиляцию то что я экспортирую функции не через ffi ,а через api кроме как накладные расходы на вызов появляются. (Ну накладные расходы я сам протестирую)

  • 2 Возможно ли включать и отключать ffi кроме как сборки без и с, ну например софтина может быть клиентом где может быть загружен и исполнен пользовательсткий lua код с ffi тут вся отвецтвенность на пользователе. И оно же может быть сервером куда тоже может быть загружен пользовательский lua (например по сети) но уже без возможности работы с ffi, а то так любой чувак сможет положить сервер раком.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

1. Апи-стиль не препятствует житу, но он сам решает, когда пора конпелять. Влияет ли на его решение вид враппера апи/ффи - вот этого не знаю.

2. Конечно. Также можно вкл/выкл жит для отдельной функции. http://luajit.org/ext_jit.html

3. На случай если ты еще не видел, есть возможность вызывать луа-функции из сишки без стека (как бы ffi в обратную сторону). Может быть удобно, а может и нет, смотря что пилишь. http://luajit.org/ext_ffi_semantics.html#callback

tl;dr

ffi.cast(myluafunc, ffi.type(“int ()(double)”) -> 
  возвращаешь в сишку, а потом: 
int (*func)(double) = lua_touserdata(L, -1);
int i = func(3.14);
Тут более низкоуровневая типоопасная движуха, и надо внутри myluafunc ловить ошибки pcall()-ом, но бывает удобно при куче несвоих колбеков.

anonymous
()
Ответ на: комментарий от anonymous

Если жит отключить, то разницы конечно не будет

Согласно пророчеству, ffi быстрее с jit, но без jit он заметно тормознее обычных луа-сишных вызовов.

Желательно, конечно, спроектировать код так, чтобы не нужно было часто скакать туда-сюда между Си и Lua.

i-rinat ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Вообще старайся следить за размером стека, он в стандартной Lua достаточно маленький. Если будешь много раз подряд вызывать функции, не выталкивая результат с вершины стека, он переполнится. (В LuaJIT тоже переполнится, только много позже.)

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

На счёт стека это да, но тут палка о двух концах, ну прям сейчас ещё рано делать задел на то как всё это уже прям реально встраивать, но всё же, для себя я вижу 2 варианта первый самый типа гибкий все объекты игровые могут иметь свой lua_State и соответственно скрипты которые будут к нему присоединены и там как в love на интерациях load/update/draw/thread_callback будут дёргаться соответствующие функции и неигровые объекты тоже, например навесить скрипт на мышку и клавиатуру. То есть состояние->действие->результат->сброс. Тогда со стеком проблем не будет (Ну меньше будет предрасположенностей к этому). Или второй вариант,когда основной код сам по себе, но на глобальные состояния load/update/draw/ могут быть навешаны скрипты где уже из внутрей будут дёргаться при переходе в то или иное состояние, это даже красивее (в моей голове) выглядит, но 100пудов будут тогда ситуации когда скрипт нужно будет перевыполнить более одного раза. Ну тут думать короче надо, по сути много делать скрипты не должны, только логику и всё, остальное должен делать С код по результатам возвратов скрипта желательно, а не в процессе выполнения скрипта.

Но сначала надо палкой тыкать усердно, и бенчи написать, а то начну херачить тем или иным подходом и окажется что вызов 100 раз чего либо в процессе работы ставит раком всё или ещё какие ограничения сам себе сделаю =) В любом случае мудрить я особо не буду нужен простой подход. Я раз в неделю стабильно на корню в движке меняю то или иное, надо что-бы скриптота не отваливалась постоянно и всё определялось централизованно как-то. Хмм, тогда прям ща подумалось что-бы не объекты игровые имели скрипты и дёргали их в зависимости от смены состояния, а скрипты ссылались на объекты тогда можно вообще всё сделать выносным кодом. Думать короче надо и экспериментировать. =)

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

А просто нормально функции вызывать — для слабаков?

Та нееее =) Я просто перебираю в голове варианты, Просто звучит прикольно, например такая наркомания - «Есть модель у неё есть материал ну там какие текстуры какое то какое сё и я навешиваю скрипт даже не на character, а прямо на материал и он например меняется автоматически в тех или иных случаях» прикольно же! Хотя да, жирновато и в 98% случаев будет не нужно. Ну пока что я больше играюсь https://youtu.be/bnpTFA32vz4 тут зачаточно, но суть в том что мне хочется например в сцене выбрать что угодно, камеру, модель, рендер, мышку не важно, и для этого просто на живую написать скрипт который соотвецтвенно когда ему положено или сразу будет вызван, вот в том и суть. Только надо ещё хоть наитупейший но какой никакой редактор допилить, что бы простые случаи можно было прямо в в сцене и закодить, а что-то сложное через вызов любого внешнего. Мне скорее это для по задумкам для игры надо чем для добавления возможностям самому движку.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

2. Я тут перепутал jit и ffi, уже заметил, но труба позвала и пришлось уйти.

Отключить ffi в рантайме можно, временно удалив его из глобальной таблицы и из registry._PRELOAD/_LOADED, чтобы нельзя было require «ffi». Похожим образом нужно удалить debug, т.к. ffi приедтся временно куда-то сохранить, а это registry, к которой можно добраться через debug.

Более правильный путь это lua sandboxing, см. lua-users wiki, но он и более сложный, придется вкуривать метатаблицы и окружения (это не страшно, просто один раз понять концепцию). В любом случае изолировать фичи от некоторых скриптов возможно, но если речь о безопасности, то делать это нужно очень внимательно.

Также можно создать отдельный привилегированный lua_State, а в обычном удалить debug и ffi (как и os, io, etc) навсегда или вовсе не подключать их, вместо luaL_loadlibs() подключив только нужные библиотеки вручную.

anonymous
()
Ответ на: комментарий от i-rinat

Блин, твоя правда. (сорян за 4.2 и венду)

timex -f%e ./main.exe 1e8 off api
1.71

timex -f%e ./main.exe 1e8 off ffi
6.68

timex -f%e ./main.exe 1e8 on api
2.72

timex -f%e ./main.exe 1e8 on ffi
0.25
local n, jit_mode, api_mode = ...
n = tonumber(n)

local jit = require 'jit'
local ffi = require 'ffi'

ffi.cdef [[ int foo_ffi(int a, double b); ]]

jit[jit_mode]() -- on/off
local foo

if api_mode == 'api' then
    foo = foo_api
elseif api_mode == 'ffi' then
    foo = ffi.C.foo_ffi
end

for i = 1, n do
    local res = foo(1, 3.14)
end
__declspec(dllexport)
int foo_ffi(int a, double b) {
    return a + b;
}

static int foo_api(lua_State *L) {
    int a = (int)lua_tointeger(L, 1);
    double b = lua_tonumber(L, 2);
    lua_pushnumber(L, a + b);
    return 1;
}
anonymous
()
Ответ на: комментарий от anonymous

за 4.2

Не тянет на «вызывающе». Я бы скорее сказал, что если дело дошло до ситуации, где эта разница вообще имеет значение, что-то не так с кодом. Реально же миллионы раз в секунду нужно вызывать, чтобы заметить.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

LÖVE, все они как под копирку, сишный врапперы, я джва года жду, тип такого:

area = love.graphics.newArea(10, 10, 300, 100)
просто пустая область на сцене, потом мне если что нужно определяю функционал:

area["virtual:mousePressEvent"] =
    function(x, y, btn)
        print("mouse:", x, y, btn)
        return true
    end

area["virtual:mouseFocusEvent"] =
    function(f)
        print("focus: ", f)
    end

area["virtual:keyPressEvent"] =
    function(k)
        print("key: ", k)
        return true
    end

area["virtual:render"] =
   function()
   -- здесь хочешь рисуй, хочешь др..чи
   end

вместо этого имеем тот же сишный big trash завернутую в lua:

love.event.clear, love.event.poll, event queue, love.event.pump, love.event.push, love.event.quit, love.event.wait

anonymous2 ★★★★★
()
Последнее исправление: anonymous2 (всего исправлений: 2)
Ответ на: комментарий от anonymous

На случай если ты еще не видел, есть возможность вызывать луа-функции из сишки без стека (как бы ffi в обратную сторону)

Оверхед большой, будут тормоза. Майк рекомендует вместо коллбеков из C делать poll со стороны Lua.

anonymous
()
Ответ на: комментарий от anonymous2

Ты пытаешься использовать LÖVE 2D как среду для создания настольных программ? Там же есть функция love.keypressed, которая вызывается при нажатии на клавишу. А рисование выполняется по таймеру, 60 раз в секунду, тоже вызовом, love.draw.

Навереное, тебе стоит искать привязку Qt или GTK к Lua.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Не, у меня нет цели пробудлировать функционал какой-то или ещё что-то повторить, всё что мне надо, это делать игру. В планах программируемые боты пользователя для добычи ресурсов, лично мне нужен только С и не более того, но раз будет возможность использовать скрипты то какие то утилиты я бы делал на скриптах, но только те которые нужны в процессе разработки, а не работы самого движка, да и движка то по сути никакого нет что Corange что мой форк EGNAROC это фреймворки, ну вот есть ui/event/assets/entity системы их можно добавить, а можно выкинуть, также будет и script система которую можно добавить, а можно выкинуть. Опять же script систему надо будет делать так что бы тут lua была не причём найду я вот что-то такое-же няшное как lua, но более похожее на angelscript и мне хочется безболезненно просто задать бинды для другого язычка вот и всё =)

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Спасибо большое. Ну, всё основное мне уже известно, буду вникать в детали, недельку поиграюсь, шишки понабиваю, а там уже будет яснее как поступать для рабочих ситуаций.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от mittorn

Я думал на счёт него, так как мне нужен по сути только код скриптования логики, а также то что С подобный синтаксис js это няяяяя, он почти идеально подходит. Но… Если честно я просто засцал его брать, мне кажется ещё рано. Я с ним играюсь как только на лоре новость выскочила, ну если мне зайдёт прям очень прикручу и его, как минимум для эксперимента может баги какие открою (хотя толку то засылать то их всё равно некуда, этому гению слать патчи бесполезно)

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

Я не настолько крут, это надо быть программистом, а я так, быдлокодер любитель, у меня всё скромно и по тупому просто =)

Хотя если ты про то что лишь тройка лошадей людей реально понимают как этот gcc работает, а случайный человек увидит код и уйдёт в запой от душевной травмы что он ничего не понял, то это не страшно. Мой быдлокод кроме меня первое никто и не увидит никогда скорее всего, а если и увидит то он мимолётно ибо он никому нахрен не нужен =)

А сложностей я избегаю, если я наколдую так что сам понять не смогу я просто всё заброшу, я уж стараюсь пусть и не очень круто писать, но что бы если я через месяц вернулся доделывать я волосы не рвал от непонимания чё я нахимичил =)

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от i-rinat

А рисование выполняется по таймеру, 60 раз в секунду, тоже вызовом, love.draw.

а это самый шикарный треш, рисовать нужно тогда когда необходимо, а тут просто проц грузит... просто не осилили)))

anonymous2 ★★★★★
()
Ответ на: комментарий от anonymous2

В играх нужно рисовать как можно быстрее, но не быстрее заданного лимита. В приложениях — когда изменилось. LÖVE заточен под игры.

Ты же не будешь тянуть какой-нибудь Unreal Engine 4 для того, чтобы Jabber-клиент запрогать.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

В играх тоже считают только что изменилось. Единственное что там требуется чтобы всё уложилось во время выделенное на обновление кадра.

anonymous
()
Ответ на: комментарий от anonymous2

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

Если ты придумаешь как в динамической игре делать расчёт кадра который нужно дропнуть и не рисовать вместо того что бы просто отрисовать кадр по новой пиши в unreal/unity/crysis и прочим они за тебя будут драться и завалят баблом, будешь склеивать банкноты колеем в кирпичи и строить из них сральник у себя на даче фундамент для которой ты будешь заливать серебром

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

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

anonymous
()
Ответ на: комментарий от anonymous

Мне нравится когда в играх фпс под 1000 (или больше). Естественно оно внезапно очень неиграбельно становится. Почему игры на юнити этим так страдают? Это хорошо ещё если всинк зафорсить можно.

anonymous
()
Ответ на: комментарий от anonymous

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

anonymous
()
Ответ на: комментарий от anonymous

Игре должно быть пофигу какой fps она выдаёт хоть 1000 хоть 23. На высоком времени кадра понятно неприятно видеть лаги, а на низком проблем не должно быть ровно никаких ибо скорость там колыхания листика на дереве и перемещение игрока будет всегда одно и тоже в не зависимости от скорости работы просто если так можно сказать кадровка и все действия не по фиксированному ремени, а размазаны по всему шагу времени одного кадра кадра.

Но если где то разработчик сделал типа

if(get_fps() == 60)
{
   do_something();
}

То, да, будут проблемы привеликие ))))))))))

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от anonymous2

Какой смысл осиливать инвалидацию регионов, если все равно 99% времени регион == экран/окно. Даже просто сказать, поменялась ли картинка (клипнулось ли изменение например), уже надо тратить время и свое, и цпу, разве нет?

anonymous
()
Ответ на: комментарий от anonymous

Это в идеале, а такое редкость, при большей частоте кадров ты не увидишь больше кадров, нет конечно, монитор будет дропать всё лишнее, но суть в том что разница в подготовленных кадрах для монитора в 60герц при 60 fps будет 0.016 секунды, а при 150 fps 0.006 секунды. То есть ты видишь игровой мир 16 и 6 милисекунд назад во времени. Эту разницу одни увидят, а другие нет. Зависит от человека. Но ты можешь сделать раскадровку и увидеть что кадров не больше, а они тупа другие, при ровных 60 кадрах при 120 тике ты можешь просто не увидеть более ранние тики. Некоторые игроки чётко видят разницу на монитора 144 и 240 герц их физиология зрительной коры им позволяет ибо латентность нейронов у них низкая. Эти же игроки будут чётко видать разницу во временных отрезках кадров на 60 герц мониторе при 60 кадрах и при 240.

По итогу важны две вещи, первая разница между кадрами в игровом мире должна быть как можно меньше и тут герцовка монитора не приоритет (это касается только сильных динамических сцен), но ещё более важное это стабильная разница во времени между кадрами их может 30 но если они идут как 30 29 31 32 29 это плохо. Это же касается и 60 кадров на 60 герц мониторе, порой могут быть просадки и если вохможно то надо рисоват с запасом с учётом просадки если есть место где кадр чато падает на 10 единиц то при 60 кадрах мы реально рисуем 60+10 и ещё пяток с верху что бы именно компенсировать пролаг и время между показываемыми кадрами осталось ровно прежним.

LINUX-ORG-RU ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.