🖋️

【Roblox】TopbarPlusを使ってトグルを作ってみた

に公開

前書き

こんにちは!ambrでクライアントエンジニアを務めているAgatsumaです。
今年からRobloxのゲーム開発に携わっており、本記事ではTopbarPlusを使ったトグル実装のポイントを紹介します。

はじめに

この記事のゴール

  • TopbarPlusでトップバーにアイコンを追加できる
  • クリックでUI(Frame)を開閉できる(同じアイコンを再クリックで閉じる)
  • 複数アイコンの排他トグル(どれかを開いたら他は閉じる)を実装できる

前提

  • クライアント側(LocalScript)で動かします
  • TopbarPlusは ReplicatedStorage に配置して require する想定です
  • (補足)表示の開閉だけなら Icon.new() で作った icon に対して icon:bindToggleItem(guiObject) で短く書けます(selected / deselectedVisible を切り替えるのと同等)

本題: TopbarPlusを使ってみた

1. TopbarPlusとは

  • Robloxのトップバーに Icon(クリック可能な要素) を追加できるUIライブラリ
  • 通知バッジやDropdownにも対応

2. 導入方法

  • 公式ドキュメントを参考に、Roblox Studio上にTopbarPlusを配置してください
  • Packageの自動更新(Get Latest Package等)は、環境によってはエラーになる場合があります

https://1foreverhd.github.io/TopbarPlus/installation/

3. 実際のコード

  • 以降のコードは説明のために分割しています。動かす場合は、必要な部分だけを1つのLocalScriptにまとめてください
  • Icon の配置場所に合わせて require のパスは読み替えてください

3.1 アイコン(ボタン)の生成

--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Icon = require(ReplicatedStorage:WaitForChild("Icon"))

local shopIcon = Icon.new()
shopIcon:setImage("rbxassetid://0") -- TODO: 好きな画像IDに差し替え
shopIcon:align("Right") -- 何も書かない場合は Left(デフォルト)。右上に出したい場合は Right

3.2 アイコン画像のスケール調整

  • デフォルトだと画像が小さく見えることがあるので、必要に応じて調整します
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Icon = require(ReplicatedStorage:WaitForChild("Icon"))

local shopIcon = Icon.new()
shopIcon:setImage("rbxassetid://0")
shopIcon:setImageScale(1.0) -- デフォルトは 0.5。小さく見える場合は調整
shopIcon:align("Right")

3.3 クリック時(selected)の処理

  • selected は「選択状態になった」タイミングで発火します(Roblox標準のイベントではなく、ライブラリ固有)
  • bindEvent のイベント名は camelCase で指定します(例: selected, deselected
  • 利用できるイベント一覧(selected, deselected, toggled など)は 公式API にまとまっています
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Icon = require(ReplicatedStorage:WaitForChild("Icon"))

local shopIcon = Icon.new()
shopIcon:setImage("rbxassetid://0")
shopIcon:setImageScale(1.0)
shopIcon:align("Right")

shopIcon:bindEvent("selected", function(_icon)
	-- TODO: 画面を開くなど
end)

3.4 解除時(deselected)の処理

  • TopbarPlusでは、以下のようなケースで deselected が呼ばれます
    • 同じアイコンをもう一度クリックしたとき
    • 他のアイコンをクリックして、選択が外れたとき(autoDeselect(true) の場合)
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Icon = require(ReplicatedStorage:WaitForChild("Icon"))

local shopIcon = Icon.new()
shopIcon:setImage("rbxassetid://0")
shopIcon:setImageScale(1.0)
shopIcon:align("Right")

shopIcon:bindEvent("selected", function(_icon)
	-- TODO: 画面を開くなど
end)

shopIcon:bindEvent("deselected", function(_icon)
	-- TODO: 画面を閉じるなど
end)

3.5 トグル(開閉)の作り方

TopbarPlusのトグル動作

  • TopbarPlus の selected / deselected で、自前UI(Shop など)の表示を切り替えます
  • selected で開き、deselected で閉じる構成にすると、同じアイコンの再クリックでも自然にトグルできます
  • deselected は再クリックだけでなく、autoDeselect(true)(デフォルトtrue)で他のautoDeselect がtrueのアイコンが押されたときにも呼ばれます
  • 排他トグルは標準の autoDeselect でも実現できますが、×ボタンなどで閉じた場合も状態を揃えるため、アイコン参照を保持して必要に応じて :deselect() します
--!strict
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Icon = require(ReplicatedStorage:WaitForChild("Icon"))

local localPlayer = Players.LocalPlayer
local playerGui = localPlayer:WaitForChild("PlayerGui")

-- 自前UI(例)
local screenGui = playerGui:WaitForChild("ScreenGui")
local shopFrame = screenGui:WaitForChild("ShopFrame") :: Frame
local codeFrame = screenGui:WaitForChild("CodeFrame") :: Frame

-- 初期状態:起動時は閉じておく
shopFrame.Visible = false
codeFrame.Visible = false

local ICON_SCALE = 0.9
local ICON_ASSETS = {
	Shop = "rbxassetid://0", -- TODO: 好きな画像IDに差し替え
	Code = "rbxassetid://0", -- TODO: 好きな画像IDに差し替え
}

-- Topbarアイコン参照(他を閉じるために保持)
type IconType = typeof(Icon.new())
local shopIconRef: IconType? = nil
local codeIconRef: IconType? = nil

-- 他のウィンドウ(=他アイコン)を閉じる
local function closeAllTopbarWindowsExcept(except: string?): ()
	if except ~= "Shop" and shopIconRef ~= nil then
		shopIconRef:deselect() -- deselected が走るので、閉じ処理はそちらに寄せられる
	end
	if except ~= "Code" and codeIconRef ~= nil then
		codeIconRef:deselect()
	end
end

-- Shop アイコン(トグル)
do
	local shopIcon = Icon.new()
	shopIcon:setImage(ICON_ASSETS.Shop)
	shopIcon:setImageScale(ICON_SCALE)
	shopIcon:align("Right")

	shopIcon:bindEvent("selected", function(_icon)
		closeAllTopbarWindowsExcept("Shop")
		shopFrame.Visible = true
	end)

	shopIcon:bindEvent("deselected", function(_icon)
		shopFrame.Visible = false
	end)

	shopIconRef = shopIcon
end

-- Code アイコン(トグル)
do
	local codeIcon = Icon.new()
	codeIcon:setImage(ICON_ASSETS.Code)
	codeIcon:setImageScale(ICON_SCALE)
	codeIcon:align("Right")

	codeIcon:bindEvent("selected", function()
		closeAllTopbarWindowsExcept("Code")
		codeFrame.Visible = true
	end)

	codeIcon:bindEvent("deselected", function()
		codeFrame.Visible = false
	end)

	codeIconRef = codeIcon
end

まとめ

TopbarPlusを実際に使ってみて、個人的に一番大きな収穫だったのは、「トップバーの導線」をきれいに整理できて、UIの切り替えが想像以上にシンプルになったことです。

特に selected / deselected を軸にトグルを組むことで、「同じアイコンをもう一度押したら閉じる」「別のアイコンを押したら前の画面が閉じる」といった自然な体験を、破綻しにくい形で作れました。

今回の実装を踏まえて、今後はDropdownの活用や、通知バッジ・画面遷移時の状態同期なども含めて、より使いやすいUIに育てていきたいです。
最後まで読んでいただき、ありがとうございました!

ambr Tech Blog

Discussion