是时候把这些工作结合起来了!现在你已经创建了光束和粒子组件,你将添加三个预制脚本。这些脚本通过告诉组件何时做什么来管理教程。例如,当新玩家与目标交互时,它们会创建光束。
存储光束和粒子
在添加脚本之前,光束和粒子需要移动到可以根据需要制作复制的位置。
在 ReplicatedStorage 中,创建一个名为 PlayerTutorial 的新文件夹。移动 TutorialBeam 出 TestPlayer,并且在新文件夹中。
在 ServerStorage 中,创建一个名为 TutorialParticles 的文件夹。将 Burst 粒子从 TestPlayer 移动到该文件夹。
当光束和粒子发射器移动时,您不再需要 TestPlayer。 删除 TestPlayer,因为脚本将在完成时与实际玩家工作。
创建事件
每次玩家与目标互动时,教程脚本需要知道, чтобы它可以更新该玩家的进度并发出粒子效果。要向脚本发送信息,信号可以使用 事件 。
在 ReplicatedStorage > PlayerTutorial 中,创建两个 RemoteEvent 对象。命名它们 下一个目标 和 教程结束 。
添加脚本
以下三个脚本将寻找早先创建的粒子发射器和光束对象,并管理教程系统。
在 ReplicatedStorage > PlayerTutorial > 创建一个名为 TutorialManager 的新 ModuleScript 。
将默认代码替换为复制并粘贴以下全部代码。
local TutorialManager = {}local ReplicatedStorage = game:GetService("ReplicatedStorage")local tutorialFolder = ReplicatedStorage:WaitForChild("PlayerTutorial")local TutorialEndEvent = tutorialFolder:WaitForChild("TutorialEnd")local NextGoalEvent = tutorialFolder:WaitForChild("NextGoal")-- 注意目标零件必须在表中订购,否则目标订购可能会在游戏中不同local goalParts = {workspace.TutorialGoals.GoalPart1,workspace.TutorialGoals.GoalPart2}local function checkTutorialEnd(player, goalParts)local currentIndex = player:WaitForChild("GoalProgress")return currentIndex.Value >= #goalPartsendlocal function finishTutorial(player)local playerBeam = player.Character.HumanoidRootPart:FindFirstChildOfClass("Beam")playerBeam:Destroy()print(player.Name .. " finished the tutorial")-- 用于存储更多验证码。例如,如果您想向服务器发送消息以执行其他任务endfunction TutorialManager.interactGoal(player)NextGoalEvent:FireServer()endfunction TutorialManager.getTutorialGoals()return goalPartsendfunction TutorialManager.nextGoal(player, goalParts)if checkTutorialEnd(player, goalParts) thenfinishTutorial(player)else-- 增加玩家的目标追踪器local currentGoalIndex = player:WaitForChild("GoalProgress")currentGoalIndex.Value += 1endend-- 创建一个 int 值来本地跟踪玩家的进度通过教程目标function TutorialManager.setupPlayerProgress(player)local currentGoalProgress = Instance.new("IntValue")currentGoalProgress.Name = "GoalProgress"currentGoalProgress.Value = 1currentGoalProgress.Parent = playerendreturn TutorialManager此脚本在教程中管理玩家的进度。这包括与目标交互的代码运行,或教程结束后发生的事件。
在 ServerScriptService 中,创建一个名为 TutorialParticles 的新 脚本 。
粘贴以下代码。
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local ServerStorage = game:GetService("ServerStorage")local tutorialFolder = ReplicatedStorage:WaitForChild("PlayerTutorial")local NextGoalEvent = tutorialFolder:WaitForChild("NextGoal")local EMIT_RATE = 50local function playParticleBurst(player)local character = player.Character or player.CharacterAdded:Wait()local humanoidRootPart = character:WaitForChild("HumanoidRootPart")local particleAttachment = humanoidRootPart:WaitForChild("ParticleAttachment")-- 通过附件上的粒子进行筛选,并根据粒子类型进行播放for _, particle in particleAttachment:GetChildren() doif particle:IsA("ParticleEmitter") thenparticle:Emit(EMIT_RATE)endendendlocal function setupPlayerParticles(player)player.CharacterAdded:Connect(function(character)local humanoidRootPart = character:WaitForChild("HumanoidRootPart")local playerParticleAttachment = Instance.new("Attachment")playerParticleAttachment.Name = "ParticleAttachment"playerParticleAttachment.Parent = humanoidRootPart-- 在文件夹中克隆粒子,即使有多个粒子并且添加到玩家for _, emitter in ServerStorage.TutorialParticles:GetChildren() doemitter:Clone().Parent = playerParticleAttachmentendend)endPlayers.PlayerAdded:Connect(setupPlayerParticles)NextGoalEvent.OnServerEvent:Connect(playParticleBurst)这个脚本在玩家与目标互动时播放爆炸粒子。还有一个名为 EMIT_RATE 的变量,它确定在交互中产生多少粒子。
在 StarterPlayer > StarterPlayerScripts 中,创建一个名为 TutorialScript 的新 本地脚本 。
然后,复制下面的脚本。 此脚本创建并管理使用来引导玩家的光束。
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local tutorialFolder = ReplicatedStorage:WaitForChild("PlayerTutorial")local TutorialManager = require(tutorialFolder:WaitForChild("TutorialManager"))local TutorialEndEvent = tutorialFolder:WaitForChild("TutorialEnd")local player = Players.LocalPlayerlocal goalParts = TutorialManager.getTutorialGoals()local playerBeam = nillocal goalIndex = nillocal function getTargetAttachment()local currentTarget = goalParts[goalIndex.Value]local interactionPart = currentTarget:FindFirstChild("InteractionPart")local attachment = interactionPart and interactionPart:FindFirstChildOfClass("Attachment")if not attachment thenattachment = Instance.new("Attachment")attachment.Name = "BeamAttachment"attachment.Parent = currentTargetendreturn attachmentendlocal function updateBeamTarget()playerBeam = player.Character.HumanoidRootPart:FindFirstChildOfClass("Beam")local targetBeamAttachment = getTargetAttachment()if targetBeamAttachment thenplayerBeam.Attachment1 = targetBeamAttachmentelsewarn("Attachment not found in a goal. Check that goals have attachments or they're included under the InteractionPart")endendlocal function setupGoals()for _, part in goalParts dolocal interactionPart = part:FindFirstChild("InteractionPart")local proximityPrompt = interactionPart and interactionPart:FindFirstChild("ProximityPrompt")if proximityPrompt thenproximityPrompt.Triggered:Connect(function(player)proximityPrompt.Enabled = falseTutorialManager.nextGoal(player, goalParts)TutorialManager.interactGoal(player)end)elsewarn("Proximity prompt not included in goal. Add one to each goal part under the InteractionPart")endendendlocal function createBeamForCharacter(character)local humanoidRootPart = character:WaitForChild("HumanoidRootPart")local playerBeamAttachment = Instance.new("Attachment")local beamTemplate = tutorialFolder:WaitForChild("TutorialBeam")if not beamTemplate thenwarn("Tutorial Beam not found in ReplicatedStorage")endplayerBeamAttachment.Name = "BeamAttachment"playerBeamAttachment.Parent = humanoidRootPartlocal targetBeamAttachment = getTargetAttachment()playerBeam = beamTemplate:Clone()playerBeam.Attachment0 = playerBeamAttachmentplayerBeam.Attachment1 = targetBeamAttachmentplayerBeam.Parent = humanoidRootPartplayerBeam.Enabled = trueendlocal function setupPlayer()setupGoals()TutorialManager.setupPlayerProgress(player)goalIndex = player:WaitForChild("GoalProgress")player.CharacterAdded:Connect(createBeamForCharacter)if player.Character thencreateBeamForCharacter(player.Character)endendsetupPlayer()goalIndex.Changed:Connect(updateBeamTarget)播放项目以测试脚本。从一个摊位移动到另一个摊位,使用交互功能来确定代码是否运行。
排查提示
发生问题 : 粒子会在游戏开始时播放。
进入服务器存储 > 教程粒子 > 爆裂。检查启用以关闭。 发出 : 在编译器上发出警告,例如“无限产出”。
因为脚本在某些位置寻找特定对象,因此有可能部分的名称会错误。请确认每个部分在游戏中的名称和位置与教程中的对象匹配。
脚本优势和限制
如果您在体验中使用此教程系统,请记住以下几点: 好处
- TutorialEnd 等级的事件可以用来触发其他脚本。 例实例,你可以在此事件发生时奖励玩家一件特殊物品。
- TutorialParticles 脚本可以同时播放多个粒子。 您可以在服务器存储/TutorialParticles 中添加更多粒子以获得更复杂的效果。 限制
- 玩家在教程中的进度不是持久的,这意味着您需要编写一些方法来保存该进度。 有关指导,请参阅文章:保存数据。