Hello, I’m currently creating a camera video screen on a SurfaceGui using a ViewportFrame and a WorldModel. My goal is to be able to display players on the UI in real-time with their animations playing as well. I’ve been successful in putting player’s characters on the screen and keeping their positions updated constantly by changing their CFrame. The only issue is the animations, I’m not sure how to go about playing the animations, every time I try to load an animation on the character in the ViewportFrame the animation keeps getting reset every time their CFrame changes, which is every 1/25 of a second.
So, I’d like to be able to play animations on the characters, is there any way to achieve this? Thanks.
I’ll provide my code in case that helps anyone understand what I’ve got going on.
Server:
local ScreenRefreshRate = 1/25 -- Seconds
local Players = game:GetService("Players")
local folderScreenDetection = workspace.ScreenDetection
local remoteScreenUpdate = game:GetService("ReplicatedStorage").ScreenUpdate
local remoteScreenUnrender = game:GetService("ReplicatedStorage").ScreenUnrender
local screenData = {}
-- Find and remove player from screenData dictionary
local function removePlayerFromData(plr)
screenData[plr.Name] = nil
print("Removed:")
print(screenData)
end
-- Add player to screenData dictionary
local function addPlayerToData(plr)
screenData[plr.Name] = plr.Character.HumanoidRootPart.CFrame
print("Added:")
print(screenData)
end
-- Check if player is in screenData dictionary
local function isPlayerInData(plr)
for i, v in pairs(screenData) do
if i == plr.Name then return true end
end
return false
end
-- Detect when player enters the stage, if they're not already in the screenData dictionary, add them
local function playerEntered(plr)
if not isPlayerInData(plr) then
addPlayerToData(plr)
end
end
-- Detect when player leaves the stage, if they're in the screenData dictionary, remove them and fire the Unrender Remote
local function playerExited(plr)
if isPlayerInData(plr) then
removePlayerFromData(plr)
remoteScreenUnrender:FireAllClients(plr.Name)
end
end
-- Connecting the playerEntered and playerExited event to a Touched event
for i, v in ipairs(folderScreenDetection:GetChildren()) do
if v.Name == "Enter" then
for i, v in ipairs(v:GetChildren()) do
v.Touched:Connect(function(p)
local c = p:FindFirstAncestorOfClass("Model")
local plr = Players:GetPlayerFromCharacter(c)
if c and plr then
playerEntered(plr)
end
end)
end
else
for i, v in ipairs(v:GetChildren()) do
v.Touched:Connect(function(p)
local c = p:FindFirstAncestorOfClass("Model")
local plr = Players:GetPlayerFromCharacter(c)
if c and plr then
playerExited(plr)
end
end)
end
end
end
-- Constantly update all player's positions in the screenData dictionary and send it to the client
local screenUpdate = coroutine.wrap(function()
while true do
wait(ScreenRefreshRate)
-- get players position and keep it updated in data dictionary
for key, value in pairs(screenData) do
local playerPosition = Players:FindFirstChild(key).Character.HumanoidRootPart.CFrame
screenData[key] = playerPosition
end
-- send to client
remoteScreenUpdate:FireAllClients(screenData)
end
end)()
Client (Animations)
local remoteScreenDetection = game:GetService("ReplicatedStorage"):WaitForChild("ScreenUpdate")
local remoteScreenUnrender = game:GetService("ReplicatedStorage"):WaitForChild("ScreenUnrender")
local Players = game:GetService("Players")
local worldModel = script.Parent:WaitForChild("WorldModel")
local runningAnim = Instance.new("Animation")
local idleAnim = Instance.new("Animation")
local sitAnim = Instance.new("Animation")
local jumpAnim = Instance.new("Animation")
runningAnim.Name = "Run"
idleAnim.Name = "Idle"
sitAnim.Name = "Sit"
jumpAnim.Name = "Jump"
runningAnim.AnimationId = "http://www.roblox.com/asset/?id=10921076136"
idleAnim.AnimationId = "http://www.roblox.com/asset/?id=10921071918"
sitAnim.AnimationId = "http://www.roblox.com/asset/?id=2506281703"
jumpAnim.AnimationId = "http://www.roblox.com/asset/?id=10921078135"
local function checkIfPlayerIsInWorldModel(name)
if worldModel:FindFirstChild(name) then return true end
end
local function removePlayerFromWorldModel(name)
if checkIfPlayerIsInWorldModel(name) then
worldModel:FindFirstChild(name):Destroy()
end
end
local function addPlayerToWorldModel(name)
print(workspace:FindFirstChild(name))
local clonedCharacter = workspace:FindFirstChild(name):Clone()
print(clonedCharacter)
clonedCharacter.Parent = worldModel
end
-- ANIMATIONS??
local function updatePlayerInWorldModel(key, value)
worldModel:FindFirstChild(key):WaitForChild("HumanoidRootPart").CFrame = value
local WMcharacter = worldModel:FindFirstChild(key)
local WMhumanoid = WMcharacter:FindFirstChild("Humanoid")
local currentAnimation = WMhumanoid:GetPlayingAnimationTracks()
if WMhumanoid then
local animator = WMhumanoid:FindFirstChildOfClass("Animator")
local animation = animator:LoadAnimation(runningAnim)
animation:Play()
animation.Looped = true
end
end
-- Every frame the server fires this event to all clients with data from all players in the screen's range
remoteScreenDetection.OnClientEvent:Connect(function(data)
for key, value in pairs(data) do
if not checkIfPlayerIsInWorldModel(key) then
addPlayerToWorldModel(key)
else
updatePlayerInWorldModel(key, value)
end
end
--print(data)
end)
remoteScreenUnrender.OnClientEvent:Connect(removePlayerFromWorldModel)