-
What do I want to achieve?
Hello!, I want to achieve a item placement system like bloxburg, fast food simulator, etc -
What is the issue?
for some odd reason i’m having 2 very odd bugs where either the meat pan model falls through other models that my mouse is on top on or either just fall through the world.
Watch Screen Recording 2025-06-23 at 3.30.50 PM | Streamable -
**What solutions have you tried so far?
I’ve tried anchoring the model but oddly enough the model just goes below the baseplate
Here’s the placement handler
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PlacementRemote = ReplicatedStorage.RemoteEvents:WaitForChild("Placement")
local function GetItemClone(name)
for _, item in pairs(ReplicatedStorage.FoodItems:GetDescendants()) do
if item.Name == name then
return item:Clone()
end
end
return nil
end
PlacementRemote.OnServerEvent:Connect(function(player, cframe, itemName)
print(cframe)
local item = GetItemClone(itemName)
if not item then
warn("Item not found:", itemName)
return false
end
if item:IsA("Model") then
local primary = item.PrimaryPart
if not primary then
warn("No PrimaryPart found for model:", item.Name)
return false
end
primary.CFrame = cframe
primary.Anchored = true
elseif item:IsA("MeshPart") then
item.CFrame = cframe
item.Anchored = true
end
item:SetAttribute("Owner", player.Name)
item.Parent = workspace
end)
Placement Module Client Sided
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local PlaceRemote = ReplicatedStorage.RemoteEvents.Placement
local Mouse = Players.LocalPlayer:GetMouse()
local Camera = workspace.CurrentCamera
local MAX_RANGE = 20
local Placement = {}
Placement.__index = Placement
function Placement.new(itemName, player, heldItem)
return setmetatable({
ItemName = itemName,
Player = player,
HeldItem = heldItem,
Preview = nil,
Root = nil,
Conn = nil,
InputConn = nil
}, Placement)
end
function Placement:CreatePreview()
print(self.ItemName)
local source
for i, v in pairs(ReplicatedStorage.FoodItems:GetDescendants()) do
if v.Name == self.ItemName then
source = v:Clone()
break
end
end
if not source then warn("Missing source item") return end
local clone = source:Clone()
self.Preview = clone
if clone:IsA("Model") then
self.Root = clone.PrimaryPart
elseif clone:IsA("BasePart") then
self.Root = clone
end
for _, p in clone:GetDescendants() do
if p:IsA("BasePart") then
p.Transparency = 0.5
p.CanCollide = false
end
end
clone.Parent = workspace
end
function Placement:InRange()
if self.Root then
local Distance = (self.Player.Character.HumanoidRootPart.Position - self.Root.Position).Magnitude
if Distance <= MAX_RANGE then
return true
else
return false
end
end
return false
end
function Placement:FollowMouse()
if not self.Root or not self.Preview then return end
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {self.Preview, self.Player.Character}
rayParams.FilterType = Enum.RaycastFilterType.Exclude
local Mouse = UserInputService:GetMouseLocation()
local ray = Camera:ViewportPointToRay(Mouse.X, Mouse.Y)
local result = workspace:Raycast(ray.Origin, ray.Direction * 1000, rayParams)
if result then
local HitPosition = result.Position
local Normal = result.Normal
local Offset = Normal * self.Root.Size.Y/2
local PlacePos = HitPosition + Offset
self.Root.CFrame = CFrame.new(PlacePos)
else
print("no result")
end
end
function Placement:Cleanup()
if self.Conn then self.Conn:Disconnect() end
if self.InputConn then self.InputConn:Disconnect() end
if self.Preview then self.Preview:Destroy() end
if self.HeldItem then self.HeldItem:Destroy() end
end
function Placement:Start()
self:CreatePreview()
self.Conn = RunService.RenderStepped:Connect(function()
self:FollowMouse()
end)
self.InputConn = UserInputService.InputBegan:Connect(function(input, gpe)
if gpe then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 and self:InRange() then
if self.Root then
print(self.Root.CFrame)
PlaceRemote:FireServer(self.Root.CFrame, self.ItemName)
self:Cleanup()
print("Destroyed")
end
end
end)
end
return Placement