开始之前
会使用 Touched 和 busy。新建 Lesson12,了解 Position 是 Vector3。
Roblox Studio · 第 12 课
用 TweenService、TweenInfo 和 Completed 做一扇能打开、等待、关闭的门。
Course overview
直接修改 Position 会让门瞬间跳到新位置。TweenService 则负责计算中间过程,让你指定“从这里到那里,用一秒完成”。
我们先用触碰开门,再在下一课换成主动按键。门只是视觉与碰撞练习,不承担乘客运输,也不当作安全权限边界。
会使用 Touched 和 busy。新建 Lesson12,了解 Position 是 Vector3。
触碰开关后,门上升一秒、保持两秒、下降一秒,期间不会重复启动。
连踩开关不会抖动;每次关门都回到同一位置,不会越升越高。

Learning route
每完成一小步,就测试一次。先说出你预计会看到什么,再用 Play 和 Output 检查,不用急着一次写完所有代码。
门应该 Anchored=true,这样重力不会和补间争着控制它。碰撞在打开期间关闭,关门时也暂时不阻挡,避免把角色夹在动画途中。
TweenService:Create(对象, TweenInfo, 目标表) 要知道改谁、怎样变化、变成什么。目标表里的键必须是真实属性名,例如 Position。
Completed:Wait() 等待这段动画结束,然后才开始保持或关闭。比随意猜一个 task.wait 时长更清楚。
把时长从 1 改成 2,门会更慢。把 Sine 改为 Linear,则变化速度更加均匀。每次只改一项,你才知道差别来自哪里。
一次开门好看还不够,连续运行五轮后也应该准确归位。位置越来越偏,通常说明起点或终点在循环过程中被重新累加了。
Step by step
门应该 Anchored=true,这样重力不会和补间争着控制它。碰撞在打开期间关闭,关门时也暂时不阻挡,避免把角色夹在动画途中。
练习时不要站在最终关门位置。真正的大门还需要检测门口是否有人,本课先把完整动画周期做清楚。
Step by step
TweenService:Create(对象, TweenInfo, 目标表) 要知道改谁、怎样变化、变成什么。目标表里的键必须是真实属性名,例如 Position。
TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut) 表示用一秒完成,起步与结束都比较柔和。Create 只是准备动画,Play 才会启动。

Step by step
Completed:Wait() 等待这段动画结束,然后才开始保持或关闭。比随意猜一个 task.wait 时长更清楚。
busy 在任何等待之前设为 true,整个开关周期结束后才恢复。另一个玩家此时踩开关,也不会创建第二套相互争抢的动画。
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local switch = script.Parent
local gate = workspace:WaitForChild("Gate")
local closedPosition = gate.Position
local openPosition = closedPosition + Vector3.new(0, 10, 0)
local info = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
local busy = false
switch.Touched:Connect(function(hit)
if busy then return end
local character = hit:FindFirstAncestorOfClass("Model")
local player = character and Players:GetPlayerFromCharacter(character)
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not player or not humanoid or humanoid.Health <= 0 then return end
busy = true
gate.CanCollide = false
local opening = TweenService:Create(gate, info, {Position = openPosition})
opening:Play()
opening.Completed:Wait()
task.wait(2)
local closing = TweenService:Create(gate, info, {Position = closedPosition})
closing:Play()
closing.Completed:Wait()
gate.CanCollide = true
busy = false
end)
Step by step
把时长从 1 改成 2,门会更慢。把 Sine 改为 Linear,则变化速度更加均匀。每次只改一项,你才知道差别来自哪里。
同一属性上同时运行的补间会互相影响。不要在另一个脚本里又不停给 Gate.Position 赋值。
Step by step
一次开门好看还不够,连续运行五轮后也应该准确归位。位置越来越偏,通常说明起点或终点在循环过程中被重新累加了。
Tween 移动的 Anchored 平台不保证像电梯一样可靠带着角色移动。做载人平台需要额外研究物理与角色行为,不在这里直接照搬。
Homework
把开关动画改为两秒,保持时间改为三秒。
在 busy 时把开关变橙色,完成后恢复蓝色。
把终点偏移改为 X 方向,确保侧面有足够空间。
Exit questions
还需要对生成的 Tween 调用 Play。
避免每次开门从变化后的坐标再累加距离,导致位置漂移。
在开门、保持、关门全部结束之后。
不应直接照搬,补间移动与可靠运送角色不是同一个问题。
Explore further
正文代码可以直接复制。先确认脚本类型、放置位置,以及这段代码是完整版本还是小实验;不要把同一脚本的多个版本叠加运行。界面参考图已标注来源,图中的对象名可能与本课不同,请以操作步骤为准。