如何有效响应游戏内目标选择事件?

How can I efficiently respond to ingame target selection events?

我是C#/Java出身,之前没接触过Lua

我希望插件显示一条消息(默认消息 window),每当我点击并瞄准另一个玩家时打印出目标的 class,并且仅当我瞄准一个玩家时.我有两个文件,SpeccySpecs.lua(包含处理事件所需的函数)和SpeccySpecs.xml(包含框架运行 函数)。每当我 运行 插件游戏时,我都会收到 nil 错误,因为我的 Core.lua 文件在需要 .xml 文件和我的 . xml 文件 returns 来自 SpeccySpecs.lua.

中的 OnTarget() 函数的 nil

我尝试通过多种方式解决这个问题,其中之一是创建一个本地 table 并在 Core.lua 中要求它,我在那里倒是最终调用了table里面的函数,但是也返回了nil。我一直在用 网站如:

https://wowpedia.fandom.com/wiki/Events

https://wowwiki-archive.fandom.com/wiki/Event_API

https://www.lua.org/

但我尝试过的方法根本没有用,我想我忘记了 Lua 代码中的一些小东西。

SpeccySpecs.lua

local function getPlayerClass()
    local playerClassName = nil;
    local playerClassFilename = nil;
    local playerClassId = nil;

    if UnitClass("target") ~= nil
    then
        playerClassName, playerClassFilename, playerClassId = UnitClass("target");
        if playerClassName == 1 -- Warrior
        then message ("It's a warrior")
        elseif playerClassId == 2 -- Paladin
        then message ("It's a paladin")
        elseif playerClassId == 3 -- Hunter
        then message ("It's a hunter")
        elseif playerClassId == 4 -- Rogue
        then message ("It's a rogue")
     elseif playerClassId == 5 -- Priest
        then message ("It's a priest")
        elseif playerClassId == 6 -- Death Knight
        then message ("It's a death knight")
        elseif playerClassId == 7 -- Shaman
        then message ("It's a shaman")
        elseif playerClassId == 8 -- Mage
        then message ("It's a mage")
        elseif playerClassId == 9 -- Warlock
        then message ("It's a warlock")
        elseif playerClassId == 10 -- Monk
        then message ("It's a monk")
        elseif playerClassId == 11 -- Druid
        then message ("It's a druid")
        elseif playerClassId == 12 -- Demon Hunter
        then message ("It's a demon hunter")
        else message ("That class does not exist")
        end
    else message ("Please target a player")
    end
end

function OnTarget(self, event, ...)
    print(event)
    return getPlayerClass()
end

SpeccySpecs.xml

<UI>
    <Script file="SpeccySpecs.lua"/>
    <Frame name="SpeccyFrame">
        <Scripts>
            <OnEvent function="OnTarget"/>
        </Scripts>
    </Frame>
</UI>

Core.lua

PlayerClassFrame = require "SpeccySpecs.xml";
return PlayerClassFrame

在此先感谢大家的帮助。

是这样的:

制作框架(你的在xml)> OnLoad 事件处理程序> 注册事件> 事件触发> 处理事件

1) 你不需要 require 或 core.lua:

WoW 有其自己的显式有序加载过程,该过程使用目录文件并包含在 xml.

您的 toc 文件可能如下所示:

# some stuff    

MyAddon.xml

然后您的 MyAddon.xml 加载:

<UI>
    <Script file="MyAddon.lua"/>
    <Frame name="MyAddonFrame">

然后首先加载 .lua 文件,这样 .lua 文件中的所有内容都可以在框架 xml 加载时被引用。

2) 您没有注册特定活动:

例如:

<OnLoad> self:RegisterEvent("PLAYER_ENTERING_WORLD") </OnLoad>

所以你最终会得到类似的东西:

<OnLoad> self:RegisterEvent("PLAYER_ENTERING_WORLD") </OnLoad>
<OnEvent> print("Event name " .. event) </OnEvent>

你需要去寻找一个特定的事件来处理当目标尽可能接近你需要的东西。

3) 您需要将遥测从事件传递到处理函数:

<OnEvent> MyAddon:OnEvent(self, event, ...) </OnEvent>

self 是当前帧,事件是在幕后给你的,因为这里的 OnEvent 只是被编译成一个常规的 Lua 函数并将事件传递给它,并且...是一个 Lua 用于未命名参数的列表类型,稍后您可以将其分解为 Lua 个变量。

4) 你需要一种 repeatable 方法来跨文件公开你的 Lua 代码

这需要以不与 WoW 或其他插件冲突的方式进行。

MyAddon = {}

是一种方式。这使得单个 Lua table 具有全局唯一名称,您可以将函数粘贴到其中,以便可以在该文件之外的其他地方找到它们。

WoW 中任何不是 'local' 的东西都会进入一个单一的环境 Lua 全局名称 space 所有插件和 wow。

5) 您需要接受来自事件的遥测参数:

并处理遥测数据以找出您更具体需要的东西

function MyAddon:OnEvent(frame, event, ...)
    if event == "SOME_EVENT_NAME" then
        local _, name = ...
        if is this some player then
            MyAddon:SomePlayerDidSomething(name)
        end
    elseif event == "SOME_EVENT_NAME" then
    end
end

这应该可以帮助您开始基本的插件流程。


在这一切都奏效之后,您需要一种方法让业务端更多地由数据驱动,这在理论上会使其代码量更小,速度更高效。

6) 添加一个 table 来查找 id 的字符串:

MyAddon.classNames = {
    [1] = "warrior",
    [2] = "paladin",
    [3] = "hunter",
}

https://www.lua.org/pil/3.6.html

这将允许您构建更像这样的代码:

local className = self.classNames[playerClassId]
if className then
    message("It's a " .. className .. ".")
end

这应该可以帮助您全面入门。很难经常找到合适的资源来让您从一开始就开始工作。你走得太远了。

  • 不一定需要XML文件,在Lua中都可以完成。此外,require() 在 WoW 环境中不存在,这是通过在 TOC
  • 中列出您的文件来处理的
  • 您链接的页面有 PLAYER_TARGET_CHANGED event. You can check if a unit is player with UnitIsPlayer()

您的代码将如下所示:

SpeccySpecs.toc

## Interface: 90105
## Version: 1.0.0
## Title: SpeccySpecs
## Notes: Some Description
## Author: YourName

SpeccySpecs.lua

SpeccySpecs.lua

local classes = {
    [1] = "warrior",
    [2] = "paladin",
    [3] = "hunter",
    [4] = "rogue",
    [5] = "priest",
    [6] = "death knight",
    [7] = "shaman",
    [8] = "mage",
    [9] = "warlock",
    [10] = "monk",
    [11] = "druid",
    [12] = "demon hunter",
}

local function getPlayerClass(unit)
    if UnitExists(unit) then
        local text
        if UnitIsPlayer(unit) then
            local _, _, classId = UnitClass(unit)
            local name = classes[classId]
            if name then
                text = "It's a "..name
            else
                text = "That class does not exist"
            end
        else
            text = "Please target a player"
        end
        message(text)
    end
end

local function OnEvent(self, event)
    getPlayerClass("target")
end

local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_TARGET_CHANGED")
f:SetScript("OnEvent", OnEvent)

或者作为一个最小的例子:

local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_TARGET_CHANGED")
f:SetScript("OnEvent", function(self, event)
    if UnitIsPlayer("target") then
        print("It's a "..UnitClass("target"))
    end
end)