You can make it a bit easier by restricting yourself to having all splitable parts only split along the Z axis. With that restriction, you can find out how far “along” the part a given position is like this:
function splitablePartPointToOffsetFromBase(part, point)
local partSpaceBase = Vector3.FromNormalId(Enum.NormalId.Back) * part.Size.Z / 2 --Same as Vector3.new(0, 0, part.Size.Z/2)
local partSpacePoint = part.CFrame:PointToObjectSpace(point)
return partSpacePoint.Z - partSpaceBase.Z
end
You can then create a function that splits a part some amount along its length like this:
function splitPartAtOffsetFromBase(part, offset)
assert(offset < part.Size.Z, "Cannot split part further along its length that it is long.")
local partSize = part.Size
local partCFrame = part.CFrame
local part1 = part
part1.Size = Vector3.new(part.Size.X, part.Size.Y, offset)
part1.CFrame = partCFrame * CFrame.new(0, 0, partSize.Z/2 - part1.Size.Z/2)
local part2 = part:Clone()
part2.Size = Vector3.new(part.Size.X, part.Size.Y, partSize.Z - offset)
part2.CFrame = partCFrame * CFrame.new(0, 0, -partSize.Z/2 + part2.Size.Z/2)
part2.Parent = part.Parent
end
Combining it all into a whole script, it could look like this:
local InputS = game:GetService("UserInputService")
local TagS = game:GetService("CollectionService")
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
function getTargetSplitable()
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Blacklist
params.FilterDescendantsInstances = {player.Character}
local result = game.Workspace:Raycast(
mouse.UnitRay.Origin,
mouse.UnitRay.Direction * 5000,
params
)
if result and TagS:HasTag(result.Instance, "Splitable") then
return result
end
return nil
end
function splitablePartPointToOffsetFromBase(part, point)
local partSpaceBase = Vector3.FromNormalId(Enum.NormalId.Back) * part.Size.Z / 2 --Same as Vector3.new(0, 0, part.Size.Z/2)
local partSpacePoint = part.CFrame:PointToObjectSpace(point)
return partSpaceBase.Z - partSpacePoint.Z
end
function splitPartAtOffsetFromBase(part, offset)
assert(offset < part.Size.Z, "Cannot split part further along its length that it is long.")
local partSize = part.Size
local partCFrame = part.CFrame
local part1 = part
part1.Size = Vector3.new(partSize.X, partSize.Y, offset)
part1.CFrame = partCFrame * CFrame.new(0, 0, partSize.Z/2 - part1.Size.Z/2)
part1.BrickColor = BrickColor.Random()
local part2 = part:Clone()
part2.Size = Vector3.new(partSize.X, partSize.Y, partSize.Z - offset)
part2.CFrame = partCFrame * CFrame.new(0, 0, -partSize.Z/2 + part2.Size.Z/2)
part2.Parent = part.Parent
part2.BrickColor = BrickColor.Random()
end
function onClicked()
local result = getTargetSplitable()
if result then
local offset = splitablePartPointToOffsetFromBase(result.Instance, result.Position)
splitPartAtOffsetFromBase(result.Instance, offset)
end
end
InputS.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
onClicked()
end
end)
Keep in mind this wouldn’t replicate the splitting to the server or any other clients, only the clicking player will see the changes.