Issue with Glass Shatter Code - maths

Right now working on a pretty basic glass shattering code. The issue I have is when a create a new window, which is like 6 parts, I set the PrimaryPart (which is the centre part) to have the CFrame of the original window, however, the model doesn’t rotate correctly; the individual parts rotate, not as a model.

I’ll leave my code below, the relevant bit is :Divide(), but I’ll drop all of it so you can test more easily if you want.

local ShatterEffect = {}
ShatterEffect.__index = ShatterEffect

local Debris                = game:GetService("Debris")

local FindSizeMultipliers = function(fractures, size)
    local fractureSize = size / fractures
    local float = fractureSize / size

    return float
end

local FindXAndYFractures = function(windowSize)
    local xFractures = math.floor(windowSize.X / 1.5)
    local yFractures = math.floor(windowSize.Y / 1.5)

    return math.clamp(xFractures, 1, 9), math.clamp(yFractures, 1, 9)
end

function ShatterEffect:Divide()
    local window = self.window

    local windowSize = window.Size
    local windowCFrame = window.CFrame

    self.windowStartSize = windowSize
    self.windowStartCFrame = windowCFrame
    self.windowStartParent = window.Parent

    -- a fracture is the actual pane. so 9 fractures are caused by 4 cracks (2 horizontal, 2 verticle :D)
    local xFractures, yFractures = FindXAndYFractures(windowSize)

    local xMultiplier = FindSizeMultipliers(xFractures, windowSize.X)
    local yMultiplier = FindSizeMultipliers(yFractures, windowSize.Y)

    local xSize = xMultiplier * windowSize.X
    local ySize = yMultiplier * windowSize.Y
    local zSize = windowSize.Z


    local model = Instance.new("Model")

    for xIterator = 1, xFractures do
        for yIterator = 1, yFractures do
            local part = window:Clone()

            part.Size = Vector3.new(xSize, ySize, zSize)

            local xPosition = (xSize * (xIterator - 1))
            local yPosition = (ySize * (yIterator - 1)) 

            part.Position = Vector3.new(xPosition, yPosition, 0)
            part.Anchored = false

            part.Name = "Fracture"

            if (xIterator == math.floor(xFractures / 2)) and (yIterator == math.floor(yFractures / 2)) then
                model.PrimaryPart = part
            end

            part.Parent = model
        end
    end

    window:Destroy()

    model:SetPrimaryPartCFrame(windowCFrame * CFrame.new(Vector3.new(-xSize / 2, -ySize / 2, 0)))
    model.Parent = workspace

    self.fractureModel = model
end

function ShatterEffect:Push()
    local fractureModel = self.fractureModel
    local origin = self.origin

    for _, fracture in pairs (fractureModel:GetChildren()) do
        local velocityForce = Instance.new("BodyVelocity")
        local direction = (origin - fracture.CFrame.p).unit

        velocityForce.Velocity = direction * 10
        velocityForce.Parent = fracture

        Debris:AddItem(velocityForce, .01)
    end
end

function ShatterEffect:Restore()
    local fractureModel = self.fractureModel
    local windowStartCFrame = self.windowStartCFrame
    local windowStartSize = self.windowStartSize

    local newWindow = fractureModel.PrimaryPart:Clone()

    fractureModel:Destroy()

    newWindow.Anchored = true
    newWindow.Size = windowStartSize
    newWindow.CFrame = windowStartCFrame
    newWindow.Name = "Glass"

    newWindow.Parent = self.windowStartParent
end


function ShatterEffect.Smash(window, origin)
 --   if origin:IsA("Model") then
  --      origin = origin.PrimaryPart
  --  end

    local self = {window = window, origin = origin}
    setmetatable(self, ShatterEffect)

    self:Divide()
    self:Push()

    wait(10)

    self:Restore()
end


return ShatterEffect
2 Likes

Forgive me if I’m wrong, but it looks like you’re trying to set all bricks using position.
Isn’t it easier to offset by cframe? It would take care of rotation aswell as position.

local window = workspace.Window
local SIZE_Y = window.Size.y
for i = 1,2 do
    local part = window:Clone()
    part.Size = window.Size + Vector3.new(0,-SIZE_Y/2,0)
    local dir = i == 1 and -1 or 1
    part.CFrame = window.CFrame * CFrame.new(0, SIZE_Y/4 * dir, 0)
    part.Parent = workspace
end

Sorry for the dir variable but you get the point right?

EDIT: Given you’re a top contributor I feel stupid just for asking lol

5 Likes

Do you know if the parts form a perfect window before the rotation is applied to the model? I’d suspect that they don’t and so after the model is rotated they don’t either. Here is an implementation of what PlaceRebuilder suggested (although I must warn you, I have not tested it).

local xDir = windowCFrame:vectorToObjectSpace(Vector3.new(windowSize.X/xFractures, 0, 0))
local yDir = windowCFrame:vectorToObjectSpace(Vector3.new(0, windowSize.Y/yFractures, 0))
local startCFrame = windowCFrame - (xDir * xFractures / 2 + yDir * yFractures / 2)

local model = Instance.new 'Model'

for xIterator = 0, xFractures - 1 do
    for yIterator = 0, yFractures - 1 do
        local part = window:Clone()
        part.Size = Vector3.new(xSize, ySize, zSize)
        part.CFrame = startCFrame + xDir * xIterator + yDir * yIterator
        part.Anchored = false
        part.Name = 'Fracture'
        part.Parent = model
    end
end

Also, I noticed in my reading on the way down to :Divide() that the local function FindSizeMultipliers mathematically defined as (f, s) => (s/f)/s can be simplified to (f) => 1/f and likely inlined into where it is called.

1 Like

This was true. The reason is because I was cloning the window, meaning its rotation was preserved.

My fix was just a simple

local part = window:Clone()
part.CFrame = CFrame.new()