Model won't place after initial placement is invalidated

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve?
    When I place a model down, it places normally. However, if it touches the red box, it will invalidate and cancel the current placement. You should be able to place again after it cancels.

  2. What is the issue? Include screenshots / videos if possible!
    The issue is that the model doesn’t place after the model is invalidated/canceled. Placement beforehand, however, works as it should.

Video displaying the functionality and error:

LocalScript section that handles the placement:

-- tower moving preview
	local RunService = game:GetService("RunService")
	local twrmdl = game.ReplicatedStorage.Towers[v.Name][skin]:FindFirstChildOfClass("Model"):Clone()
	twrmdl.Parent = workspace
	for i2,v2 in pairs(twrmdl:GetChildren()) do
		if v2.ClassName == "Mesh" or "Part" then
			v2.Anchored = true
			v2.CanCollide = false
			v2.CanTouch = false
		end
	end
	local mouse = game.Players.LocalPlayer:GetMouse() --- Gets Players Mouse
	local func
	func = mouse.Move:Connect(function() --- A friendlier while true do
		if disable == true then return nil end
		local yPos = coroutine.wrap(function()
			-- raycast to get part immediately below mouse position
			local ray = Ray.new(mouse.UnitRay.Origin, mouse.UnitRay.Direction * 1000)
			local part, position = workspace:FindPartOnRayWithIgnoreList(ray, {twrmdl, game.Players.LocalPlayer.Character})
			-- allow model to sit on other surfaces than baseplate correctly
			if part and part.Name ~= "Baseplate" then
				return part.Position.Y + (part.Size.Y / 2) + twrmdl:GetExtentsSize().Y/2
			else
				return twrmdl:GetExtentsSize().Y/2
			end
		end)()
	
		-- make mouse ignore model
		mouse.TargetFilter = twrmdl
		
		-- move model to mouse position
		local x,y,z = mouse.Hit.X,yPos,mouse.Hit.Z 
		twrmdl:MoveTo(Vector3.new(x,y,z))
		
		local clicked = false
		mouse.Button1Down:Connect(function()
			if not clicked then 
				clicked = true
				print("rec click on "..v.Name)
				if placement:PlaceTower(twrmdl, disable) == true then
					print("Placed!")
					local twr = twrmdl:Clone()
					twr.Parent = workspace.Towers
					coroutine.wrap(function()
						for i,v2 in pairs(twrmdl:GetChildren()) do
							local a = v2:Clone()
							v2.Parent = twrmdl
						end
					end)()
					twrmdl:Destroy()
					clicked = false
					disable = true
					return nil
				else
					print("nope.",disable,clicked)
					if twrmdl then twrmdl:Destroy() end
					clicked = false
					disable = true
					return nil
				end
			else
				print("wait what")
				return nil
			end
		end)
	end)

ModuleScript “placement”

local placement = {}

local partWhitelist = {
	workspace.Baseplate
}

function placement:Enable()
	if #placement < 1 then return nil end
	for i,v in pairs(placement) do
		if not tonumber(i) then return nil end
		v.Transparency = 0.5
	end
end

function placement:Disable()
	if #placement < 1 then return nil end
	for i,v in pairs(placement) do
		if not tonumber(i) then return nil end
		v.Transparency = 1
	end
end

local ptdb = false -- debounce for func below
function placement:PlaceTower(twrmdl, killed)
	
	-- kill catch
	if killed == true then return false end
	
	-- debounce check
	if ptdb == true then return false end
	ptdb = true
	
	-- error catch
	if not twrmdl:WaitForChild("HitBox") or not twrmdl.HitBox or not twrmdl then
		error("Placement Module ERROR CATCH LINE 17 -- Tower or Tower Hitbox is nil.", 0)
	end
	
	-- part to test
	local testPart = Instance.new("Part")
	testPart.Size = twrmdl:GetExtentsSize() + Vector3.new(1,1,1)
	testPart.Position = twrmdl:FindFirstChild("HitBox").Position
	testPart.Transparency = 1
	testPart.BrickColor = BrickColor.new("Bright red")
	testPart.Material = Enum.Material.Neon
	testPart.Anchored = true
	testPart.CanCollide = false
	testPart.Parent = workspace

	-- check collisions
	for i,v in pairs(workspace:GetPartsInPart(testPart)) do
		print("checking "..v.Name)
		if table.find(placement, v) then
			print("DET CANT PLACE "..v.Name)
			if table.find(partWhitelist, v) then print("WHITELISTED PART "..v.Name) return true end
			print("disabling")
			placement:Disable()
			coroutine.wrap(function()
				testPart:Destroy()
			end)()
			-- insert UI code here in future -- !! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!!! ATTENTION !!
			return nil
		end
	end
	
	placement[#placement+1] = testPart
	ptdb = false
	coroutine.wrap(function()
		placement:Disable()
	end)()
	return true
end

return placement
  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I’ve tried a few methods but nothing has worked, I wasn’t exactly sure what to look up at this was a unique issue. (I’m working on this tower placement method from scratch)

If you need me to provide anything like pathways or additional script information, just ask
Any help or recommendations are appreciated. (Also, there are no errors or warnings in the output.)

In the mouse.Button1Down in the
if statement where there is a coroutine wrap it should be true?

I’m trying to understand the setup here. You could try it in the mean time.

Changing it didn’t change or solve anything. I think I found an alternative around this, however, which is not allowing the part to place if it is touching a hitbox

Figured it out, had to add something to check if the hitbox existed in the LocalScript because the function would get constantly looped, even after twrmdl destroyed. This led to errors after testing, which allowed me to figure out to add this line

if twrmdl:FindFirstChild("HitBox") == nil then return nil end

after the “if not clicked” if-statement.

1 Like

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