游戏Lua脚本 - 使用couroutine或民意调查?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏Lua脚本 - 使用couroutine或民意调查?相关的知识,希望对你有一定的参考价值。

我开始学习如何使用Logitech软件将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

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

经过对Logitech支持的SDK / Lua论坛的一些研究,似乎我的脚本存在问题

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

我读到使用coroutine.yield()或轮询可以用于在循环中停止重复脚本。但我找不到在线初学者的教程。

抱歉,这是一个noobish问题!

答案

我对Logitech鼠标一无所知,所以我将尝试使用简化的纯Lua示例来解释事物。让我们将autoattack脚本建模为一个循环,可以选择打印“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永远不会运行,自动攻击标志永远不会更新。我们该如何解决这个问题?

Polling

如果我们可以调用一些代码来查看是否应该停止循环,而不是调用函数并设置一个标志来停止循环?

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

Coroutines

如果我们想保持代码在循环外停止循环,我们需要一种方法一次一步地运行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_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一样。

另一答案

好吧,特别是Logitech在Logitech游戏软件套件中实现lua,你需要使用轮询。

按下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),而不是从i / o设备读取,所以你可以使用IsMouseButtonPressed作为自动鼠标按下的中断。

使用G-Key关闭操作并单击鼠标中断(结束)操作,(或者您可以同时使用鼠标和/或修改器)。

以上是关于游戏Lua脚本 - 使用couroutine或民意调查?的主要内容,如果未能解决你的问题,请参考以下文章

COCOS2DX-LUA 脚本开发之一在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途!

LUA脚本语言在网络游戏编写中主要是干啥用的?

lua脚本在游戏中的应用

游戏开发小白学Lua(上)

lua脚本在游戏中的应用

学Lua(上)