是时候把这一切工作聚在一起了!现在你已经创建了光束和粒子组件,你将添加三个预制脚本。这些脚本管理教程,告诉组件何时做什么。例如,脚本会为新玩家创建光束并在他们与目标互动时发射粒子。
存储光束和粒子
在添加脚本之前,光束和粒子需要移动到脚本需要复制它们的地方。
在 复制存储 中,创建一个名为 PlayerTutorial 的新文件夹。将教程光束从测试玩家移出,并移至新文件夹。
在 服务器存储 中,创建一个名为 TutorialParticles 的文件夹。将 爆破 粒子从 TestPlayer 移出到该文件夹。
一旦光束和粒子发射器移动,你就不再需要测试玩家。 删除 测试玩家,因为脚本完成后将与真实玩家一起工作。
创建事件
每次玩家与目标互动时,教程脚本需要知道,以便可以更新该玩家的进度并发出粒子效果。要向脚本发送信号,可以使用 事件 发送。
在 ReplicatedStorage > PlayerTutorial 中,创建两个 远程事件 对象。命名为 下一个目标 和 教程结束 。
添加脚本
以下三个脚本将查找早期创建的粒子发射器和光束对象,并管理教程系统。
在 ReplicatedStorage > PlayerTutorial > 创建一个名为 TutorialManager 的新模块脚本。
替换默认代码,通过复制并粘贴下面的整个代码。
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该脚本运行教程中管理玩家进度的代码。这包括与目标互动的运行代码或教程结束时发生的事情等任务。
在 服务器脚本服务 中,创建一个名为 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.Enabled = trueplayerBeam.Parent = humanoidRootPartendlocal 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)播放项目以测试脚本。使用互动功能从一个展位移动到另一个展位,看看代码是否运行。
排除问题的提示
问题 : 游戏开始时发生粒子。
进入服务器存储 > 教程粒子 > 爆炸。检查启用关闭。 问题 : 编译器中的警告,例如无限产出。
因为脚本正在寻找特定位置的特定对象,所以有可能是部分名称不正确。双方检查游戏中每个部分的名称和位置是否匹配教程。
脚本优缺点和限制
如果你在体验中使用此教程系统,请记住以下几点: 好处
- 例如,教程结束等事件可以用来触发其他脚本。例实例,当这个事件发生时,你可以奖励玩家一件特殊物品。
- 教程参与者脚本可以一次播放多个粒子。您可以在 ServerStorage/TutorialParticles 中添加更多粒子以获得更复杂的效果。 限制
- 教程中玩家的进度不是持久的,这意味着你必须编写一种方法来保存那些进度。如需指导,请参阅文章:保存数据。