Placement system visual block clipping through the ground

Im trying to make this building/placement system work i mean like the visual part that shows you where your gonna place it but it keeps clipping underground with large models (i know its mostly ai thats because i already tried to fix it myself but couldnt get it to work)

local plr = game.Players.LocalPlayer
local tool = script.Parent
local Event = tool:WaitForChild("Place")
local Equipped = false
local CanPlace = false

-- Preview part
local VisPart = Instance.new("Part")
VisPart.Anchored = true
VisPart.CanCollide = false
VisPart.Transparency = 0.5
VisPart.Material = Enum.Material.ForceField
VisPart.Name = "PreviewPart"

-- OverlapParams for collision checks
local overlapParams = OverlapParams.new()
overlapParams.FilterType = Enum.RaycastFilterType.Exclude

-- Raycast params for ground check
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {VisPart}

-- Equip
tool.Equipped:Connect(function()
	Equipped = true
	VisPart.Parent = workspace

	-- Match size with stored model in ReplicatedStorage
	local storedModel = game.ReplicatedStorage:FindFirstChild(tool.Name)
	if storedModel and storedModel:FindFirstChild("Collision") then
		VisPart.Size = storedModel.Collision.Size
	else
		VisPart.Size = Vector3.new(4, 4, 4) -- fallback size
	end

	-- Update loop
	while Equipped do
		task.wait()

		local hrp = plr.Character and plr.Character:FindFirstChild("HumanoidRootPart")
		if not hrp then
			continue
		end

		-- Start preview 10 studs forward
		local forwardOffset = 10
		VisPart.CFrame = hrp.CFrame * CFrame.new(0, 0, -forwardOffset)

		-- Push forward if overlapping with player
		local maxPushes = 10 -- up to 100 studs
		local pushes = 0
		repeat
			overlapParams.FilterDescendantsInstances = {VisPart}
			local touching = workspace:GetPartBoundsInBox(VisPart.CFrame, VisPart.Size, overlapParams)

			local collidingWithPlayer = false
			for _, part in ipairs(touching) do
				if plr.Character and part:IsDescendantOf(plr.Character) then
					collidingWithPlayer = true
					break
				end
			end

			if collidingWithPlayer then
				forwardOffset += 10
				VisPart.CFrame = hrp.CFrame * CFrame.new(0, 0, -forwardOffset)
				pushes += 1
			else
				break
			end
		until pushes >= maxPushes

		-- Raycast directly under preview part to check if it's grounded
		local rayOrigin = VisPart.Position
		local rayDirection = Vector3.new(0, -((VisPart.Size.Y / 2) + 0.5), 0) -- a little below the part
		local rayResult = workspace:Raycast(rayOrigin, rayDirection, rayParams)

		local isGrounded = rayResult ~= nil

		-- General collision check
		overlapParams.FilterDescendantsInstances = {VisPart, plr.Character}
		local touching = workspace:GetPartBoundsInBox(VisPart.CFrame, VisPart.Size, overlapParams)

		local blocked = false
		for _, part in ipairs(touching) do
			if part:IsA("BasePart") and part:HasTag("Collidable") then
				blocked = true
				break
			end
		end

		-- Final placement validity
		if not isGrounded or blocked then
			CanPlace = false
			VisPart.BrickColor = BrickColor.new("Really red")
		else
			CanPlace = true
			VisPart.BrickColor = BrickColor.new("Forest green")
		end
	end
1 Like

basically half of it is underground but idk how to fix it

oh. its because the position is set to be your position, and its not snapped to be above ground, probably move the model preview half of the model’s height upwards

huh im not sure how to implument that but thanks for the advice

nevermind i managed to think of something that made it work here it is if your asking

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.