Images on SpriteSheet are "flickery"

I’ve been having this problem with a sprite sheet, and I don’t know what’s going on. I made a bunch of different images, and I even used ContentProvider:PreloadAsync, but I still don’t know what’s going on. Is there a chance that I can fix this?

Here’s my code:

local ContentProvider = game:GetService("ContentProvider")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local IMAGE_TABLE = {
	[1] = "rbxassetid://4949409027",
	[2] = "rbxassetid://4949409041",
	[3] = "rbxassetid://4949409040",
	[4] = "rbxassetid://4949409034",
	[5] = "rbxassetid://4949409044",
	[6] = "rbxassetid://4949409094",
	[7] = "rbxassetid://4949409095",
	[8] = "rbxassetid://4949409102",
	[9] = "rbxassetid://4949409103",
	[10] = "rbxassetid://4949409104",
	[11] = "rbxassetid://4949409165",
	[12] = "rbxassetid://4949409242",
	[13] = "rbxassetid://4949409166",
	[14] = "rbxassetid://4949409183",
	[15] = "rbxassetid://4949409173",
	[16] = "rbxassetid://4949409240",
	[17] = "rbxassetid://4949409244",
	[18] = "rbxassetid://4949409253",
	[19] = "rbxassetid://4949409250",
	[20] = "rbxassetid://4949409303",
	[21] = "rbxassetid://4949409310",
	[22] = "rbxassetid://4949409317",
	[23] = "rbxassetid://4949409313",
	[24] = "rbxassetid://4949409314",
	[25] = "rbxassetid://4949409350",
	[26] = "rbxassetid://4949409362",
	[27] = "rbxassetid://4949409360",
	[28] = "rbxassetid://4949409367",
	[29] = "rbxassetid://4949409375",
	[30] = "rbxassetid://4949409412",
	[31] = "rbxassetid://4949409447",
	[32] = "rbxassetid://4949409444",
	[33] = "rbxassetid://4949409445",
}

local Remotes = ReplicatedStorage:WaitForChild("Remotes")

ContentProvider:PreloadAsync(IMAGE_TABLE)

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

repeat wait(1) until character:FindFirstChildOfClass("Humanoid")
local humanoid = character:FindFirstChildOfClass("Humanoid")

local SPRITE_SIZE_X, SPRITE_SIZE_Y = 512, 0
local IMAGE_SIZE_X, IMAGE_SIZE_Y = 512, 512
local FRAME_RATE = 24

local Gui = script.Parent
local ImageLabel = Gui:WaitForChild("ImageLabel")

local event = Instance.new("BindableEvent")

local isPlaying = true

local function playImage()
	isPlaying = true
	for _, image in ipairs(IMAGE_TABLE) do
		if not isPlaying then break end
		
		ImageLabel.Image = image
		ImageLabel.ImageRectSize = Vector2.new(IMAGE_SIZE_X, IMAGE_SIZE_Y)
		for y = 0, SPRITE_SIZE_Y, IMAGE_SIZE_Y do
			if not isPlaying then break end
			for x = 0, SPRITE_SIZE_X, IMAGE_SIZE_X do
				ImageLabel.ImageRectOffset = Vector2.new(x, y)
				
				delay(1 / FRAME_RATE, function()
					event:Fire()
				end)
				
				
				event.Event:Wait()
				if not isPlaying then break end
			end
			
				
			delay(1 / FRAME_RATE, function()
				event:Fire()
			end)
			
			event.Event:Wait()
			if not isPlaying then break end
		end
	end
end

local INTERACTABLE_TAG_NAME = "Interactables" -- Constant to define what the tag is called
local INTERACT_ACTION_NAME = "Interact"
local INTERACTABLE_DISTANCE = 10

local Interactables = CollectionService:GetTagged(INTERACTABLE_TAG_NAME)

CollectionService:GetInstanceAddedSignal(INTERACTABLE_TAG_NAME):Connect(function()
	Interactables = CollectionService:GetTagged(INTERACTABLE_TAG_NAME)
end)

CollectionService:GetInstanceRemovedSignal(INTERACTABLE_TAG_NAME):Connect(function()
	Interactables = CollectionService:GetTagged(INTERACTABLE_TAG_NAME)
end)

_G.currentInteractable = nil -- only shared inside the player's client, so it's ok

local cameraConnection
cameraConnection = RunService.RenderStepped:Connect(function()
	ImageLabel.Visible = false
	
	if _G.currentInteractable then
		local guiPosition, onScreen = workspace.CurrentCamera:WorldToScreenPoint(_G.currentInteractable.Position)
		
		if onScreen then
			ImageLabel.Visible = true
			ImageLabel.Position = UDim2.fromOffset(guiPosition.X, guiPosition.Y)
			ImageLabel.Size = UDim2.fromOffset(800 / guiPosition.Z, 800 / guiPosition.Z)
		end
	end
end)

local diedConnection
diedConnection = humanoid.Died:Connect(function()
	cameraConnection:Disconnect()
	diedConnection:Disconnect()
	ContextActionService:UnbindAction(INTERACT_ACTION_NAME)
end)


local function handleAction(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		if _G.currentInteractable then
			playImage()
			ImageLabel.Image = IMAGE_TABLE[1]
			ImageLabel.ImageRectOffset = Vector2.new(0, 0)
			
			Remotes:WaitForChild("InteractEvent"):FireServer(_G.currentInteractable)
		end
	else
		ImageLabel.Image = IMAGE_TABLE[1]
		ImageLabel.ImageRectOffset = Vector2.new(0, 0)
		isPlaying = false
	end
end

ContextActionService:BindAction(INTERACT_ACTION_NAME, handleAction, false, Enum.KeyCode.E, Enum.KeyCode.ButtonX)

while wait(0.1) do
	for _, Interactable in ipairs(Interactables) do
		if (character:GetBoundingBox().Position - Interactable.Position).Magnitude < INTERACTABLE_DISTANCE then
			if _G.currentInteractable then
				if (character:GetBoundingBox().Position - Interactable.Position).Magnitude < (character:GetBoundingBox().Position - _G.currentInteractable.Position).Magnitude then
					_G.currentInteractable = Interactable
				end
			else
				_G.currentInteractable = Interactable
			end
		end
	end
	
	if UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) then
		ImageLabel:GetChildren()[1].Text = "X"
	end
end

Also, all of the images are approved, so I doubt that’s the problem either.

It isn’t really a spritesheet, since they’re all seperate images. I recommend you use an actual spritesheet by putting all of the frames in one image, then iterate through all the frames using ImageRectOffset and ImageRectSize.

1 Like

Well, the problem with that is that Roblox makes it so images can only be 1024x1024, which makes all of the individual frames extremely low resolution. I can’t do that, since the image would look very blurry.

Actually, this works, since the Images aren’t automatically loading. So, I’m just doing this.