Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- 字体初始化
- if isfile("SmallestPixel7.font") then
- delfile("SmallestPixel7.font")
- end
- writefile("fs-tahoma-8px.ttf", game:HttpGet("https://github.com/i77lhm/storage/raw/refs/heads/main/fonts/fs-tahoma-8px.ttf"))
- -- 字体系统
- local Font = {
- new = function(path) return path end,
- Register = function() end,
- GetRegistry = function() end
- }
- Font = setreadonly(Font, false)
- local fontAsset
- do
- getsynasset = getcustomasset or getsynasset
- function Font:Register(Name, Weight, Style, Asset)
- if not isfile(Name .. ".font") then
- if not isfile(Asset.Id) then
- writefile(Asset.Id, Asset.Font)
- end
- local Data = {
- name = Name,
- faces = {{
- name = "Regular",
- weight = Weight,
- style = Style,
- assetId = getsynasset(Asset.Id)
- }}
- }
- writefile(Name .. ".font", game:GetService("HttpService"):JSONEncode(Data))
- return getsynasset(Name .. ".font")
- else
- warn("Font already registered")
- end
- end
- function Font:GetRegistry(Name)
- if isfile(Name .. ".font") then
- return getsynasset(Name .. ".font")
- end
- end
- Font:Register("SmallestPixel7", 400, "normal", {Id = "fs-tahoma-8px.ttf", Font = ""})
- fontAsset = Font:GetRegistry("SmallestPixel7")
- end
- -- 配置
- local config = {
- minWidth = 120,
- maxWidth = 400,
- padding = 12,
- duration = 3,
- spacing = 10,
- accentColor = Color3.fromRGB(255, 174, 174),
- backgroundColor = Color3.fromRGB(30, 30, 40),
- textColor = Color3.fromRGB(255, 255, 255),
- titleColor = Color3.fromRGB(255, 255, 255),
- contentColor = Color3.fromRGB(200, 200, 200),
- fontSize = 12,
- titleSize = 14,
- contentSize = 12,
- lineSpacing = 5 -- 行间距
- }
- -- 通知系统
- local Notifications = {ActiveNotifs = {}}
- local TweenService = game:GetService("TweenService")
- local RunService = game:GetService("RunService")
- local Players = game:GetService("Players")
- local CoreGui = game:GetService("CoreGui")
- local TextService = game:GetService("TextService")
- -- 创建UI父级
- local ScreenGui = Instance.new("ScreenGui")
- ScreenGui.Name = "NotificationSystem"
- ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
- ScreenGui.Parent = RunService:IsStudio() and Players.LocalPlayer:WaitForChild("PlayerGui") or CoreGui
- -- 设置字体
- local function SetFont(label, size)
- if fontAsset then
- label.FontFace = Font.new(fontAsset)
- else
- label.Font = Enum.Font.Arcade
- end
- label.TextSize = size or config.fontSize
- end
- -- 计算文本宽度
- local function GetTextWidth(text, size)
- local success, result = pcall(function()
- local textParams = Instance.new("GetTextBoundsParams")
- textParams.Text = text
- textParams.Font = fontAsset and Font.new(fontAsset) or Enum.Font.Arcade
- textParams.Size = size or config.fontSize
- textParams.Width = math.huge
- local bounds = TextService:GetTextBoundsAsync(textParams)
- return bounds.X
- end)
- return success and result or 150 -- 默认宽度
- end
- -- 更新通知位置
- function Notifications:UpdatePositions()
- local startY = 20
- for i, notif in ipairs(self.ActiveNotifs) do
- local notificationHeight = notif.Container.AbsoluteSize.Y
- local yPos = startY + ((notificationHeight + config.spacing) * (i-1))
- local xPos = notif.Config.side == "right" and
- (workspace.CurrentCamera.ViewportSize.X - notif.Container.AbsoluteSize.X - 20) or
- 20
- TweenService:Create(
- notif.Container,
- TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
- {Position = UDim2.new(0, xPos, 0, yPos)}
- ):Play()
- end
- end
- -- 创建通知
- function Notifications:New(customConfig)
- local currentConfig = table.clone(config)
- for k,v in pairs(customConfig or {}) do
- currentConfig[k] = v
- end
- -- 计算宽度
- local textWidth
- if currentConfig.isTwoLine then
- local titleWidth = GetTextWidth(currentConfig.title, currentConfig.titleSize)
- local contentWidth = GetTextWidth(currentConfig.content, currentConfig.contentSize)
- textWidth = math.max(titleWidth, contentWidth)
- else
- textWidth = GetTextWidth(currentConfig.text)
- end
- local calculatedWidth = math.clamp(textWidth + currentConfig.padding * 2, currentConfig.minWidth, currentConfig.maxWidth)
- local containerHeight = currentConfig.isTwoLine and (currentConfig.titleSize + currentConfig.contentSize + config.lineSpacing * 3) or 30
- -- 创建容器
- local container = Instance.new("Frame")
- container.Name = "Notification"
- container.BackgroundTransparency = 1
- container.Size = UDim2.new(0, calculatedWidth, 0, containerHeight)
- container.Position = UDim2.new(currentConfig.side == "right" and 1 or -1, currentConfig.side == "right" and -20 or 20, 0, 20)
- container.AnchorPoint = currentConfig.side == "right" and Vector2.new(1, 0) or Vector2.new(0, 0)
- container.Parent = ScreenGui
- -- 背景
- local background = Instance.new("Frame")
- background.Name = "Background"
- background.Size = UDim2.new(1, 0, 1, 0)
- background.BackgroundColor3 = currentConfig.backgroundColor
- background.BackgroundTransparency = 1
- background.BorderSizePixel = 0
- background.Parent = container
- -- 装饰条
- local accent = Instance.new("Frame")
- accent.Name = "Accent"
- accent.Size = UDim2.new(0, 3, 1, 0)
- accent.Position = UDim2.new(currentConfig.side == "right" and 1 or 0, currentConfig.side == "right" and -3 or 0, 0, 0)
- accent.AnchorPoint = currentConfig.side == "right" and Vector2.new(1, 0) or Vector2.new(0, 0)
- accent.BackgroundColor3 = currentConfig.color or currentConfig.accentColor
- accent.BackgroundTransparency = 1
- accent.BorderSizePixel = 0
- accent.Parent = background
- -- 文本容器
- local textContainer = Instance.new("Frame")
- textContainer.Name = "TextContainer"
- textContainer.BackgroundTransparency = 1
- textContainer.Size = UDim2.new(1, -currentConfig.padding, 1, 0)
- textContainer.Position = UDim2.new(0, currentConfig.side == "right" and 0 or currentConfig.padding/2, 0, 0)
- textContainer.Parent = background
- -- 通知对象
- local notification = {
- Container = container,
- Config = currentConfig,
- flashThread = nil,
- Destroy = function(self)
- if self.flashThread then
- coroutine.close(self.flashThread)
- end
- local tweenOut = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
- local slideOutPos = UDim2.new(currentConfig.side == "right" and 1 or -1, currentConfig.side == "right" and -20 or 20, 0, container.Position.Y.Offset)
- TweenService:Create(background, tweenOut, {BackgroundTransparency = 1}):Play()
- TweenService:Create(accent, tweenOut, {BackgroundTransparency = 1}):Play()
- TweenService:Create(container, tweenOut, {Position = slideOutPos}):Play()
- if currentConfig.isTwoLine then
- TweenService:Create(self.titleLabel, tweenOut, {TextTransparency = 1}):Play()
- TweenService:Create(self.contentLabel, tweenOut, {TextTransparency = 1}):Play()
- else
- TweenService:Create(self.textLabel, tweenOut, {TextTransparency = 1}):Play()
- end
- for i, notif in ipairs(Notifications.ActiveNotifs) do
- if notif == self then
- table.remove(Notifications.ActiveNotifs, i)
- break
- end
- end
- Notifications:UpdatePositions()
- task.wait(0.5)
- container:Destroy()
- end,
- UpdateText = function(self, newText, newContent)
- if currentConfig.isTwoLine then
- self.titleLabel.Text = newText or self.titleLabel.Text
- self.contentLabel.Text = newContent or self.contentLabel.Text
- local titleWidth = GetTextWidth(self.titleLabel.Text, currentConfig.titleSize)
- local contentWidth = GetTextWidth(self.contentLabel.Text, currentConfig.contentSize)
- local newWidth = math.clamp(math.max(titleWidth, contentWidth) + currentConfig.padding * 2,
- currentConfig.minWidth, currentConfig.maxWidth)
- TweenService:Create(container, TweenInfo.new(0.3), {Size = UDim2.new(0, newWidth, 0, containerHeight)}):Play()
- else
- self.textLabel.Text = newText
- local newWidth = math.clamp(GetTextWidth(newText) + currentConfig.padding * 2,
- currentConfig.minWidth, currentConfig.maxWidth)
- TweenService:Create(container, TweenInfo.new(0.3), {Size = UDim2.new(0, newWidth, 0, containerHeight)}):Play()
- end
- Notifications:UpdatePositions()
- end
- }
- if currentConfig.isTwoLine then
- -- 双行模式
- local titleLabel = Instance.new("TextLabel")
- titleLabel.Name = "Title"
- titleLabel.Text = currentConfig.title
- SetFont(titleLabel, currentConfig.titleSize)
- titleLabel.TextColor3 = currentConfig.titleColor
- titleLabel.TextTransparency = 1
- titleLabel.TextXAlignment = currentConfig.side == "right" and Enum.TextXAlignment.Right or Enum.TextXAlignment.Left
- titleLabel.BackgroundTransparency = 1
- titleLabel.Size = UDim2.new(1, 0, 0, currentConfig.titleSize)
- titleLabel.Position = UDim2.new(0, 0, 0, 0)
- titleLabel.Parent = textContainer
- local contentLabel = Instance.new("TextLabel")
- contentLabel.Name = "Content"
- contentLabel.Text = currentConfig.content
- SetFont(contentLabel, currentConfig.contentSize)
- contentLabel.TextColor3 = currentConfig.contentColor
- contentLabel.TextTransparency = 1
- contentLabel.TextXAlignment = currentConfig.side == "right" and Enum.TextXAlignment.Right or Enum.TextXAlignment.Left
- contentLabel.BackgroundTransparency = 1
- contentLabel.Size = UDim2.new(1, 0, 0, currentConfig.contentSize)
- contentLabel.Position = UDim2.new(0, 0, 0, currentConfig.titleSize + config.lineSpacing)
- contentLabel.Parent = textContainer
- notification.titleLabel = titleLabel
- notification.contentLabel = contentLabel
- else
- -- 单行模式
- local textLabel = Instance.new("TextLabel")
- textLabel.Name = "Text"
- textLabel.Text = currentConfig.text
- SetFont(textLabel)
- textLabel.TextColor3 = currentConfig.textColor
- textLabel.TextTransparency = 1
- textLabel.TextXAlignment = currentConfig.side == "right" and Enum.TextXAlignment.Right or Enum.TextXAlignment.Left
- textLabel.BackgroundTransparency = 1
- textLabel.Size = UDim2.new(1, 0, 1, 0)
- textLabel.Position = UDim2.new(0, 0, 0, 0)
- textLabel.Parent = textContainer
- notification.textLabel = textLabel
- end
- table.insert(self.ActiveNotifs, notification)
- -- 滑入动画
- local tweenIn = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
- local targetX = currentConfig.side == "right" and (workspace.CurrentCamera.ViewportSize.X - calculatedWidth - 20) or 20
- TweenService:Create(background, tweenIn, {BackgroundTransparency = 0}):Play()
- TweenService:Create(accent, tweenIn, {BackgroundTransparency = 0}):Play()
- TweenService:Create(container, tweenIn, {Position = UDim2.new(0, targetX, 0, 20)}):Play()
- if currentConfig.isTwoLine then
- TweenService:Create(titleLabel, tweenIn, {TextTransparency = 0}):Play()
- TweenService:Create(contentLabel, tweenIn, {TextTransparency = 0}):Play()
- else
- TweenService:Create(textLabel, tweenIn, {TextTransparency = 0}):Play()
- end
- self:UpdatePositions()
- -- 闪烁效果
- if currentConfig.flash then
- notification.flashThread = task.spawn(function()
- local time = 0
- while task.wait(0.05) do
- if not container.Parent then break end
- time = time + 0.05
- local pulse = (math.sin(time * 5) + 1) / 2
- accent.BackgroundColor3 = (currentConfig.color or currentConfig.accentColor):Lerp(Color3.new(1, 1, 1), pulse)
- end
- end)
- end
- -- 自动销毁
- task.delay(currentConfig.duration, function()
- if container.Parent then
- notification:Destroy()
- end
- end)
- return notification
- end
- -- 通知接口
- function Notifications:Notify(arg1, arg2, arg3, arg4, arg5)
- local isTwoLine = type(arg2) == "string" and type(arg3) ~= "boolean"
- if isTwoLine then
- return self:New({
- title = arg1,
- content = arg2,
- duration = arg3 or config.duration + 2,
- flash = arg4 or false,
- side = arg5 or "left",
- isTwoLine = true
- })
- else
- return self:New({
- text = arg1,
- duration = arg2 or config.duration,
- flash = arg3 or false,
- side = arg4 or "left",
- isTwoLine = false
- })
- end
- end
- return Notifications
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement