Zenn
⚒️

【Roblox】UGC機能の実装(2)~ステージの生成~

2025/03/17に公開

はじめに

今回は前回の記事で紹介したUGC機能を使って作成したステージデータから実際にステージを生成する方法について紹介します。
今回使用するデータの構造は前回の記事で作成したものになるので、読んでいない方はそちらを読んでからご覧いただきますようお願いします。

前回の記事
https://zenn.dev/landho_roblox/articles/83f317c0283f1d

Robloxバージョン 0.658.0.6580461

ステージの生成

前回保存したデータはDataStoreで使用できるようにCFrameを配列に変換して保存を行っていました。
まずは配列をもう一度CFrameに変換する処理について紹介します。

tableからCFrameに変換する

前回CFrameをtable型に変換しましたが、そのときの配列の中身は

cframe = {0, 10, 20, 0.49995946884155273, 0, 0.8660488128662109, 0, 1, 0, -0.8660488128662109, 0, 0.49995946884155273}

このようになっています。
これをもう一度CFrameに変換するにはtable型に用意されているunpackメソッドを使用します。
このメソッドはtableの要素をタプル型として返します。

local part = Instance.new("Part")
part.CFrame = CFrame.new(table.unpack(cframe))

こうすることで複雑なコードを組まずともtable型からCFrameに変換することができます。

DataStoreからデータを取得し、ステージを作成する

実際にステージデータをDataStoreから取得し、生成してみましょう。
命令情報に関してはMoveを例に紹介します。

local DataStoreService = game:GetService("DataStoreService")
local StageDataStore = DataStoreService:GetDataStore("StageDataStore")

--生成したステージオブジェクトの親になるModelインスタンス
local StageBase = workspace:WaitForChild("BaseModel")

--ステージを生成する際の基準位置となるBasePartインスタンス
local BasePosPart = workspace:WaitForChild("BasePos")

local ReplicatedStorage = game:GetService("ReplicatedStorage")
--プレハブフォルダ
local prefabFolder = ReplicatedStorage:WaitForChild("Prefab")
--配置するオブジェクトを格納しているフォルダ
local objectFolder = prefabFolder:WaitForChild("Object")

local TweenService = game:GetService("TweenService")

local StageLoadManager = {}

function StageLoadManager:CreateStage(stageId)
    -- ステージデータの取得
    local data = StageDataStore:GetAsync(stageId)
    
    local directiveTweens = {}
    
    for i,v in ipairs(data) do
        local object = prefabFolder:WaitForChild("Object_"..v.objectId):Clone()
        object.CFrame = CFrame.new(table.unpack(v.cframe))
        object.Position = object.Position + BasePosPart.Position
    
        if v.directive.Move.IsActive then
            local currentPos = object.Position
            local targetPos = Vector3.new(v.directive.Move.TargetPos[1],v.directive.Move.TargetPos[2],v.directive.Move.TargetPos[3])
            local mag = (targetPos + BasePosPart.Position - currentPos).Magnitude
            local tweenInfo = mag / v.directive.Move.Speed
            local moveForward = TweenService:Create(object, tweenInfo, {Position = targetPos + BasePosPart.Position})
            local moveBackward = TweenService:Create(object, tweenInfo, {Position = currentPos})
            moveForward.Completed:Connect(function()
                moveBackward:Play()
            end)
            moveBackward.Complited:Connect(function()
                moveForward:Play()
            end)

            --作成したTweenのうち最初に再生されるものをテーブルに格納する
            table.insert(directiveTweens, moveForward)
        end
    end

    return directiveTweens
end

return StageLoadManager

これでステージを生成することができました。
returnしているdirectiveTweensにはオブジェクトに対する命令のTweenが入っているので、ステージ開始タイミングでfor文でまとめてPlayすることでオブジェクトを動かすことができます。

UGC機能でステージを生成する際の注意点

DataStoreを使ってステージデータを扱う際にはDataStoreの制限に気を付ける必要があります。
UGC機能では多くのデータをやり取りする必要があるので、設計をしっかりと行わないと制限に引っ掛かりDataStoreの使用が一時的にできなくなる可能性があります。

リクエスト回数制限

リクエストタイプごとに1分間にリクエストできる回数に制限が設定されています。

リクエストタイプ 機能 1分あたりのリクエスト数
Get GetAsync() 60 + サーバー上のプレイヤー数 * 10
Set SetAsync()
IncrementAsync()
UpdateAsync()
RemoveAsync()
60 + サーバー上のプレイヤー数 * 10
Get Sorted GetSortedAsync() 5 + サーバー上のプレイヤー数 * 2
Get Version GetVersionAsync()
GetVersionAtTimeAsync()
5 + サーバー上のプレイヤー数 * 2
List ListDataStoreAsync()
ListKeysAsync()
ListVersionAsync()
5 + サーバー上のプレイヤー数 * 2
Remove RemoveVersionAsync() 5 + サーバー上のプレイヤー数 * 2

データ量制限

一つにエントリに対して4MBのデータしか保存することができません。

スループット制限

サーバー全体でリクエストでやり取りできるデータ量に制限があります。
またこの時のデータ量はキロバイト単位にすべて切り上げられます。

リクエストタイプ 制限
Read 1分あたり25MB
Write 1分あたり4MB

まとめ

  • tableからCFrameに変換するときはunpackメソッドを使用する
  • DataStoreの制限に注意する
    • リクエスト回数制限
    • エントリのデータ量制限
    • スループット制限

今回はUGC機能で作成したステージデータをDataStoreから呼び出し、ステージを生成する方法について紹介しました。
UGC機能を作る上ではDataStoreの制限に気を使って実装を行わないと制限に引っ掛かったときにDataStoreの使用が一時的にできなくなってしまうことがあるので、どのタイミングでDataStoreにリクエストが送信されるのか、重複してデータの取得を行っていないか注意する必要があります。
UGC機能はゲームでできることの幅を大きく広げてくれますが、DataStoreの制限やさまざまな状況を考慮した設計が必要になってきます。サービスの制限に関しての知見を深めた上で、余裕のある設計ができるように心がけましょう。
最後までお読みいただき、ありがとうございました!

参考

https://create.roblox.com/docs/cloud-services/data-stores
https://create.roblox.com/docs/cloud-services/data-stores/error-codes-and-limits
https://create.roblox.com/docs/reference/engine/libraries/table

ランド・ホー Roblox開発チーム

Discussion

ログインするとコメントできます