Игра Lua Scripting - с использованием куртинов или опросов?
Я начинаю изучать, как использовать скрипты Lua для разных игровых профилей с программным обеспечением Logitech.
Сначала я попытался использовать onevent (я знаю, что он не очень продвинутый) и создал комбо-скрипт для этой атаки.
function OnEvent(event, arg)
if event == "MOUSE_BUTTON_PRESSED" and arg == 1 then --set flag for mb1
mb1_pressed = true
elseif event == "MOUSE_BUTTON_RELEASED" and arg == 1 then --set flag for mb1=false
mb1_pressed = false
end
end
if mb1_pressed then --using flags to determine whether to start attack or not
repeat
presskey("A")
Sleep(50)
releasekey("A")
Sleep(100)
--if MB1 is release, it will also break script. if i only tap mb1, this will only execute the first line of attack without the rest below
if not (**argument**, can be MB1/ismouse1) then break end
presskey("S")
Sleep(50)
releasekey("")
Sleep(120)
presskey("A")
Sleep(50)
releasekey("A")
Sleep(200)
if not (**argument**, can be MB1/ismouse1) then break end --if MB1 is release, it will also break script. this point will prevent script from looping from start if mb1 release
until not (**argument**, i use ismouse1) --end the loop of script
end
Поэтому я пытаюсь привязать это к кнопке G6 моей мыши logiech (используя mouse_button_press == 6). Установка флага с MB6 работает, но завершение цикла / разрыв цикла не может быть вызвано MB6
После некоторых исследований на форуме поддержки Logitech на SDK/Lua, похоже, что проблема с моим скриптом
- Флаги нельзя использовать / определять в качестве аргумента, когда скрипт выполняет последовательность циклов
- IsMouseButtonPressed (читает нажатие клавиш Windows) может использоваться вместо аргументов
- Windows обнаруживает только MB1-5, поэтому привязка к G6 невозможна (регистрируется как 6-я кнопка)
Я прочитал, что использование couroutine.yield() или опроса могут быть использованы для остановки повторяющихся сценариев в цикле. Но я не могу найти учебник для начинающих онлайн.
Извините за нубистский вопрос!
2 ответа
Я ничего не знаю о мышах Logitech, поэтому я попытаюсь объяснить вещи, используя упрощенный, чистый пример Lua. Давайте смоделируем сценарий автоматической атаки как цикл, который печатает "A" и "B" поочередно. "A" соответствует первой части вашего цикла (нажмите и отпустите A), а "B" представляет вторую часть (нажмите и отпустите S и A).
function autoattack()
while true do
print("A")
print("B")
end
end
autoattack()
Пока все в порядке, но цикл, очевидно, будет работать вечно, и нам нужно добавить способ остановить его. Я думаю, что вы пытаетесь сделать что-то вроде:
local autoattacking = false
function autoattack()
autoattacking = true
while true do
print("A")
if not autoattacking then break end
print("B")
if not autoattacking then break end
end
end
function stop_autoattack()
autoattacking = false
end
autoattack()
stop_autoattack()
Однако, поскольку autoattack представляет собой бесконечный цикл, stop_autoattack никогда не запускается, а флаг autoattack никогда не обновляется. Как мы можем это исправить?
голосование
Вместо вызова функции и установки флага для остановки цикла, что если мы могли бы вызвать некоторый код, чтобы увидеть, должен ли цикл быть остановлен или нет?
function continue_autoattack()
print("continue autoattacking? y/n")
return (io.read("*l") == "y")
end
function autoattack()
while true do
print("A")
if not continue_autoattack() then break end
print("B")
if not continue_autoattack() then break end
end
end
autoattack()
В вашей мыши это, вероятно, будет означать использование некоторой функции isKeyPressed, если она доступна в API. Также важно отметить, что цикл autoattack по-прежнему является бесконечным циклом - просто мы изменили его, чтобы он контролировал состояние остановки.
Сопрограммы
Если мы хотим сохранить код для остановки цикла вне цикла, нам потребуется способ запуска цикла автоматической атаки по одному шагу за раз. Вот пример:
local state = 1
function autoattack_step()
if state == 1 then
print("A")
state = 2
elseif state == 2
print("B")
state = 1
elseif state == 3
print("STOPPED")
--state remains as 3
else
error("bad state") -- defensive programming; I hate if/elseif without an else
end
end
function stop_autoattack()
state = 3
end
autoattack_step()
autoattack_step()
autoattack_step()
stop_autoattack()
autoattack_step()
Так как мы разорвали цикл autoattack, теперь у нас есть возможность вызывать stop_autoattack между вызовами autoattack_step. Чтобы сделать это в вашем скрипте мыши, я думаю, что stop_autoattack может идти в обработчиках "кнопки отпускания", но я не знаю, куда бы я поместил вызовы autoattack_step. Возможно API включает что-то похожее на setTimeout или setInterval в Javascript.
Что касается сопрограмм, где они входят? Вы заметили, как нам нужно было провести существенный рефакторинг кода, чтобы разбить цикл на одношаговые фрагменты для autoattack_step? Сопрограммы - это функция Lua, которая позволяет вам писать код с использованием циклов, но при этом выполнять их "по одному шагу за раз". Когда сопрограмма достигает coroutine.yield, она возвращается к своему вызывающему. Дело в том, что при повторном вызове coroutine.resume сопрограмма продолжит выполнение с того места, где остановилась, вместо того, чтобы вернуться к началу, как это делала бы обычная функция.
local autoattacking = true
autoattack = coroutine.create(function()
while true do
print("A")
coroutine.yield()
if not autoattacking then break end
print("B")
coroutine.yield()
if not autoattacking then break end
end
end)
function stop_autoattack()
autoattacking = false
end
coroutine.resume(autoattack)
coroutine.resume(autoattack)
coroutine.resume(autoattack)
stop_autoattack()
coroutine.resume(autoattack)
coroutine.resume(autoattack)
Очень часто сопрограммы позволяют вам сделать код более читабельным, не выворачивая наизнанку множество явных переменных состояния. Нам все еще нужно иметь некоторый код "выше", вызывающий coroutine.resume, точно так же, как нам нужен был код более высокого уровня, вызывающий autoattack_step.
Итак, настолько специфично для реализации lua в Logitech в наборе игрового программного обеспечения Logitech, вам нужно использовать опрос.
После нажатия клавиши G (мыши, клавиатуры или клавиатуры) вызывается функция OnEvent(). Оказавшись внутри события, новые события OnEvent() не могут быть вызваны до тех пор, пока вы не выйдете, ваш процесс застрянет в любом цикле (так как он не может выйти из цикла, он не может выйти из вызова OnEvent().
То, что вам нужно, это прерывание для опроса.
Их три:- IsMouseButtonPressed(кнопка), IsMKeyPressed(клавиша), IsModifierPressed(модификатор).
Если вы хотите, чтобы ваша функция запускалась, пока вы удерживаете (любую указанную) кнопку мыши, вы можете использовать IsMouseButtonPressed(n), таким образом: -
while IsMouseButtonPressed(n) do
doStuff()
end
Если вы хотите сказать, что у вас есть тумблер, чтобы начать стрельбу (то есть: для автоматического нажатия кнопки мыши), то вам нужно использовать одно из двух других доступных прерываний, то есть: -
PressMouseButton(n);
while not IsModifierPressed("ctrl") do
doStuff()
end
Здесь ваш цикл будет работать, пока вы не нажмете клавишу Ctrl. Так что не пуристический тумблер (клавиша G для включения и ctrl для выключения), а сносный, я считаю.
Примечание: - после дальнейшей игры, т. Е. Тестирования, я обнаружил, что IsMouseButtonPressed(n) не зависит от PressMouseButton (n), скорее это считывается с устройства ввода-вывода, поэтому вы можете использовать IsMouseButtonPressed в качестве прерывания для автоматического нажатия мыши,
Использование G-Key, чтобы запустить действие, и щелчок мышью, чтобы прервать (завершить) действие (или вы можете использовать мышь и / или модификатор).