Игра 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, похоже, что проблема с моим скриптом

  1. Флаги нельзя использовать / определять в качестве аргумента, когда скрипт выполняет последовательность циклов
  2. IsMouseButtonPressed (читает нажатие клавиш Windows) может использоваться вместо аргументов
  3. 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, чтобы запустить действие, и щелчок мышью, чтобы прервать (завершить) действие (или вы можете использовать мышь и / или модификатор).

Другие вопросы по тегам