はじめに

本投稿は[Roblox ムービー演出の作り方(1) MoonAnimator2][Roblox ムービー演出の作り方(2) データ構造とエクスポート]にて作成されたアニメーションデータをもとに、ローカルのScriptにて再生する方法を3回に分けて紹介していきます。

また、MoonAnimator2でエクスポートされるデータのうち、MoonAnimator2フォルダ配下にあるデータはアニメーションの各ターゲット(キャラクターやカメラなど)の位置情報と向いている方向になるため、本投稿の紹介とは別にキャラクターのアニメーションは編集して再生する必要があります。

下準備

[Roblox ムービー演出の作り方(2) データ構造とエクスポート]にてエクスポートされたMoonAnimator2のデータはServerStorage配下に格納されているためローカルのScriptからアクセスすることができません。

そのため、ServerStorage配下にあるMoonAnimator2Savesフォルダを、ReplicatedStorage/MoonAnimator2Savesとなる様にReplicatedStorage配下にコピーします。

また、実際にアニメーションを読み込んだり再生するScriptとして以下のファイルを用意します。
StartPlayer/StarterCharacterScripts/LocalScript

手順

MoonAnimtor2のエクスポートされたデータをScriptにて再生する方法の手順として、以下の様に3つの内容に分けています。

  1. エクスポートされたデータから必要な情報を抜き出す
  2. 各ターゲットの位置データをフレーム単位に分解
  3. 再生

では、実際に手順に沿って説明していきます。

エクスポートされたデータから必要な情報を抜き出す

まずはスクリプト内で使用する変数等と、エクスポートされたデータから必要な情報を抜き出して準備するためのSetup関数をLocalScript内に用意します。
Scriptのサンプルについては本記事の下部に記載してありますので、解説と共に参照してください。

MoonAnimtor2フォルダ配下のCFrameオブジェクト(StringValue)のValue要素には、アニメーション全体の情報がJSONデータとして入っています。
このままでは扱いづらいので、JSONデータをHttpService:JSONDecode関数を使用して配列に変換します。①

このJSONデータの構造については[Roblox ムービー演出の作り方(2) データ構造とエクスポート]に記載されていますが、Items配下にアニメーションの各ターゲットの情報が入っているため、その対象となるオブジェクトの名称を取得します。②
また、MoonAnimtor2/CFrameオブジェクトの配下には、Items配下の要素数分のフォルダが1からの連番で存在し、その中に各ターゲットのキーフレーム毎のCFrameのデータ(位置と向き)が入っています。
今回の記事で用意しているデータの場合、Items配下には順番にRig、Rig2、CurrentCameraの3つのターゲットの情報があり、MoonAnimtor2/CFrameの配下にはそれぞれ1、2、3フォルダがありますが、ターゲットの順番とフォルダの順番(添字)がそれぞれ対応しています。

MoonAnimator2が用意してくれるデータは各ターゲットのキーフレーム毎のCFrameのデータなので、このまま特定のキーフレーム時にターゲットに対してCFrameのデータを渡してしまうと見た目上はワープしている様に見えてしまいます。
そのため、キーフレーム毎に用意されたCFrameのデータを元に1フレーム毎のCFrameのデータが必要になるため、別の関数を用意して1フレーム毎のCFrameのデータを準備します。③

StartPlayer/StarterCharacterScripts/LocalScript

-- 各種サービスを取得
local HttpService = game:GetService("HttpService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- アニメーション時以外のカメラのTypeを保持
local currentCameraType = nil
-- アニメーション前のカメラのCFrame
local currentCameraCFrame = nil
-- 総フレーム数を保持
local totalFrameCount = 0
-- アニメーションに使用するデータを入れる配列
local animationDataArray = {}
-- アニメーション用のconnectを保持
local connection = nil
-- アニメーションを実行中か
local isPlayingAnimation = false

-- マウス操作用の処理
local player = Players.LocalPlayer
local mouse = player:GetMouse()

-- セットアップ関数
function Setup()
    -- ゲームがロードされるまで待機
    repeat wait() until game:IsLoaded()

    -- アニメーション全体のデータが格納されたオブジェクトを取得
    local animationData = ReplicatedStorage:WaitForChild("MoonAnimator2Saves"):FindFirstChild("CFrame")

    -- ①JSONの文字列を配列に変換
    local animationInfoArray = HttpService:JSONDecode(animationData.Value)

    -- アニメーションの総フレーム数を取得
    totalFrameCount = animationInfoArray["Information"]["Length"]

    -- アニメーションのターゲット毎に処理
    for i, data in ipairs(animationInfoArray["Items"]) do
        -- ②ターゲットの名称を取得
        local targetName = data["Path"]["InstanceNames"][#data["Path"]["InstanceNames"]]

        local targetObject = nil
        -- 「CurrentCamera」かどうかで取得方法を分岐
        if targetName == "CurrentCamera" then
            targetObject = workspace.Camera
        else
            targetObject = workspace:FindFirstChild(targetName)
        end

        -- HumanoidRootPartがあるか
        local isHaveHRP = false
        if targetObject:FindFirstChild("HumanoidRootPart") then
            isHaveHRP = true
        end

        -- ターゲット毎に配列に挿入
        animationDataArray[targetName] = {
            target = targetObject,
            -- ③1フレーム毎の位置情報に分解
            frameArray = CreateAnimationFrames(animationData:FindFirstChild(i), totalFrameCount),
            isHaveHRP = isHaveHRP
        }
    end
end
Setup()

次の手順

次回の記事では、キーフレームのCFrameのデータを元に1フレーム毎のCFrameのデータへ分解する処理を解説します。