Open44

Roblox開発 Tipsメモ

まつさこまつさこ

Partの CanQuery がtrueだと、RayCastが当たる。
CanCollide がtrueの時はCanQueryは暗黙的にtrue(StudioのUIにそもそも表示されない)。
CanTouch はRayCastが当たるかどうかに無関係。

まつさこまつさこ

Soundを立体音響にするには、SoundがPart直下の子オブジェクトになっていないといけない。
※Modelの子オブジェクトだと立体音響にならない

まつさこまつさこ

Rolox Studioでソロプレイ中、 Shift + P でスクリーンショットモードになる。
UIが非表示になり、WASDキーで自由に動ける。

まつさこまつさこ

プレースの太陽と月を表示するかどうかは、Skyオブジェクトの CelestialBodiesShown で変更できる。

まつさこまつさこ

HttpService:JSONDecode をすると配列で返ってくる。つまり data.output みたいにKey名を指定しても取れない。
しかし、さらにもう一度 HttpService:JSONDecode を重ねると、Dictionary型になるので data.output で値をとれる!

まつさこまつさこ

SoundはFolder内なら複数入れて再生できるが、Partには複数入れると再生できなくなる。
以下のようにするのはOK

まつさこまつさこ

サーバースクリプトでのプレイヤー参加時処理覚書

local Players = game:GetService("Players")

local function initializePlayer(player)
    -- 初期化処理
end

for _, player in Players:GetPlayers() do
	initializePlayer(player)
end
Players.PlayerAdded:Connect(initializePlayer)
まつさこまつさこ

ドッスンTween覚書

local TweenService = game:GetService("TweenService")
local dossun = script.Parent:WaitForChild("Dossun")
local height = script.Parent:GetAttribute("Height")
local upTime = script.Parent:GetAttribute("UpTime")
local downTime = script.Parent:GetAttribute("DownTime")
local awaitTime = script.Parent:GetAttribute("AwaitTime")

local upPosition = dossun.Position + Vector3.new(0, height, 0) -- 上昇後の位置
local downPosition = dossun.Position -- 元の位置(下降後の位置)

local upTweenInfo = TweenInfo.new(upTime, Enum.EasingStyle.Linear, Enum.EasingDirection.Out) -- 上昇のTween情報
local downTweenInfo = TweenInfo.new(downTime, Enum.EasingStyle.Linear, Enum.EasingDirection.Out) -- 下降のTween情報

local upTween = TweenService:Create(dossun, upTweenInfo, {Position = upPosition})
local downTween = TweenService:Create(dossun, downTweenInfo, {Position = downPosition})

while true do
	upTween:Play() -- 上昇開始
	upTween.Completed:Wait() -- 上昇が完了するまで待つ
	downTween:Play() -- 下降開始
	downTween.Completed:Wait() -- 下降が完了するまで待つ
	wait(awaitTime) -- 3秒間停止
end
まつさこまつさこ

ModuleScriptは StarterPlayerScripts などのローカル環境に作成して配置することもできる。
そうすることで、LocalScript間でModuleScript内のグローバル変数を共有することが可能に。

まつさこまつさこ

RunService.Stepped を使えば、毎フレームの物理演算前に処理をすることが出来、引数のstepで前フレームからの秒数を取得できる。

local RunService = game:GetService("RunService")

local RATE_PER_SECOND = 2

RunService.Stepped:Connect(function(time, step)
	local increment = RATE_PER_SECOND * step
end)
まつさこまつさこ

サーバースクリプトでToolsをBackpackに入れる際、CharacterAddedを待たないと正常に動作しない。

--- local functions ---
local function setSpeedCoil(player)
	player.CharacterAdded:Wait()
	local coilInBackpack = player.Backpack:FindFirstChild("Speed Coil")
	if coilInBackpack then
		return
	end
	
	local speedCoil = ServerStorage:WaitForChild("Speed Coil")
	if speedCoil then
		local coilClone = speedCoil:Clone()
		coilClone.Parent = player.Backpack
	end
end

--- player added ---
for _, player in Players:GetPlayers() do
	setSpeedCoil(player)
end

Players.PlayerAdded:Connect(function(player)
	setSpeedCoil(player)
end)
まつさこまつさこ

SetFavoriteや
FriendInviteのコード

local success, errorMessage = pcall(function()
			local ExperienceInviteOptions = Instance.new("ExperienceInviteOptions")
			ExperienceInviteOptions.PromptMessage = "Enjoy the quiz with your FRIENDS!"
			SocialService:PromptGameInvite(player, ExperienceInviteOptions)
		end)

ローカルスクリプトでしか動作しない

まつさこまつさこ
{
    ["key1"] = value1,
    ["key2"] = value2
}

という形式のテーブルからKeyを指定して行を削除したい場合は
table["key1"] = nil
という風にnilを入れることで、削除される。

まつさこまつさこ

player.CharacterAdded:Wait() を使う際は、すでにCharacterがあったら永遠に待ち続けてしまうため

if not player.Character then
    player.CharacterAdded:Wait()
end

と書くように注意

まつさこまつさこ

AvatarEditorService:GetFavorite() を利用するには、 AvatarEditorService:PromptAllowInventoryReadAccess() でユーザーにアクセス許可を求め、OKしてもらう必要がある。

まつさこまつさこ

BillboardGuiの大きさが距離によって変わらないようにするには
SizeのScaleを変更してOffsetは0にする

まつさこまつさこ

AudioDeviceOutputをPlayer参加時にPlayer配下に追加する場合、少し待ってから追加しないと正常に動作しない(2024年5月22日時点)

まつさこまつさこ

Humanoidアニメーションは、ローカルで動作させてもサーバーで動きが同期される

まつさこまつさこ

Humanoidをprintすると以下のエラーが出るのでしないように(2024年6月4日時点)

まつさこまつさこ

自分の環境のみで他のプレイヤーを透明にしたい場合、ローカルスクリプトで他のプレイヤーを透明化処理する

local function SetDisplayOtherPlayer(player, active)
	local transparency = 0
	if active then
		transparency = 0
	else
		transparency = 1
	end
	
	if player ~= LocalPlayer then
		local character = player.Character
		if character then
			for _, part in ipairs(character:GetDescendants()) do
				if part:IsA("BasePart") then
					part.Transparency = transparency
					if part:FindFirstChildOfClass("Decal") then
						part:FindFirstChildOfClass("Decal").Transparency = transparency
					end
				elseif part:IsA("Decal") or part:IsA("Texture") then
					part.Transparency = transparency
				end
			end
		end
	end
end
まつさこまつさこ

ローカルスクリプトで、KnitのServiceに定義したClient関数を呼ぶときは、promiseとして返ってくるので必ずawait()する

local result, value = AnythingService:GetSomething():await()
if result then
	print(value)
end
まつさこまつさこ

OrderedDataStore覚書

local DataStoreService = game:GetService("DataStoreService")
local SomethingStore = DataStoreService:GetOrderedDataStore("SomethingStore")

--- local functions ---
local function SetStore(userId, value)
	local success, errorMessage = pcall(function()
		SomethingStore:SetAsync(userId, value)
	end)
	if not success then
		print(errorMessage)
	end
end

local function GetStore(userId)
	local success, val = pcall(function()
		return SomethingStore:GetAsync(userId)
	end)
	if success then
		if val == nil then
			SetStore(userId, 0)
			val = 0
		end
		return val
	end
end

local function ResetStore(userId)
	local success, removedVal = pcall(function()
		return SomethingStore:RemoveAsync(userId)
	end)
	if success then
		warn("UserId:" .. userId ..  "SomethingStore has been removed.")
	end
end

local function GetTopRanking(topNum)
	local isAscending = false
	local pageSize = topNum
	local pages = SomethingStore:GetSortedAsync(isAscending, pageSize)
	local topScores = pages:GetCurrentPage()
	return topScores
end
まつさこまつさこ

1000以上の数値を*K表記にする

function FormatNumber(value)
	if value >= 1000 then
		local kValue = value / 1000
		return string.format("%gK", kValue)
	else
		return tostring(value)
	end
end
まつさこまつさこ

SurfaceGuiをUIとして機能させるには、StarterGui内に入れて、 Adornee プロパティにくっつけたいPartを指定する。

まつさこまつさこ

NPCをアニメーションさせるときは、HumanoidRootPartのAnchoredをtrueにした方が安定する。

まつさこまつさこ

Backpack内のToolの強制Equip/Unequip

--- flags ---
local equipingTool

--- local functions ---
local function SetEnableTools(active)
	local humanoid = LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
	if humanoid then
		if active then
			if equipingTool then
				humanoid:EquipTool(equipingTool)
			end
			equipingTool = nil
		else
			equipingTool = LocalPlayer.Character:FindFirstChildWhichIsA("Tool")
			if equipingTool then
				humanoid:UnequipTools()
			end
		end
	end
end
まつさこまつさこ

アセットのサムネイルを画像として使う
rbxthumb://type=Asset&id=ASSETID&w=150&h=150

まつさこまつさこ

upperTorsoのローカル座標系で、offset位置、rotation回転させる

local offset = CFrame.new(0, -0.1, 0.6)
local rotation = CFrame.fromEulerAnglesYXZ(math.rad(30), math.rad(90), 0)
object.CFrame = upperTorso.CFrame * offset * rotation
まつさこまつさこ

HTTP POSTリクエスト覚書

local success, result = pcall(function()
    print("sending...")
    local response = HttpService:RequestAsync({
        Url = "ここにエンドポイントをいれる",
        Method = "POST",
        Headers = {
            ["Content-Type"] = "application/json",
        },
        Body = jsonString,
    })
    return response
end)

if success then
    if result.Success then
        print("Status code:", result.StatusCode, result.StatusMessage)
        print(result.Body)
    else
        print("The request failed:", result.StatusCode, result.StatusMessage)
    end
else
    warn(result)
end
まつさこまつさこ

以下をコードの最初に記述することで、Studio外の本番環境では動作しないようにできる

if not game["Run Service"]:IsStudio() then return end
まつさこまつさこ

C#でいうところの

var hoge = boolean ? "true" : "false"

はLuaでは

local hoge = boolean and "true" or "false"

と書ける

まつさこまつさこ

HumanoidRootPartにPartをWeldする場合、Masslessにしないとその重さに振り回される

まつさこまつさこ

Player.LoadCharacter を実行すると以下の順でイベントが実行される

  1. Player.Characterセット
  2. Player.CharacterAddedが発火
  3. Player.Changedが "Character "の値で発火
  4. キャラクターの外観が初期化される
  5. Player.CharacterAppearanceLoadedが発火
  6. Character.ParentがDataModelに設定
  7. キャラクターのリグが構築され、キャラクターがスケールする
  8. キャラクターがスポーン位置に移動する
  9. LoadCharacterがreturnされる

https://create.roblox.com/docs/reference/engine/classes/Player#LoadCharacter

まつさこまつさこ

Roblox開発のテーブル操作

Copy code
table1 = {1, 2, 3}
table2 = table1
table.remove(table2, 1)

上記のようにすると、table2を操作するとtable1にも影響が出てしまう。

理由
table2 = table1 とすると、table2はtable1の参照を持つことになります。つまり、どちらかのテーブルを変更すると、もう片方のテーブルにも同じ変更が反映される。

解決策
table1をコピーしてからtable2に代入することで、独立したテーブルとして操作できる。

Copy code
-- 元のテーブル
table1 = {1, 2, 3}

-- コピー用の新しいテーブルを作成
table2 = {}

-- table1の要素をtable2にコピー
for i, v in ipairs(table1) do
    table2[i] = v
end

-- table2から最初の要素を削除
table.remove(table2, 1)

-- 結果確認
print(table1[1])  -- 出力: 1
print(table2[1])  -- 出力: 2

結果
table2から最初の要素を削除しても、table1には影響しません。
table1は元のままの内容を保持します。
table2は変更された内容を持ちます。

まつさこまつさこ

所属するグループや自分のアカウントに保存したAnimationを、別のグループに複製したいとき

  1. RigBuilder でRigをつくる
  2. Animation Editor ウィンドウを開いてRigを選択し、Import > From Roblox でグループからAnimationを選択
  3. キーフレームが読み込めたら、Publish to Roblox で複製したいグループに保存
まつさこまつさこ

Motor6Dの制約(謎)

このようにしてWeldConstraintとMotor6Dを組み合わせると、動作が破綻する

全部Motor6Dにしてもダメでした
複数Motorの回転はダメっぽい?


原因はMassだった
Masslessにすることで解消