Hello good. I am developing a plugin that will be a kind of Motor2d, almost everything is ready; I ran into a problem, and that is that my code is very poorly optimized for too many pixels, I don’t know what to do, I already had many conversations with ChatGPT to see how much it helped me, and it significantly reduced the lag, but not enough.
Here is the code for generating collidable pixels:
local module = {}
local PixelsGenerate = {}
function module.SetPixelHash(image: EditableImage, size:Vector2,ID:string)
local activePixelHash = {}
local pixels = image:ReadPixelsBuffer(Vector2.zero, size)
local index = 1
for y = 0, size.Y - 1 do
for x = 0, size.X - 1 do
local pixelIndex = (y * size.X + x) * 4
if buffer.readu8(pixels, pixelIndex + 3) > 0 then
activePixelHash[index] = Vector2.new(x, y)
index = index + 1
end
end
end
PixelsGenerate[ID] = activePixelHash
return activePixelHash
end
function module.getPixelHash(ID)
return PixelsGenerate[ID]
end
return module
Here is the one that detects if there is a collision with another image:
local module = {}
function rotatePoint(x, y, angle, cx, cy)
local radian = math.rad(angle)
local cosAngle = math.cos(radian)
local sinAngle = math.sin(radian)
x = x - cx
y = y - cy
local newX = cosAngle * x - sinAngle * y + cx
local newY = sinAngle * x + cosAngle * y + cy
return newX, newY
end
function module.pixelPerfectCollisionFromHashes(hash1, hash2, rotation1, rotation2, size1, size2, pos1, pos2, scale1, scale2)
local newPos1 = {}
for i = 1, #hash1 do
local pos = hash1[i]
local rotatedX1, rotatedY1 = rotatePoint(pos.X, pos.Y, rotation1, size1.X / 2, size1.Y / 2)
local scaledX1 = math.round(pos1.X + rotatedX1 * scale1.X)
local scaledY1 = math.round(pos1.Y + rotatedY1 * scale1.Y)
newPos1[scaledX1] = newPos1[scaledX1] or {}
newPos1[scaledX1][scaledY1] = true
end
for i = 1, #hash2 do
local pos = hash2[i]
local rotatedX2, rotatedY2 = rotatePoint(pos.X, pos.Y, rotation2, size2.X / 2, size2.Y / 2)
local scaledX2 = math.round(pos2.X + rotatedX2 * scale2.X)
local scaledY2 = math.round(pos2.Y + rotatedY2 * scale2.Y)
if newPos1[scaledX2] and newPos1[scaledX2][scaledY2] then
return true
end
end
return false
end
return module
Here I made a small code to connect the module:
local A = script.Parent:FindFirstChild("a")--imageLabel
if A.ImageContent.Object then
A.ImageContent.Object:Destroy()
end
local B = script.Parent:FindFirstChild("b")--imageLabel
if B.ImageContent.Object then
B.ImageContent.Object:Destroy()
end
local a = game:GetService("AssetService"):CreateEditableImage({Size = A.AbsoluteSize})--EditableImage
local b = game:GetService("AssetService"):CreateEditableImage({Size = B.AbsoluteSize})--EditableImage
A.ImageContent = Content.fromObject(a)
B.ImageContent = Content.fromObject(b)
local obj1 = game.ReplicatedStorage:WaitForChild("SpriteFolder"):WaitForChild("First Sprite"):FindFirstChild("4")--Image folder Data
local myString = obj1:GetAttribute("Image")--BufferString
local obj2 =game.ReplicatedStorage:WaitForChild("SpriteFolder"):WaitForChild("First Sprite"):FindFirstChild("5")--Image folder Data
local myString2 = obj2:GetAttribute("Image")--BufferString
a:WritePixelsBuffer(Vector2.zero,obj1:GetAttribute("Size"),buffer.fromstring(myString))--Buffer Convertion
b:WritePixelsBuffer(Vector2.zero,obj2:GetAttribute("Size"),buffer.fromstring(myString2))--Buffer Convertion
local DetecCollider = require(game.ReplicatedStorage.touch)--Name of the module Collider detector
local GenerateActivePixels = require(game.ReplicatedStorage["Pre-Pixels"])----Name of the module Pixels Collider
local hash1 = GenerateActivePixels.SetPixelHash(a, a.Size, obj1:GetAttribute("ID"))--Create a hash of the image
local hash2 = GenerateActivePixels.SetPixelHash(b, b.Size, obj2:GetAttribute("ID"))--Create a hash of the image
local Mouse = game.Players.LocalPlayer:GetMouse()
local objMove = A
local Rotate = false
game:GetService("UserInputService").InputBegan:Connect(function(obj)
if obj.KeyCode == Enum.KeyCode.Tab then
if objMove == A then
objMove = B
A.ImageColor3 = Color3.new(1,1,1)
else
objMove = A
B.ImageColor3 = Color3.new(1,1,1)
end
elseif obj.KeyCode == Enum.KeyCode.F then
Rotate = true
end
end)
game:GetService("UserInputService").InputEnded:Connect(function(obj)
if obj.KeyCode == Enum.KeyCode.F then
Rotate = false
end
end)
game:GetService("RunService").RenderStepped:Connect(function(deltaTime)
local scale1 = Vector2.new(A.AbsoluteSize.X / a.Size.X, A.AbsoluteSize.Y / a.Size.Y)--AbsoluteSizeWordFrame
local scale2 = Vector2.new(B.AbsoluteSize.X / b.Size.X, B.AbsoluteSize.Y / b.Size.Y)--AbsoluteSizeWordFrame
objMove.Position=UDim2.fromOffset(Mouse.X,Mouse.Y)--MoveToMousePosition
local rotationA = A.Rotation
local rotationB = B.Rotation
local canCollide = DetecCollider.pixelPerfectCollisionFromHashes(hash1, hash2, rotationA, rotationB, a.Size, b.Size, A.AbsolutePosition, B.AbsolutePosition, scale1, scale2,obj1:GetAttribute("ID"),obj2:GetAttribute("ID"))
if canCollide then
objMove.ImageColor3 = Color3.new(0, 1, 0)
else
objMove.ImageColor3 = Color3.new(1, 0, 0)
end
if Rotate then
objMove.Rotation +=20
if objMove.Rotation>180 then
objMove.Rotation=-180
elseif objMove.Rotation<-180 then
objMove.Rotation=180
end
end
end)
Comparisons:
Few pixels:
6 times more pixels
97344 Pixels
I need help optimizing this. For the rest, thank you for reading. Excuse my bad English.