Skip to content

Instantly share code, notes, and snippets.

@unrooot
Created November 3, 2024 05:10
Show Gist options
  • Save unrooot/6ada7e5eb340f5fca951b3d0ab00cbc3 to your computer and use it in GitHub Desktop.
Save unrooot/6ada7e5eb340f5fca951b3d0ab00cbc3 to your computer and use it in GitHub Desktop.
Seamlessly play multiple VideoFrames back to back
--[[
-- This script seamlessly* plays videos in a SurfaceGui in order. It's a bit
-- hacky for a few reasons (mainly Roblox limitations & random delays with
-- VideoFrames) but the biggest one being that Roblox only allows you to upload
-- 3, 30 second videos per month (...lol).
--
-- * - technically, because of a hack (see line 99), we end each clip early by 0.05 seconds
--
-- INSTRUCTIONS:
-- 1. Create a SurfaceGui somewhere
-- 2. Tag the SurfaceGui's parent with "VideoDisplay" (or change TAG_NAME to something else)
-- 3. Add VideoFrames to the SurfaceGui, with a number at the end of the name in order of how they should be played
--
-- e.g. with the following hierarchy:
-- Part
-- SurfaceGui
-- VideoFrame1
-- VideoFrame2
-- VideoFrame3
--
-- The videos will play in the order of VideoFrame1 -> VideoFrame2 -> VideoFrame3 -> ... -> VideoFrame1 -> ...
--
-- You can put as many VideoFrames as you want, but keep in mind more videos =
-- more memory usage. Also, Roblox currently has a limit of 2 VideoFrames
-- playing at the same time.
--
-- Hopefully something like this won't be needed in the future, but for now, I hope this helps!
--]]
local CollectionService = game:GetService("CollectionService")
local ContentProvider = game:GetService("ContentProvider")
-- the name of the tag you wanna use for the video player
local TAG_NAME = "VideoDisplay"
local setupDisplays = {}
local function playVideos(videoDisplay)
task.spawn(function()
-- prevent the same display from running twice
if setupDisplays[videoDisplay] then
return
end
setupDisplays[videoDisplay] = true
local currentVideoIndex = 0
local surfaceGui = videoDisplay.VideoSurfaceGui
local videoFrames = {}
-- try to preload the videos (spoiler: there's still a delay 🗿 but in theory this should help)
ContentProvider:PreloadAsync(surfaceGui:GetChildren())
-- this assumes there are only VideoFrames in the SurfaceGui, with a number at
-- the end of the name in order of how they should be played
for _, video in surfaceGui:GetChildren() do
if not video:IsA("VideoFrame") then
continue
end
local index = tonumber(string.match(video.Name, "%d+"))
if not index then
continue
end
-- hack: force the clip to load to prevent the other delay when the
-- video first plays on a VideoFrame
video.Visible = true
video.ZIndex = 100
video:Play()
repeat task.wait() until video.IsLoaded
video:Pause()
video.TimePosition = 0
-- reset the video to its original state
video.Looped = false
video.Visible = false
video.ZIndex = index
table.insert(videoFrames, index, video)
end
local function playNextVideo()
currentVideoIndex += 1
if currentVideoIndex > #videoFrames then
currentVideoIndex = 1
end
local currentVideo = videoFrames[currentVideoIndex]
local connection
currentVideo:Play()
currentVideo.Visible = true
-- hack: play the next clip early, since .Ended fires late and the
-- TimeLength seems to be longer than the actual video, causing a
-- delay between clips. this fixes that
task.delay(currentVideo.TimeLength - 0.05, function()
-- hack: because of the aforementioned delay, if `currentVideo`
-- is the last clip, we have to hide it early because the
-- ZIndex is higher than the first clip. if we don't, it will
-- cause another delay...
if currentVideoIndex + 1 > #videoFrames then
currentVideo.Visible = false
end
playNextVideo()
end)
-- hide & reset the video when it ends
task.delay(currentVideo.TimeLength, function()
currentVideo.Visible = false
currentVideo:Pause()
currentVideo.TimePosition = 0
end)
end
playNextVideo()
end)
end
-- set up video displays
for _, player in CollectionService:GetTagged(TAG_NAME) do
playVideos(player)
end
CollectionService:GetInstanceAddedSignal(TAG_NAME):Connect(playVideos)
CollectionService:GetInstanceRemovedSignal(TAG_NAME):Connect(function(videoDisplay)
setupDisplays[videoDisplay] = nil
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment