玩家工具

Time:15 分钟

Tool(工具)是用于在 Roblox 中实现武器、魔杖和其他交互式对象的特殊实例。在本文中您将学到如何创建工具、如何让玩家能够装备工具,以及如何赋予工具能力和技能。

创建一个新的工具

工具是一个容器示例,就像 Model(模型)一样。要创建一个新的工具,请在 Workspace(工作区)中右键单击,选择 Insert Object(插入对象),然后选择 Tool(工具)。

Tool_Image01.png

再次提醒您,工具只是一个容器,所以如果它是空的,就不会显示在 3D 视图中。右键单击该工具并插入新的部件。该工具现在将显示在 3D 视图中。为了能被拾取,工具里需要有一个叫做 Handle(手柄)的部件。将工具中的部件重命名为 “Handle”。现在,如果您运行游戏,您的角色将能够拿起该工具。

Tool_Image09.png

自定义工具几何

一个工具可以包含任意多个部件。但请记住,只有一个部件能被命名为 Handle,因为该部件是工具将附加到角色的手的位置。这里有几个构建工具的小贴士:

  • 当您完成构建时,请确保所有部件都没有锚固。如果工具的任何部分被锚固,工具将无法移动,角色在拿起它时将被卡住。

  • 只命名一个部件为 Handle。如果有多个称为 Handle 的部件,工具将随意选择其中一个作为与手的连接点。

  • 在创建工具时,请不要使用 Surface(表面)接合,这一点非常重要。用表面接合构造的工具在装备时会散开。当您将具有兼容表面(例如 Smooth/Weld 或 Inlet/Stud)的两个部件合并在一起时,会创建表面接合。您应将连接行为更改为 Always(始终),并确保所有部件的表面是 SmoothSmoothNoOutlines

Tool_Image07.png

Tool_Image06.png

由多个部件构建的工具示例:

Tool_Image02.png

在上面的示例中,白色部分是 Handle,其他部件使用接合连接在一起。

无手柄工具

您可以制作没有手柄或任何几何体的工具。在这种情况下,该工具就成为玩家输入的接口,而没有 3D 视图中的任何视觉表示。要制作这样的工具,只需关闭该工具的 RequiresHandle 属性。例如一个魔法物品,当它被拥有时,会给玩家一个通过键盘输入激活的特殊能力。

Tool_Image05.png

装备工具

工具可以通过多种方式装备。最简单的方法是将该工具放在工作区中,并在玩家与其发生碰撞时装备该工具。当这种情况发生时,该工具会自动添加到玩家的背包中。如果玩家当前没有任何装备,该工具将自动装备自己。请注意,这仅在工具的 RequiresHandle 属性设置为 true 时才有效。

Tool_Image04.png

您也可以使用 StarterPack 给玩家工具。每当玩家出生时,StarterPack 的所有内容都会被复制到玩家的背包中。如果您想确保所有玩家都使用相同的装备开始游戏,StarterPack 是实现此目的的最佳方式。

您还可以使用 Script(脚本)将工具提供给某个玩家,该脚本可以将该工具(或该工具的副本)放入玩家的背包中。

local copy = game.Workspace.Tool:Clone()
copy.Parent = game.Players.Player1.Backpack

您还可以通过将工具设置为玩家角色的子对象来强制玩家装备工具。

local copy = game.Workspace.Tool:Clone()
copy.Parent = game.Players.Player1.Character

使用脚本将工具给予角色时要小心!如果一个玩家已经装备了一个工具,而你强迫他们装备另一个,则两个工具可能会同时被装备,或许会导致意想不到的行为。

丢弃工具

默认情况下,玩家可以按 ← Backspace 键(在 OSX 上为 Delete)丢弃工具。 您可以将工具的 CanBeDropped 设为 false 来禁用此行为。

Tools_Image00.png

动作栏外观

当一个工具在玩家的背包里时,同时会出现在玩家屏幕底部的动作栏中。您可以自定义此栏中工具的工具提示和图标。可以通过编辑工具的 Tooltip 属性来设置工具提示。

Tool_Image08.png

您可以使用 TextureId 属性设置该工具的图标,可以像为贴花设置图像一样设置此属性的图像。

工具脚本基础知识

技术层面上,工具的目的是为玩家输入提供接口,因此有许多与它们相关的函数和事件可供开发人员与之交互。工具也是独一无二的,因为它们既可以运行常规脚本,也可以运行本地脚本。但是,由于它们与脚本的复杂关系,了解如何使用工具编写脚本的基础知识非常重要。

Script 对 LocalScript

Script 和 LocalScript 都可以监听相同的事件并调用工具上的相同函数。那么什么时候该使用哪一种呢?以下是一些一般指导原则:

代码符合下列条件时,应该使用 Script

  • 导致游戏世界发生变化(例如更改玩家健康状况、创建部件等)

代码符合下列条件时,应该使用 LocalScript

  • 依赖玩家输入(如鼠标或触摸输入)

  • 需要只向拿着工具的玩家展示一些东西

事件

脚本可以监听四个工具特有的事件:

  • Activated:当玩家开始激活工具时(单击、触摸或按游戏手柄上的 A 键)。

  • Deactivated:玩家释放激活输入时。

  • Equipped:玩家从背包中选择工具。

  • Unequipped:玩家丢弃或切换工具时。

请记住,Script 和 LocalScript 都可以监听这些事件。下面是两个脚本连接到这些事件的代码:

-- 此代码假定脚本直接位于工具内部。如果脚本位于其他位置,则必须更改下一个变量所指向的路径。
local tool = script.Parent

local function onEquip()  
end

local function onUnequip()
end

local function onActivate()
end

local function onDeactivate()
end

tool.Equipped:connect(onEquip)
tool.Unequipped:connect(onUnequip)
tool.Activated:connect(onActivate)
tool.Deactivated:connect(onDeactivate)

创建魔杖工具

在本例中,我们将演示如何制作一个简单的工具,该工具在持有者单击鼠标时会创建部件。我们将同时使用 Script 和 LocalScript 来说明它们分别的职责。

获取鼠标输入

每当用户单击鼠标时,都会触发 Activated 事件,但它不包含有关鼠标的信息。我们希望工具在用户单击的地方创建一个部件,因此知道该单击发生在空间中的哪个位置对我们来说很重要。要获得鼠标位置,我们需要使用 LocalScript,因为常规 Script 在服务器上运行,而服务器不知道任何有关用户鼠标的信息。

-- 本地 Script
local tool = script.Parent
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

local function onActivate()
  local clickLocation = mouse.Hit
end

tool.Activated:connect(onActivate)

我们先为工具、玩家和玩家的鼠标创建了变量,然后在 onActivate 函数中,我们将单击的位置存储在了一个变量中。

创建部件

现在我们知道了玩家单击的位置,我们需要创建一个部件。哪个脚本应该处理此问题?在获得 LocalScript 中的位置后立即创建部件似乎是最简单的,然而这样做的问题是,LocalScript 仅在玩家的机器上运行,如果游戏中的 Experimental Mode(实验模式)处于关闭状态(这是默认设置),则由该 LocalScript 创建的任何部件都不会复制到服务器,则其他人不会看到您创建的部件!我们希望所有其他玩家都能够看到这些新的部件并与之交互,因此我们必须使用 Script 在服务器上创建该部件。

-- 服务器端 Script
local function createPart(location)
  local part = Instance.new("Part")
  part.CFrame = location
  part.Parent = workspace
end

在 Script 和 LocalScript 之间通信

我们现在可以获取鼠标单击的位置,也可以在任意位置创建新部件,但是这些是用不同的脚本写的!我们需要让Script 和 LocalScript 之间能互相通信,以便其协同工作。为此,我们将使用前面创建的 RemoteEvent。

RemoteEvent 是可用于在 Script 和 LocalScript 之间发送信息的特殊对象。每个脚本都有一个事件侦听器,注册后就可以在事件触发时调用函数。我们也有一些函数可用于触发事件。

让我们从服务器 Script 上的侦听器开始。

-- 服务器端 Script
local tool = script.Parent
local clickEvent = tool.ClickEvent
local clickEventConnection
 
local function createPart(location)
  local part = Instance.new("Part")
  part.CFrame = location
  part.Parent = workspace
end
 
local function onClick(player, clickLocation)
  createPart(clickLocation)
end
 
local function onEquip()
  clickEventConnection = clickEvent.OnServerEvent:connect(onClick)
end
 
local function onUnequip()
  clickEventConnection:disconnect()
end
 
tool.Equipped:connect(onEquip)
tool.Unequipped:connect(onUnequip)

我们已经添加了相当多的内容,下面将进行逐步分解。首先,我们为工具和 RemoteEvent 声明了变量。我们还创建了变量 clickEventConnection,将使用它来存储事件连接。

然后,我们声明了函数 onClick,当侦听器听到事件触发时将调用该函数。该函数有两个参数,触发事件的玩家和玩家单击的位置(稍后将从 LocalScript 传入)。

onEquip 函数中,我们将 onClick 函数连接到 RemoteEvent 的 OnServerEvent 事件。这样,每当 RemoteEvent 触发时,它都会调用 onclick。最后,我们在 onUnequip 函数中的 clickEventConnection 上调用 disconnect,这样当玩家没有拿出工具时就不会触发该事件。

您可能已经注意到,我们将玩家传入了 onClick 函数,但我们从未实际使用过该变量。当您将函数绑定到 OnServerEvent 时,总是首先传入玩家参数,因此我们需要确保为它准备一个变量。

现在我们已经设置了 Script,我们只需要稍微修改一下 LocalScript,让它触发 RemoteEvent 即可。

-- 本地 Script
local tool = script.Parent
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local clickEvent = tool.ClickEvent
 
local function onActivate()
  local clickLocation = mouse.Hit
  clickEvent:FireServer(clickLocation)
end
 
tool.Activated:connect(onActivate)

为了让 LocalScript 触发 RemoteEvent,我们调用 FireServer。此函数可以接受我们想要的任意数量的参数。在本例中,我们只想传递玩家单击的位置。

现在,当我们装备好工具时,就可以通过单击来创建部件了!

Tool_Image10.png

***Roblox官方链接:玩家工具