Skip to content

Instantly share code, notes, and snippets.

@jakedowns
Last active April 4, 2020 21:51
Show Gist options
  • Save jakedowns/5e97e719545d512ca89a06b961148b6d to your computer and use it in GitHub Desktop.
Save jakedowns/5e97e719545d512ca89a06b961148b6d to your computer and use it in GitHub Desktop.
Roblox Moon Suite 2 : Running Saved Rig Animations at Runtime / Game Play Animation Playback (Work in Progress)
-- This script is a work in Progress!!! It only supports Size property animation so far
-- Place this script in StarterPlayer > StarterPlayerScripts
-- Note: I Copied MoonAnimatorSaves from ServerStorage to Workspace. Probably some way to get it to work with the default save location...
-- Change the File name here to the animation you want to play
aniSavePath = workspace.MoonAnimatorSaves["pig-eyes.xsixx"]
-- @xSIXx Would be helpful if Information had the target FPS stored inside it
targetFPS = 60
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")
-- Used for converting Raw Tables into Vector3's and So-on for the different animatable property types
PropValueFactories = {}
function PropValueFactories.Size(raw)
--print("Size",raw)
return Vector3.new(raw.x,raw.y,raw.z)
end
-- A deep selector we can wrap in a pcall
function deepSelectItemFromArrayOfStrings(T, root)
local output = root or game
for i,v in ipairs(T) do
--print(output.Name,v,output:FindFirstChild(v))
if(v == "Value" and output[v] ~= nil) then
output = output[v]
break
end
if(v ~= "game" and output:FindFirstChild(v) == nil) then
output = nil
break
end
if v ~= "game" and output:FindFirstChild(v) ~= nil then
output = output[v]
end
end
--print("output",output)
return output;
end
-- helper
local function tryGetSavedDataForItemPropFrame(aniSavePath,i,prop,f)
return deepSelectItemFromArrayOfStrings({tostring(i),prop,tostring(f),"Values",tostring(0),"Value"},aniSavePath)
end
-- A helper that expands out a known value for Each Frame of animation
-- Will look into a way to optimize this step later
local function parseAnimation(aniSavePath)
local aniSave = HttpService:JSONDecode(aniSavePath.Value);
local models = aniSave["Items"]
local aniMetaTable = {}
aniMetaTable["Items"] = {}
aniMetaTable["Information"] = aniSave["Information"]
for i, model in ipairs(models) do
local part = deepSelectItemFromArrayOfStrings(model["Path"]["InstanceNames"])
table.insert(aniMetaTable["Items"],{Part=part, Prop=model["Prop"], PropFrames = {}})
-- Expand out values for Each Frame of the Animation's Total Length
for i2, prop in ipairs(model["Prop"]) do
aniMetaTable["Items"][i]["PropFrames"][prop] = {}
local frameValue = nil
for f=0, aniMetaTable["Information"]["Length"] do
local status, output = pcall(tryGetSavedDataForItemPropFrame,aniSavePath,i,prop,f)
--print("pcall status",status, "output", output)
if status == true and output ~= nil then
frameValue = output
end
table.insert(aniMetaTable["Items"][i]["PropFrames"][prop], frameValue)
--print(part.Name,prop,f,frameValue)
end
end
end
return aniMetaTable
end
-- One-time initialization for expensive operations
aniMetaTable = parseAnimation(aniSavePath)
--targetFrameTime = 1/targetFPS
currentFrame = -1
aniInfo = aniMetaTable["Information"]
--for i,v in ipairs(aniMetaTable["Items"][1]["PropFrames"]["Size"]) do
-- print("expanded",i,v)
--end
local function playAnimation(aniMetaTable, deltaTime)
if(not aniInfo["Looped"] and currentFrame > aniInfo["Length"]) then
return
end
-- TODO: could do some deltaTime factoring to get "real-time" frame values instead of "frame-time" values
-- that way the animation could skip frames on slower framerate envs
local frameOfLength = currentFrame % (aniInfo["Length"] + 1)
--print("frame of length", currentFrame, aniInfo["Length"], frameOfLength)
for i, part in ipairs(aniMetaTable["Items"]) do
local MetaItemsPropFrames = aniMetaTable["Items"][i]["PropFrames"]
for i2, prop in ipairs(part["Prop"]) do
local propFrameData = nil
-- local status, output = pcall(deepSelectItemFromArrayOfStrings, {prop, frameOfLength},MetaItemsPropFrames)
-- if(status ~= false and output ~= nil) then
-- propFrameData = output
-- end
propFrameData = MetaItemsPropFrames[prop][frameOfLength]
--print("animating", prop, frameOfLength, propFrameData)
if(propFrameData ~= nil)then
part["Part"][prop] = PropValueFactories[prop](propFrameData)
end
--print(part["Part"].Name .. ":" .. prop .. ":" .. tostring(part["Part"][prop]))
end
end
--print(targetFrameTime, deltaTime, deltaTime * targetFPS)
end
local function onRenderStep(deltaTime)
-- keep track of the curent frame
currentFrame = currentFrame+1
playAnimation(aniMetaTable, deltaTime)
end
RunService.RenderStepped:Connect(onRenderStep)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment