1

我开始学习如何通过罗技软件使用 Lua 脚本编写不同的游戏配置文件。

首先我尝试使用 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

所以我试图将它绑定到我的 logiech 鼠标的 G6 按钮(使用 mouse_button_press == 6)使用 MB6 设置标志有效,但结束循环/中断循环不能由 MB6 触发

经过罗技支持的SDK/Lua论坛的一些研究,似乎我的脚本有问题

  1. 脚本执行循环序列时,标志不能用作/检测为参数
  2. IsMouseButtonPressed(读取windows keypress)可以在地方或参数中使用
  3. Windows 仅检测 MB1-5,因此无法绑定到 G6(注册为第 6 个按钮)

我读到使用 couroutine.yield() 或轮询可用于停止循环中的重复脚本。但是我在网上找不到适合初学者的教程。

对不起这个noobish问题!

4

2 回答 2

5

我对罗技鼠标一无所知,所以我将尝试使用简化的纯 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()

但是,由于自动攻击是一个无限循环,因此 stop_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 中可用的话。同样重要的是要注意自动攻击循环仍然是一个无限循环——只是我们改变了它,所以它可以控制它的停止条件。

协程

如果我们想保持代码在循环外停止循环,我们将需要一种方法来一次运行自动攻击循环。这是一个例子:

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_step 的调用之间调用 stop_autoattack。要在鼠标脚本中执行此操作,我认为 stop_autoattack 可以进入“释放按钮”处理程序,但我不知道将 autoattack_step 调用放在哪里。也许 API 包含类似于 Javascript 中的 setTimeout 或 setInterval 的内容。

至于协程,它们从何而来?您是否注意到我们需要进行一些实质性的代码重构以将循环分解为 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 一样。

于 2014-07-06T07:01:19.290 回答
4

好的,那么具体到罗技游戏软件套件中罗技的lua实现,就需要使用轮询了。

一旦按下 G 键(鼠标、键盘或键盘),就会调用 OnEvent() 函数。一旦进入 on 事件,在退出之前无法调用任何新的 OnEvent() 事件,您的进程将“卡在”任何循环中(因为它无法退出循环,因此无法退出 OnEvent() 调用。

您需要的是一个轮询中断

有三个:- IsMouseButtonPressed(button)、IsMKeyPressed(key)、IsModifierPressed(modifier)。

如果您希望您的例程在按住(任何指定的)鼠标按钮时运行,您可以使用 IsMouseButtonPressed(n) 如下:-

while IsMouseButtonPressed(n) do
    doStuff()
end

如果您想说,有一个拨动开关开始触发(即:自动按下鼠标按钮),那么您必须使用其他两个可用中断之一,即:-

PressMouseButton(n);
while not IsModifierPressed("ctrl") do
    doStuff()
end

在这里,您的循环将一直运行,直到您按住 ctrl 键。所以不是一个纯粹的拨动开关(一个 G 键打开和 ctrl 关闭),但我相信可以通过。

注意:-经过进一步的播放,呃,测试,我发现 IsMouseButtonPressed(n) 是独立于 PressMouseButton(n) 的,而是从 i/o 设备读取的,所以你可以使用 IsMouseButtonPressed 作为自动鼠标按下的中断.

使用 G 键启动动作并单击鼠标中断(结束)动作,(或者您可以同时使用鼠标和/或修改器)。

于 2017-12-29T11:34:17.983 回答