Trong hoạt hình, tweening là quá trình tạo ra các khung hình trung gian giữa hai điểm chính trong một chuỗi. Khi thiết kế giao diện người dùng, bạn có thể sử dụng tweening để chuyển đổi một GuiObject một cách mượt mà từ trạng thái này sang trạng thái khác, chẳng hạn như:
- Tăng kích thước của một nút khi người dùng chọn nó.
- Trượt các menu UI vào và ra từ các cạnh của màn hình.
- Dần dần hoạt hình một thanh sức khỏe giữa hai độ rộng khi người dùng nhận được một sự tăng cường sức khỏe.
Tween một thuộc tính
Vị trí
Để tween vị trí của một GuiObject:
- Đặt AnchorPoint cho đối tượng.
- Truyền một TweenInfo và vị trí mục tiêu vào TweenService:Create().
- Chạy tween với Tween:Play().
Đoạn mã sau di chuyển một ImageLabel trong một ScreenGui đến chính giữa màn hình:
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
object.AnchorPoint = Vector2.new(0.5, 0.5)
local targetPosition = UDim2.new(0.5, 0, 0.5, 0)
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {Position = targetPosition})
tween:Play()Kích thước
Để tween kích thước của một GuiObject:
- Gắn một UIAspectRatioConstraint vào đối tượng để duy trì tỷ lệ khung hình thiết kế của nó khi tweening.
- Truyền một TweenInfo và kích thước mục tiêu vào TweenService:Create().
- Chạy tween với Tween:Play().
Đoạn mã sau thay đổi kích thước một ImageLabel trong một ScreenGui đến 40% chiều rộng hoặc chiều cao của màn hình (tùy thuộc vào chiều nào nhỏ hơn) từ điểm neo trung tâm của đối tượng:
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
object.AnchorPoint = Vector2.new(0.5, 0.5)
local aspectRatioConstraint = Instance.new("UIAspectRatioConstraint")
aspectRatioConstraint.Parent = object
local targetSize = UDim2.new(0.4, 0, 0.4, 0)
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {Size = targetSize})
tween:Play()Xoay
Để tween xoay của một GuiObject:
- Đặt AnchorPoint cho đối tượng để xoay quanh.
- Xác định Rotation mục tiêu cho đối tượng.
- Truyền một TweenInfo và góc xoay mục tiêu vào TweenService:Create().
- Chạy tween với Tween:Play().
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
object.AnchorPoint = Vector2.new(0.5, 0.5)
local targetRotation = 45
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {Rotation = targetRotation})
tween:Play()Độ trong suốt
Nhiều thuộc tính điều khiển độ trong suốt của UI, tùy thuộc vào loại đối tượng. Bạn có thể tween từng thuộc tính này một cách riêng lẻ hoặc kết hợp thông qua một multi-property tween. Ngoài ra, bạn có thể tween độ trong suốt tổng thể của một đối tượng bằng cách đặt nó vào trong một CanvasGroup và tween độ trong suốt của nhóm GroupTransparency.
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
local targetTransparency = 0.8
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {ImageTransparency = targetTransparency})
tween:Play()local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local canvasGroup = ScreenGui:WaitForChild("CanvasGroup")
local targetTransparency = 0.8
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(canvasGroup, tweenInfo, {GroupTransparency = targetTransparency})
tween:Play()Màu sắc
Nhiều thuộc tính điều khiển màu sắc của UI, tùy thuộc vào loại đối tượng. Bạn có thể tween từng thuộc tính này một cách riêng lẻ hoặc kết hợp thông qua một multi-property tween. Ngoài ra, bạn có thể tween màu sắc tổng thể của một đối tượng bằng cách đặt nó vào trong một CanvasGroup và tween màu sắc của nhóm GroupColor3.
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
local targetColor = Color3.fromRGB(255, 0, 0)
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {ImageColor3 = targetColor})
tween:Play()local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local canvasGroup = ScreenGui:WaitForChild("CanvasGroup")
local targetColor = Color3.fromRGB(255, 0, 0)
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(canvasGroup, tweenInfo, {GroupColor3 = targetColor})
tween:Play()Stroke
Nhiều thuộc tính điều khiển các đường viền UI, tùy thuộc vào loại đối tượng.
Ngoài ra, bạn có thể áp dụng một UIStroke con và tween độ dày, màu sắc và/hoặc độ trong suốt của nó.
| Đối tượng UI | Thuộc tính |
|---|---|
| UIStroke | Color, Thickness, Transparency |
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("TextLabel")
local stroke = Instance.new("UIStroke")
stroke.Color = Color3.fromRGB(255, 255, 255)
stroke.Thickness = 5
stroke.Parent = object
local targetColor = Color3.fromRGB(255, 0, 0)
local targetThickness = 10
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(stroke, tweenInfo, {Color = targetColor, Thickness = targetThickness})
tween:Play()Multi-property tweens
Bạn có thể kết hợp bất kỳ single-property tweens nào thành các tween phức tạp hơn bằng cách truyền nhiều thuộc tính mục tiêu vào TweenService:Create(), ví dụ như vị trí + xoay hoặc kích thước + độ trong suốt.
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
object.AnchorPoint = Vector2.new(0.5, 0.5)
local targetPosition = UDim2.new(0.5, 0, 0.5, 0)
local targetRotation = 45
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {Position = targetPosition, Rotation = targetRotation})
tween:Play()local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
object.AnchorPoint = Vector2.new(0.5, 0.5)
local aspectRatioConstraint = Instance.new("UIAspectRatioConstraint")
aspectRatioConstraint.Parent = object
local targetSize = UDim2.new(0.4, 0, 0.4, 0)
local targetTransparency = 0.8
local tweenInfo = TweenInfo.new(2)
local tween = TweenService:Create(object, tweenInfo, {Size = targetSize, ImageTransparency = targetTransparency})
tween:Play()Chuỗi tween
Bạn có thể nối các hoạt hình UI để xảy ra lần lượt bằng cách phát các tween tiếp theo sau sự kiện Completed của tween trước đó. Ví dụ, đoạn mã sau di chuyển một đối tượng đến chính giữa màn hình, sau đó xoay nó 45°.
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
local object = ScreenGui:WaitForChild("ImageLabel")
object.AnchorPoint = Vector2.new(0.5, 0.5)
local targetPosition = UDim2.new(0.5, 0, 0.5, 0)
local targetRotation = 45
local tweenInfo = TweenInfo.new(2)
local positionTween = TweenService:Create(object, tweenInfo, {Position = targetPosition})
local rotationTween = TweenService:Create(object, tweenInfo, {Rotation = targetRotation})
-- Ban đầu phát tween vị trí
positionTween:Play()
-- Phát tween xoay khi hoàn thành tween vị trí
positionTween.Completed:Connect(function()
rotationTween:Play()
end)Chuyển tiếp kiểu
Các đối tượng UI cũng có thể được hoạt hình thông qua chuyển tiếp kiểu, tương tự như chuyển tiếp CSS, nơi một hoặc nhiều thuộc tính UI được tween thông qua các định nghĩa StyleRule. Xem hướng dẫn Trình chỉnh sửa kiểu để biết chi tiết.

Tùy chọn easing
Sử dụng các tùy chọn easing của TweenInfo, bạn có thể kiểm soát kiểu và hướng easing của các hoạt hình UI.
Kiểu
Enum.EasingStyle đặt tỷ lệ nội suy từ đầu đến cuối. Theo mặc định, kiểu easing được đặt thành Enum.EasingStyle.Quad.
| Kiểu | Mô tả |
|---|---|
| Đường thẳng | Di chuyển với tốc độ không đổi. |
| Sine | Tốc độ được xác định bởi một sóng sine cho một chuyển động easing nhẹ nhàng. |
| Quad | Tương tự như Sine nhưng với một đường cong sắc nét hơn dựa trên nội suy bậc hai. |
| Cubic | Tương tự như Quad nhưng với một đường cong sắc nét hơn dựa trên nội suy bậc ba. |
| Quart | Tương tự như Cubic nhưng với một đường cong sắc nét hơn nữa dựa trên nội suy bậc bốn. |
| Quint | Tương tự như Quart nhưng với một đường cong sắc nét hơn nữa dựa trên nội suy bậc năm. |
| Exponential | Đường cong sắc nét nhất dựa trên nội suy mũ. |
| Hình tròn | Đi theo một cung tròn, sao cho gia tốc mạnh hơn và giảm tốc nhẹ nhàng hơn so với Quint hoặc Exponential. |
| Quay lại | Nhẹ nhàng vượt quá mục tiêu, sau đó quay lại vị trí. |
| Nảy | Nảy ngược lại nhiều lần sau khi đạt được mục tiêu, trước khi cuối cùng ổn định. |
| Đàn hồi | Di chuyển như thể gắn với một dây cao su, vượt quá mục tiêu nhiều lần. |

local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Cubic)
local tween = TweenService:Create(object, tweenInfo, {Rotation = 45})Hướng
Enum.EasingDirection xác định cách mà nội suy kiểu easing áp dụng cho một đối tượng, với mặc định là Ra. Lưu ý rằng một tween với kiểu easing Đường thẳng không bị ảnh hưởng, vì nội suy đường thẳng là không đổi từ đầu đến cuối.
| Hướng | Mô tả |
|---|---|
| Vào | Kiểu easing áp dụng theo hướng tiến về phía trước. |
| Ra | Kiểu easing áp dụng theo hướng ngược lại. |
| VàoRa | Kiểu easing áp dụng tiến về phía trước trong nửa đầu và ngược lại trong nửa sau. |
local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut)
local tween = TweenService:Create(object, tweenInfo, {Rotation = 45})Hiệu ứng đánh máy trên văn bản
Bạn có thể dễ dàng nâng cao UI dựa trên văn bản, chẳng hạn như banner cắt cảnh, hướng dẫn người chơi và lời nhắc, với các hiệu ứng hoạt hình. Hiệu ứng "đánh máy" là lý tưởng cho TextLabels kể một câu chuyện, xuất các cuộc hội thoại của NPC, v.v.
Tạo một ModuleScript mới trong ReplicatedStorage.
Đổi tên script mới thành AnimateUI.

Dán đoạn mã sau vào script:
ModuleScript - AnimateUIlocal LocalizationService = game:GetService("LocalizationService")local Players = game:GetService("Players")local SOURCE_LOCALE = "en"local translator = nillocal AnimateUI = {}function AnimateUI.loadTranslator()pcall(function()translator = LocalizationService:GetTranslatorForPlayerAsync(Players.LocalPlayer)end)if not translator thenpcall(function()translator = LocalizationService:GetTranslatorForLocaleAsync(SOURCE_LOCALE)end)endendfunction AnimateUI.typeWrite(guiObject, text, delayBetweenChars)guiObject.Visible = trueguiObject.AutoLocalize = falselocal displayText = text-- Dịch văn bản nếu có thểif translator thendisplayText = translator:Translate(guiObject, text)end-- Thay thế các thẻ ngắt dòng để vòng lặp grapheme không bỏ lỡ các ký tự đódisplayText = displayText:gsub("<br%s*/>", "\n")-- Xóa các thẻ RichText vì hoạt hình ký tự theo ký tự sẽ làm hỏng các thẻdisplayText = displayText:gsub("<[^<>]->", "")-- Đặt văn bản đã dịch/đã sửa đổi trên chaguiObject.Text = displayTextlocal index = 0for first, last in utf8.graphemes(displayText) doindex += 1guiObject.MaxVisibleGraphemes = indextask.wait(delayBetweenChars)endendreturn AnimateUITạo một TextLabel ở một vị trí phù hợp, chẳng hạn như trong một ScreenGui được gán cho StarterGui.
Chèn một LocalScript mới làm con trực tiếp của nhãn và dán vào đoạn mã sau. Lưu ý rằng mỗi thông điệp được xuất ra bằng cách gọi AnimateUI.typeWrite() với các tham số cho đối tượng cha, chuỗi để xuất và độ trễ giữa các ký tự.
LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local AnimateUI = require(ReplicatedStorage:WaitForChild("AnimateUI"))local label = script.Parent-- Tải trình dịch nếu trò chơi được địa phương hóa--AnimateUI.loadTranslator()local message1 = [[Đằng sau cánh cửa này là<br /><font size="46" color="rgb(255,50,25)">Great Zorgoth...</font> <font size="40">🗡</font>]]AnimateUI.typeWrite(label, message1, 0.05)task.wait(1)local message2 = [[...người cai trị ngục tối này <font color="rgb(255,200,50)">không bị thách thức!</font> <font size="30">😈</font>]]AnimateUI.typeWrite(label, message2, 0.05)