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

我来自 C#/Java 背景,之前从未接触过 Lua。

我想让插件在我单击并选择其他玩家作为目标时(仅在选择另外一个玩家作为目标时),在消息窗口中打印出目标的职业类别。我有两个文件,SpeccySpecs.lua(包含处理事件所需的函数)和 SpeccySpecs.xml(包含运行该函数的框架)。每当我在游戏中运行插件时,都会出现 nil 错误,因为我的 Core.lua 文件在要求 .xml 文件时返回 nil,而我的 .xml 文件从 SpeccySpecs.lua 中的 OnTarget() 函数返回 nil。

我已经尝试了多种方法来解决这个问题,其中之一是创建一个本地表并在 Core.lua 中要求它,在以后调用表中的函数,但它也返回 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 -- 战士
        then message ("目标是战士")
        elseif playerClassId == 2 -- 圣骑士
        then message ("目标是圣骑士")
        elseif playerClassId == 3 -- 猎人
        then message ("目标是猎人")
        elseif playerClassId == 4 -- 盗贼
        then message ("目标是盗贼")
     elseif playerClassId == 5 -- 牧师
        then message ("目标是牧师")
        elseif playerClassId == 6 -- 死亡骑士
        then message ("目标是死亡骑士")
        elseif playerClassId == 7 -- 萨满祭司
        then message ("目标是萨满祭司")
        elseif playerClassId == 8 -- 法师
        then message ("目标是法师")
        elseif playerClassId == 9 -- 术士
        then message ("目标是术士")
        elseif playerClassId == 10 -- 武僧
        then message ("目标是武僧")
        elseif playerClassId == 11 -- 德鲁伊
        then message ("目标是德鲁伊")
        elseif playerClassId == 12 -- 恶魔猎手
        then message ("目标是恶魔猎手")
        else message ("该职业不存在")
        end
    else message ("请选择一个玩家作为目标")
    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

感谢各位的帮助。

原文链接 https://stackoverflow.com/questions/70382462

点赞
stackoverflow用户714557
stackoverflow用户714557

下面是翻译,已保留原本的 markdown 格式:

这个过程如下:

制作框架(您的框架使用 xml)> OnLoad 事件句柄 > 注册事件 > 事件触发 > 处理事件

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

WoW 有自己的显式有序加载过程,这个过程使用 toc 文件和 xml 中的 includes。

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

# some stuff

MyAddon.xml

然后您的 MyAddon.xml 开始加载:

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

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

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 是当前的 frame,事件被隐藏在幕后,并在此编译为常规 Lua 函数并传递给它事件,… 是用于未命名参数的 Lua 类型列表,稍后可以将其拆分为 Lua 变量。

4) 您需要可重复使用的方法,以便在文件之间暴露您的 Lua 代码

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

MyAddon = {}

这是一种方法。这将创建一个单个的 Lua 表格名称唯一的全局名称,您可以将函数放到其中,以便它们可以在该文件之外的其他地方找到。

在 WoW 中,任何不是 'local' 的东西都进入单个环境的 Lua 全局名称空间,跨所有插件和 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) 添加查询 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

这应该可以为您提供整体起点。通常很难找到正确的资源,以在最初开始时为您提供帮助。您已经来了很远。

2021-12-17 20:35:26
stackoverflow用户1297035
stackoverflow用户1297035
  • 不一定需要 XML 文件,所有东西都可以在 Lua 中完成。同时,在 WoW 环境中是没有 require() 的,需要在 TOC 中列出你的文件。
  • 你链接的页面有 PLAYER_TARGET_CHANGED 事件。你可以使用 UnitIsPlayer() 检查一个单位是否是玩家。

你的代码应该长这样:

SpeccySpecs.toc

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

SpeccySpecs.lua

SpeccySpecs.lua

local classes = {
    [1] = "战士",
    [2] = "圣骑士",
    [3] = "猎人",
    [4] = "潜行者",
    [5] = "牧师",
    [6] = "死亡骑士",
    [7] = "萨满祭司",
    [8] = "法师",
    [9] = "术士",
    [10] = "武僧",
    [11] = "德鲁伊",
    [12] = "恶魔猎手",
}

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 = "这是一个"..name
            else
                text = "没有这个职业"
            end
        else
            text = "请选定一个玩家"
        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("这是一个"..UnitClass("target"))
    end
end)
2021-12-18 05:54:49